hiddifypanel 10.85.0b12__py3-none-any.whl → 10.85.0b14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hiddifypanel/VERSION +1 -1
- hiddifypanel/VERSION.py +2 -2
- hiddifypanel/database.py +1 -0
- hiddifypanel/drivers/abstract_driver.py +1 -1
- hiddifypanel/drivers/singbox_api.py +3 -3
- hiddifypanel/drivers/ssh_liberty_bridge_api.py +4 -3
- hiddifypanel/drivers/user_driver.py +6 -5
- hiddifypanel/drivers/wireguard_api.py +35 -13
- hiddifypanel/drivers/xray_api.py +75 -38
- hiddifypanel/hutils/flask.py +1 -1
- hiddifypanel/hutils/proxy/shared.py +1 -1
- hiddifypanel/panel/init_db.py +64 -1
- hiddifypanel/panel/usage.py +195 -99
- hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
- hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/METADATA +1 -1
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/RECORD +25 -25
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/WHEEL +1 -1
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/entry_points.txt +0 -0
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/licenses/LICENSE.md +0 -0
- {hiddifypanel-10.85.0b12.dist-info → hiddifypanel-10.85.0b14.dist-info}/top_level.txt +0 -0
hiddifypanel/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
10.85.
|
1
|
+
10.85.0.b14
|
hiddifypanel/VERSION.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# import importlib.metadata
|
2
2
|
from datetime import datetime
|
3
3
|
|
4
|
-
__version__ = '10.85.
|
5
|
-
__release_time__= datetime.strptime('2025-
|
4
|
+
__version__ = '10.85.0.b14'
|
5
|
+
__release_time__= datetime.strptime('2025-06-28T13:07:47','%Y-%m-%dT%H:%M:%S')
|
6
6
|
is_released_version=True
|
hiddifypanel/database.py
CHANGED
@@ -38,17 +38,17 @@ class SingboxApi(DriverABS):
|
|
38
38
|
def remove_client(self, user):
|
39
39
|
pass
|
40
40
|
|
41
|
-
def get_all_usage(self
|
41
|
+
def get_all_usage(self):
|
42
42
|
xray_client = self.get_singbox_client()
|
43
43
|
usages = xray_client.stats_query('user', reset=True)
|
44
|
-
|
44
|
+
|
45
45
|
res = defaultdict(int)
|
46
46
|
for use in usages:
|
47
47
|
if "user>>>" not in use.name:
|
48
48
|
continue
|
49
49
|
# print(use.name, use.value)
|
50
50
|
uuid = use.name.split(">>>")[1].split("@")[0]
|
51
|
-
res[
|
51
|
+
res[uuid] += use.value # uplink + downlink
|
52
52
|
return res
|
53
53
|
# return {u: self.get_usage_imp(u.uuid) for u in users}
|
54
54
|
|
@@ -41,12 +41,13 @@ class SSHLibertyBridgeApi(DriverABS):
|
|
41
41
|
redis_client.hdel(USERS_USAGE, f'{user.uuid}')
|
42
42
|
redis_client.save()
|
43
43
|
|
44
|
-
def get_all_usage(self
|
44
|
+
def get_all_usage(self):
|
45
45
|
redis_client = self.get_ssh_redis_client()
|
46
46
|
allusage = redis_client.hgetall(USERS_USAGE)
|
47
47
|
redis_client.delete(USERS_USAGE)
|
48
|
-
return
|
49
|
-
return {u:
|
48
|
+
return allusage
|
49
|
+
# return {u: int(allusage.get(u.uuid) or 0) for u in users}
|
50
|
+
# return {u: self.get_usage_imp(u.uuid) for u in users}
|
50
51
|
|
51
52
|
def get_usage_imp(self, client_uuid: str, reset: bool = True) -> int:
|
52
53
|
redis_client = self.get_ssh_redis_client()
|
@@ -17,16 +17,17 @@ def enabled_drivers():
|
|
17
17
|
def get_users_usage(reset=True):
|
18
18
|
res = {}
|
19
19
|
from hiddifypanel.database import db
|
20
|
-
|
21
|
-
users = db.session.query(User).all()
|
20
|
+
|
21
|
+
# users = db.session.query(User).all()
|
22
22
|
# users = list(User.query.all())
|
23
23
|
res = defaultdict(lambda: {'usage': 0, 'devices': ''})
|
24
24
|
for driver in enabled_drivers():
|
25
25
|
try:
|
26
|
-
all_usage = driver.get_all_usage(
|
27
|
-
for
|
26
|
+
all_usage = driver.get_all_usage()
|
27
|
+
for uuid, usage in all_usage.items():
|
28
|
+
# print(f"{driver.__class__.__name__} {uuid} usage={usage}")
|
28
29
|
if usage:
|
29
|
-
res[
|
30
|
+
res[uuid]['usage'] += usage
|
30
31
|
# res[user]['devices'] +=usage
|
31
32
|
except Exception as e:
|
32
33
|
print(driver)
|
@@ -22,7 +22,25 @@ class WireguardApi(DriverABS):
|
|
22
22
|
|
23
23
|
def __init__(self) -> None:
|
24
24
|
super().__init__()
|
25
|
-
|
25
|
+
self.pub_uuid_map={}
|
26
|
+
def __load_pubkey_uuid_map(self):
|
27
|
+
from hiddifypanel.database import db
|
28
|
+
users = db.session.query(User).all()
|
29
|
+
self.pub_uuid_map={u.wg_pub: u.uuid for u in users}
|
30
|
+
|
31
|
+
def __convert_pub_key_to_uuid(self,pubkeys):
|
32
|
+
res={}
|
33
|
+
can_reload_map=True
|
34
|
+
for key in pubkeys:
|
35
|
+
if uuid:=self.pub_uuid_map.get(key):
|
36
|
+
res[key]=uuid
|
37
|
+
elif can_reload_map:
|
38
|
+
self.__load_pubkey_uuid_map()
|
39
|
+
can_reload_map=False
|
40
|
+
if uuid:=self.pub_uuid_map.get(key):
|
41
|
+
res[key]=uuid
|
42
|
+
return res
|
43
|
+
|
26
44
|
def __get_wg_usages(self) -> dict:
|
27
45
|
raw_output = commander(Command.update_wg_usage, run_in_background=False)
|
28
46
|
data = {}
|
@@ -36,6 +54,7 @@ class WireguardApi(DriverABS):
|
|
36
54
|
'down': int(sections[1]),
|
37
55
|
'up': int(sections[2]),
|
38
56
|
}
|
57
|
+
|
39
58
|
return data
|
40
59
|
|
41
60
|
def __get_local_usage(self) -> dict:
|
@@ -45,22 +64,25 @@ class WireguardApi(DriverABS):
|
|
45
64
|
|
46
65
|
return {}
|
47
66
|
|
48
|
-
def __sync_local_usages(self
|
67
|
+
def __sync_local_usages(self) -> dict:
|
49
68
|
local_usage = self.__get_local_usage()
|
50
69
|
wg_usage = self.__get_wg_usages()
|
70
|
+
|
51
71
|
res = {}
|
52
72
|
# remove local usage that is removed from wg usage
|
53
73
|
for local_wg_pub in local_usage.copy().keys():
|
54
74
|
if local_wg_pub not in wg_usage:
|
55
75
|
del local_usage[local_wg_pub]
|
56
|
-
|
76
|
+
|
77
|
+
|
78
|
+
uuid_map = self.__convert_pub_key_to_uuid(wg_usage.keys())
|
57
79
|
for wg_pub, wg_usage in wg_usage.items():
|
58
|
-
|
59
|
-
|
80
|
+
uuid = uuid_map.get(wg_pub)
|
81
|
+
|
60
82
|
if not local_usage.get(wg_pub):
|
61
83
|
local_usage[wg_pub] = {"uuid": uuid, "usage": wg_usage}
|
62
84
|
continue
|
63
|
-
res[
|
85
|
+
res[uuid] = self.calculate_reset(local_usage[wg_pub]['usage'], wg_usage)
|
64
86
|
local_usage[wg_pub] = {"uuid": uuid, "usage": wg_usage}
|
65
87
|
|
66
88
|
self.get_redis_client().set(USERS_USAGE, json.dumps(local_usage))
|
@@ -101,14 +123,14 @@ class WireguardApi(DriverABS):
|
|
101
123
|
def remove_client(self, user):
|
102
124
|
pass
|
103
125
|
|
104
|
-
def get_all_usage(self,
|
126
|
+
def get_all_usage(self, reset=True):
|
105
127
|
if not hconfig(ConfigEnum.wireguard_enable):
|
106
128
|
return {}
|
107
|
-
all_usages = self.__sync_local_usages(
|
129
|
+
all_usages = self.__sync_local_usages()
|
108
130
|
res = {}
|
109
|
-
for
|
110
|
-
if use := all_usages.get(u.wg_pub):
|
111
|
-
res[
|
112
|
-
else:
|
113
|
-
|
131
|
+
for uuid,use in all_usages.items():
|
132
|
+
# if use := all_usages.get(u.wg_pub):
|
133
|
+
res[uuid] = use['up'] + use['down']
|
134
|
+
# else:
|
135
|
+
# res[u] = 0
|
114
136
|
return res
|
hiddifypanel/drivers/xray_api.py
CHANGED
@@ -16,36 +16,41 @@ class XrayApi(DriverABS):
|
|
16
16
|
return self.xray_client
|
17
17
|
|
18
18
|
def get_enabled_users(self):
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
19
|
+
return {u:1 for u in self.get_enabled_users_terminal()}
|
20
|
+
# xray_client = self.get_xray_client()
|
21
|
+
# usages = xray_client.stats_query('user', reset=True)
|
22
|
+
# res = defaultdict(int)
|
23
|
+
# tags = set(self.get_inbound_tags())
|
24
|
+
# for use in usages:
|
25
|
+
# if "user>>>" not in use.name:
|
26
|
+
# continue
|
27
|
+
# uuid = use.name.split(">>>")[1].split("@")[0]
|
28
|
+
# res[uuid]=1
|
29
|
+
|
30
|
+
# #TODO use xtls api
|
31
|
+
# for t in tags.copy():
|
32
|
+
# try:
|
33
|
+
# self.__add_uuid_to_tag(uuid, t)
|
34
|
+
# self._remove_client(uuid, [t], False)
|
35
|
+
# # print(f"Success add {uuid} {t}")
|
36
|
+
# res[uuid] = 0
|
37
|
+
# break
|
38
|
+
# except ValueError:
|
39
|
+
# # tag invalid
|
40
|
+
# tags.remove(t)
|
41
|
+
# pass
|
42
|
+
# except xtlsapi.xtlsapi.exceptions.EmailAlreadyExists as e:
|
43
|
+
# res[uuid] = 1
|
44
|
+
# break
|
45
|
+
# except Exception as e:
|
46
|
+
# print(f"error {e}")
|
47
|
+
# # res[uuid] = 1
|
48
|
+
# break
|
49
|
+
|
50
|
+
# return res
|
45
51
|
|
46
52
|
# xray_client = self.get_xray_client()
|
47
|
-
# users = User.query.all()
|
48
|
-
# t = "xtls"
|
53
|
+
# users = User.query.all() # t = "xtls"
|
49
54
|
# protocol = "vless"
|
50
55
|
# enabled = {}
|
51
56
|
# for u in users:
|
@@ -101,8 +106,7 @@ class XrayApi(DriverABS):
|
|
101
106
|
if (protocol == "vless" and p != "xtls" and p != "realityin") or "realityingrpc" in t:
|
102
107
|
xray_client.add_client(t, f'{uuid}', f'{uuid}@hiddify.com', protocol=protocol, flow='\0',)
|
103
108
|
else:
|
104
|
-
xray_client.add_client(t, f'{uuid}', f'{uuid}@hiddify.com', protocol=protocol,
|
105
|
-
flow='xtls-rprx-vision', alter_id=0, cipher='chacha20_poly1305')
|
109
|
+
xray_client.add_client(t, f'{uuid}', f'{uuid}@hiddify.com', protocol=protocol, flow='xtls-rprx-vision', alter_id=0, cipher='chacha20_poly1305')
|
106
110
|
|
107
111
|
def add_client(self, user):
|
108
112
|
uuid = user.uuid
|
@@ -130,26 +134,26 @@ class XrayApi(DriverABS):
|
|
130
134
|
for t in tags:
|
131
135
|
try:
|
132
136
|
xray_client.remove_client(t, f'{uuid}@hiddify.com')
|
133
|
-
if dolog:
|
134
|
-
|
137
|
+
# if dolog:
|
138
|
+
# logger.info(f"Success remove {uuid} {t}")
|
135
139
|
except Exception as e:
|
136
140
|
if dolog:
|
137
141
|
logger.info(f"error in remove {uuid} {t} {e}")
|
138
142
|
pass
|
139
143
|
|
140
|
-
def get_all_usage(self
|
144
|
+
def get_all_usage(self)->dict:
|
141
145
|
xray_client = self.get_xray_client()
|
142
146
|
usages = xray_client.stats_query('user', reset=True)
|
143
|
-
uuid_user_map = {u.uuid: u for u in users}
|
147
|
+
# uuid_user_map = {u.uuid: u for u in users}
|
144
148
|
res = defaultdict(int)
|
145
149
|
for use in usages:
|
146
150
|
if "user>>>" not in use.name:
|
147
151
|
continue
|
148
152
|
uuid = use.name.split(">>>")[1].split("@")[0]
|
149
|
-
if u := uuid_user_map.get(uuid):
|
150
|
-
|
151
|
-
else:
|
152
|
-
|
153
|
+
# if u := uuid_user_map.get(uuid):
|
154
|
+
res[uuid] += use.value
|
155
|
+
# else:
|
156
|
+
# self._remove_client(uuid)
|
153
157
|
return res
|
154
158
|
|
155
159
|
def get_usage_imp(self, uuid):
|
@@ -167,3 +171,36 @@ class XrayApi(DriverABS):
|
|
167
171
|
if res:
|
168
172
|
logger.debug(f"Xray usage {uuid} d={d} u={u} sum={res}")
|
169
173
|
return res
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
|
178
|
+
def get_enabled_users_terminal(self):
|
179
|
+
import subprocess
|
180
|
+
import json
|
181
|
+
tags=self.get_inbound_tags()
|
182
|
+
for t in tags:
|
183
|
+
# Command to execute
|
184
|
+
cmd = [
|
185
|
+
'xray',
|
186
|
+
'api',
|
187
|
+
'inbounduser',
|
188
|
+
'--server=127.0.0.1:10085',
|
189
|
+
f'-tag={t}'
|
190
|
+
]
|
191
|
+
|
192
|
+
try:
|
193
|
+
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
194
|
+
|
195
|
+
# Parse JSON output
|
196
|
+
data = json.loads(result.stdout)
|
197
|
+
users= [splt[0] for splt in [u.get('email','').split("@") for u in data.get('users',[])] if len(splt)==2 and splt[1]=="hiddify.com"]
|
198
|
+
if len(data)>0:
|
199
|
+
return users
|
200
|
+
|
201
|
+
except subprocess.CalledProcessError as e:
|
202
|
+
print("Command failed:", e)
|
203
|
+
print("Error output:", e.stderr)
|
204
|
+
except json.JSONDecodeError as e:
|
205
|
+
print("Failed to parse JSON:", e)
|
206
|
+
return []
|
hiddifypanel/hutils/flask.py
CHANGED
@@ -244,7 +244,7 @@ def validate_domain_exist(form, field):
|
|
244
244
|
|
245
245
|
|
246
246
|
def get_proxy_stats_url():
|
247
|
-
proxy_stats_url = f'{request.host_url}{g.proxy_path}/proxy-stats/'
|
247
|
+
proxy_stats_url = f'{request.host_url}{g.proxy_path}/proxy-stats/'.replace("http://","https://")
|
248
248
|
params = f'hostname={proxy_stats_url}api/&port=443&secret=hiddify'
|
249
249
|
return f'{proxy_stats_url}?{params}'
|
250
250
|
|
@@ -361,7 +361,7 @@ def make_proxy(hconfigs: dict, proxy: Proxy, domain_db: Domain, phttp=80, ptls=4
|
|
361
361
|
return base
|
362
362
|
elif "shadowsocks" in proxy.transport:
|
363
363
|
return base
|
364
|
-
if
|
364
|
+
if proxy.l3 in [ProxyL3.reality] and proxy.transport in [ProxyTransport.XTLS,ProxyTransport.xhttp]:
|
365
365
|
base['flow'] = 'xtls-rprx-vision'
|
366
366
|
return {**base, 'transport': 'tcp'}
|
367
367
|
|
hiddifypanel/panel/init_db.py
CHANGED
@@ -17,6 +17,63 @@ from loguru import logger
|
|
17
17
|
MAX_DB_VERSION = 120
|
18
18
|
|
19
19
|
|
20
|
+
def _v102(child_id):
|
21
|
+
|
22
|
+
add_usage_proc= """
|
23
|
+
DROP PROCEDURE IF EXISTS add_usage_json;
|
24
|
+
|
25
|
+
CREATE PROCEDURE add_usage_json(IN usage_data JSON)
|
26
|
+
BEGIN
|
27
|
+
DECLARE u_id INT DEFAULT NULL;
|
28
|
+
DECLARE u_uuid CHAR(36) DEFAULT NULL;
|
29
|
+
DECLARE u_usage BIGINT;
|
30
|
+
DECLARE done BOOL DEFAULT FALSE;
|
31
|
+
|
32
|
+
DECLARE cur CURSOR FOR
|
33
|
+
SELECT jt.id, jt.uuid, jt.usage FROM JSON_TABLE(
|
34
|
+
usage_data,
|
35
|
+
'$[*]' COLUMNS (
|
36
|
+
id INT PATH '$.id' NULL ON ERROR,
|
37
|
+
uuid CHAR(36) PATH '$.uuid' NULL ON ERROR,
|
38
|
+
`usage` BIGINT PATH '$.usage'
|
39
|
+
)
|
40
|
+
) AS jt;
|
41
|
+
|
42
|
+
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
|
43
|
+
|
44
|
+
OPEN cur;
|
45
|
+
|
46
|
+
read_loop: LOOP
|
47
|
+
FETCH cur INTO u_id, u_uuid, u_usage;
|
48
|
+
IF done THEN
|
49
|
+
LEAVE read_loop;
|
50
|
+
END IF;
|
51
|
+
|
52
|
+
IF u_id IS NOT NULL THEN
|
53
|
+
UPDATE user
|
54
|
+
SET current_usage = current_usage + u_usage,
|
55
|
+
last_online = NOW(),
|
56
|
+
start_date = CASE WHEN start_date IS NULL THEN CURDATE() ELSE start_date END
|
57
|
+
WHERE id = u_id;
|
58
|
+
ELSEIF u_uuid IS NOT NULL THEN
|
59
|
+
UPDATE user
|
60
|
+
SET current_usage = current_usage + u_usage,
|
61
|
+
last_online = NOW(),
|
62
|
+
start_date = CASE WHEN start_date IS NULL THEN CURDATE() ELSE start_date END
|
63
|
+
|
64
|
+
WHERE uuid = u_uuid;
|
65
|
+
END IF;
|
66
|
+
|
67
|
+
COMMIT;
|
68
|
+
END LOOP;
|
69
|
+
|
70
|
+
CLOSE cur;
|
71
|
+
END
|
72
|
+
|
73
|
+
"""
|
74
|
+
|
75
|
+
db_execute(add_usage_proc,commit=True)
|
76
|
+
|
20
77
|
|
21
78
|
def _v101(child_id):
|
22
79
|
add_config_if_not_exist(ConfigEnum.path_xhttp, hutils.random.get_random_string(7, 15))
|
@@ -660,7 +717,7 @@ def make_proxy_rows(cfgs):
|
|
660
717
|
continue
|
661
718
|
if l3 in ["kcp", 'reality'] and cdn != "direct":
|
662
719
|
continue
|
663
|
-
if l3 == "reality" and ((transport not in ['tcp', 'grpc', 'XTLS']) or proto != 'vless'):
|
720
|
+
if l3 == "reality" and ((transport not in ['tcp', 'grpc', 'XTLS',ProxyTransport.xhttp]) or proto != 'vless'):
|
664
721
|
continue
|
665
722
|
if proto == "trojan" and l3 not in ["tls", 'xtls', 'tls_h2', 'h3_quic']:
|
666
723
|
continue
|
@@ -668,6 +725,11 @@ def make_proxy_rows(cfgs):
|
|
668
725
|
continue
|
669
726
|
if transport in ["h2"] and l3 != "reality":
|
670
727
|
continue
|
728
|
+
if l3 in [ProxyL3.h3_quic,ProxyL3.tls_h2] and transport in [ProxyTransport.httpupgrade, ProxyTransport.WS]:
|
729
|
+
continue
|
730
|
+
|
731
|
+
|
732
|
+
|
671
733
|
# if l3 == "tls_h2" and transport =="grpc":
|
672
734
|
# continue
|
673
735
|
enable = l3 != "http" or proto == "vmess"
|
@@ -805,6 +867,7 @@ def upgrade_database():
|
|
805
867
|
def init_db():
|
806
868
|
# set_hconfig(ConfigEnum.db_version, 71)
|
807
869
|
db_version = current_db_version()
|
870
|
+
# set_hconfig(ConfigEnum.db_version,101)
|
808
871
|
if db_version == latest_db_version():
|
809
872
|
return
|
810
873
|
|
hiddifypanel/panel/usage.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
|
2
|
+
from celery import shared_task
|
2
3
|
from sqlalchemy import func
|
3
4
|
from typing import Dict
|
4
5
|
import datetime
|
@@ -6,12 +7,12 @@ import datetime
|
|
6
7
|
from hiddifypanel.drivers import user_driver
|
7
8
|
from hiddifypanel.models import *
|
8
9
|
from hiddifypanel.panel import hiddify
|
9
|
-
from hiddifypanel.database import db
|
10
|
+
from hiddifypanel.database import db, db_execute, text
|
10
11
|
from hiddifypanel import cache, hutils
|
11
12
|
from loguru import logger
|
13
|
+
import json
|
12
14
|
to_gig_d = 1024**3
|
13
15
|
|
14
|
-
from celery import shared_task
|
15
16
|
|
16
17
|
@shared_task(ignore_result=False)
|
17
18
|
def update_local_usage():
|
@@ -19,9 +20,9 @@ def update_local_usage():
|
|
19
20
|
# if not cache.redis_client.set(lock_key, "locked", nx=True, ex=600):
|
20
21
|
# return {"msg": "last update task is not finished yet."}
|
21
22
|
try:
|
22
|
-
res=update_local_usage_not_lock()
|
23
|
+
res = update_local_usage_not_lock()
|
23
24
|
cache.redis_client.set(lock_key, "locked", nx=False, ex=60)
|
24
|
-
|
25
|
+
|
25
26
|
return res
|
26
27
|
except Exception as e:
|
27
28
|
cache.redis_client.set(lock_key, "locked", nx=False, ex=60)
|
@@ -30,147 +31,242 @@ def update_local_usage():
|
|
30
31
|
return {"msg": f"Exception in update usage: {e}"}
|
31
32
|
|
32
33
|
# return {"status": 'success', "comments":res}
|
34
|
+
|
35
|
+
|
33
36
|
def update_local_usage_not_lock():
|
34
|
-
|
37
|
+
|
35
38
|
try:
|
36
39
|
res = user_driver.get_users_usage(reset=True)
|
37
|
-
return
|
40
|
+
return add_users_usage_new([{'uuid': uuid, "usage": uinfo['usage']} for uuid, uinfo in res.items()], child_id=0)
|
41
|
+
# add_users_usage_uuid({"66ac79b8-8c03-4084-81c7-a2b1b3e9eefe":{"usage":1000000000}},child_id=0)
|
42
|
+
# json_data=json.dumps([{ "uuid": uuid, "usage": uinfo["usage"]}for uuid, uinfo in {"66ac79b8-8c03-4084-81c7-a2b1b3e9eefe":{"usage":1000000000}}.items()])
|
43
|
+
# db_execute("CALL add_usage_json(:usage_data)", usage_data= json_data, commit=True)
|
38
44
|
except Exception as e:
|
39
45
|
raise
|
40
|
-
|
41
46
|
|
42
47
|
|
43
48
|
def add_users_usage_uuid(uuids_bytes: Dict[str, Dict], child_id, sync=False):
|
44
|
-
uuids_bytes = {u: v for u, v in uuids_bytes.items() if v}
|
49
|
+
uuids_bytes = {u: v for u, v in uuids_bytes.items() if v and v.get('usage', 0) > 0}
|
45
50
|
uuids = uuids_bytes.keys()
|
46
51
|
users = db.session.query(User).filter(User.uuid.in_(uuids))
|
47
|
-
dbusers_bytes = {u: uuids_bytes.get(u.uuid, 0) for u in users}
|
52
|
+
dbusers_bytes = {u: uuids_bytes.get(u.uuid, {"usage": 0}) for u in users}
|
48
53
|
_add_users_usage(dbusers_bytes, child_id, sync) # type: ignore
|
49
54
|
|
50
55
|
|
51
|
-
def _reset_priodic_usage():
|
56
|
+
def _reset_priodic_usage() -> bool:
|
57
|
+
apply_changes = False
|
52
58
|
last_usage_check: int = hconfig(ConfigEnum.last_priodic_usage_check) or 0
|
53
59
|
import time
|
54
60
|
current_time = int(time.time())
|
55
|
-
if current_time - last_usage_check < 60 * 60 * 6:
|
56
|
-
|
57
|
-
# reset as soon as possible in the day
|
58
|
-
if datetime.datetime.now().hour > 5 and current_time - last_usage_check < 60 * 60 * 24:
|
59
|
-
|
61
|
+
# if current_time - last_usage_check < 60 * 60 * 6:
|
62
|
+
# return apply_changes
|
63
|
+
# # reset as soon as possible in the day
|
64
|
+
# if datetime.datetime.now().hour > 5 and current_time - last_usage_check < 60 * 60 * 24:
|
65
|
+
# return apply_changes
|
60
66
|
logger.debug("reseting user usage if needed")
|
61
|
-
for user in db.session.query(User).filter(User.mode != UserMode.no_reset).all():
|
67
|
+
# for user in db.session.query(User).filter(User.mode != UserMode.no_reset).all():
|
68
|
+
# if user.user_should_reset():
|
69
|
+
# logger.info(f"reseting user usage for {user.uuid}")
|
70
|
+
# user.reset_usage(commit=False)
|
71
|
+
|
72
|
+
today = datetime.date.today()
|
73
|
+
|
74
|
+
db_change = False
|
75
|
+
for user in db.session.query(User).filter(User.mode != UserMode.no_reset, User.start_date != None, User.start_date+User.package_days >= today).all():
|
62
76
|
if user.user_should_reset():
|
63
77
|
logger.info(f"reseting user usage for {user.uuid}")
|
78
|
+
old_active = user.is_active
|
64
79
|
user.reset_usage(commit=False)
|
65
|
-
|
80
|
+
db_change = True
|
66
81
|
|
82
|
+
if not old_active and user.is_active:
|
83
|
+
logger.info(f"adding enabled client {user.uuid} ")
|
84
|
+
user_driver.add_client(user)
|
85
|
+
apply_changes = True
|
86
|
+
send_bot_message(user)
|
67
87
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
if db_change:
|
89
|
+
db.session.commit()
|
90
|
+
|
91
|
+
for user in db.session.query(User).filter(User.start_date != None, User.start_date+User.package_days < today).all():
|
92
|
+
logger.info(f"Removing enabled client {user.uuid} ")
|
93
|
+
if not user.is_active:
|
94
|
+
user_driver.remove_client(user)
|
95
|
+
apply_changes = True
|
96
|
+
|
97
|
+
set_hconfig(ConfigEnum.last_priodic_usage_check, current_time, commit=True)
|
98
|
+
return apply_changes
|
99
|
+
|
100
|
+
|
101
|
+
def add_users_usage_new(usages: list[dict], child_id, sync=False):
|
102
|
+
usages = [use for use in usages if use['usage'] > 0]
|
103
|
+
# usages[0]['usage']=1000000000000
|
74
104
|
before_enabled_users = user_driver.get_enabled_users()
|
75
105
|
|
76
106
|
daily_usage = {}
|
77
107
|
today = datetime.date.today()
|
78
|
-
|
108
|
+
db_changes = False
|
79
109
|
for adm in db.session.query(AdminUser).all():
|
80
110
|
daily_usage[adm.id] = db.session.query(DailyUsage).filter(DailyUsage.date == today, DailyUsage.admin_id == adm.id, DailyUsage.child_id == child_id).first()
|
81
111
|
if daily_usage[adm.id] is None:
|
82
112
|
logger.info(f"creating a new daily usage {today} admin={adm.id} child={child_id}")
|
83
|
-
daily_usage[adm.id] = DailyUsage(date=today, admin_id=adm.id, child_id=child_id)
|
113
|
+
daily_usage[adm.id] = DailyUsage(date=today, admin_id=adm.id, child_id=child_id, usage=0)
|
84
114
|
db.session.add(daily_usage[adm.id])
|
85
|
-
|
115
|
+
db_changes = True
|
86
116
|
daily_usage[adm.id].online = db.session.query(User).filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
|
87
|
-
if
|
117
|
+
if db_changes:
|
88
118
|
db.session.commit()
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
if not
|
119
|
+
|
120
|
+
apply_changes = _reset_priodic_usage()
|
121
|
+
|
122
|
+
db_execute("CALL add_usage_json(:usage_data)", usage_data=json.dumps(usages), commit=True)
|
123
|
+
|
124
|
+
usage_map = {u['uuid']: u for u in usages}
|
125
|
+
|
126
|
+
users = db.session.query(User).filter(User.uuid.in_(set(usage_map.keys()))).all()
|
127
|
+
|
128
|
+
all_users_uuids = set()
|
129
|
+
for user in users:
|
130
|
+
all_users_uuids.add(user.uuid)
|
131
|
+
|
132
|
+
user_before_active = before_enabled_users.get(user.uuid,False)
|
133
|
+
user_active = user.is_active
|
134
|
+
|
135
|
+
if not user_before_active and user_active:
|
106
136
|
logger.info(f"Enabling disabled client {user.uuid} ")
|
107
137
|
user_driver.add_client(user)
|
108
138
|
send_bot_message(user)
|
109
|
-
|
110
|
-
|
111
|
-
# Check if there's new usage value
|
112
|
-
if not isinstance(usage_bytes, int) or usage_bytes == 0:
|
113
|
-
res[user.uuid] = "No usage"
|
114
|
-
else:
|
115
|
-
# Set new daily usage of the user
|
116
|
-
if sync and daily_usage.get(user.added_by, daily_usage[1]).usage != usage_bytes:
|
117
|
-
daily_usage.get(user.added_by, daily_usage[1]).usage = usage_bytes
|
118
|
-
else:
|
119
|
-
daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
|
120
|
-
|
121
|
-
in_bytes = usage_bytes
|
122
|
-
|
123
|
-
# Set new current usage of the user
|
124
|
-
if sync and user.current_usage != in_bytes:
|
125
|
-
user.current_usage = in_bytes
|
126
|
-
# detail.current_usage_GB = in_gig
|
127
|
-
else:
|
128
|
-
user.current_usage += in_bytes
|
129
|
-
# detail.current_usage = detail.current_usage or 0
|
130
|
-
# detail.current_usage += in_bytes
|
131
|
-
|
132
|
-
# Change last online time of the user
|
133
|
-
user.last_online = datetime.datetime.now()
|
134
|
-
# detail.last_online = datetime.datetime.now()
|
135
|
-
|
136
|
-
# Set start date of user to the current datetime if it hasn't been set already
|
137
|
-
if user.start_date is None:
|
138
|
-
user.start_date = datetime.date.today()
|
139
|
-
|
140
|
-
res[user.uuid] = f'{in_bytes/1000000:0.3f}MB'
|
141
|
-
|
142
|
-
# Remove user from drivers(singbox, xray, wireguard etc.) if they're inactive
|
143
|
-
# print(before_enabled_users[user.uuid], user.is_active)
|
144
|
-
if before_enabled_users[user.uuid] and not user.is_active:
|
139
|
+
apply_changes = True
|
140
|
+
elif user_before_active and not user_active:
|
145
141
|
logger.info(f"Removing enabled client {user.uuid} ")
|
146
|
-
|
147
142
|
user_driver.remove_client(user)
|
148
|
-
|
149
|
-
|
143
|
+
send_bot_message(user)
|
144
|
+
apply_changes = True
|
145
|
+
|
146
|
+
daily_usage.get(user.added_by, daily_usage[1]).usage += usage_map[user.uuid]['usage']
|
150
147
|
|
151
|
-
db.session.commit()
|
148
|
+
db.session.commit()
|
152
149
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
150
|
+
if len(users) != len(usage_map):
|
151
|
+
# check for zombie-users
|
152
|
+
check_users = set(before_enabled_users.keys())-all_users_uuids
|
153
|
+
all_db_users = {u.uuid for u in db.session.query(User).filter(User.uuid.in_(check_users)).all()}
|
154
|
+
zombie_users = check_users-all_db_users
|
157
155
|
|
158
|
-
|
159
|
-
|
156
|
+
for uuid in zombie_users:
|
157
|
+
logger.info(f"Remove zombiee users {uuid} ")
|
160
158
|
user_driver.remove_client(User(uuid=uuid))
|
161
|
-
|
162
|
-
user_driver.remove_client(user)
|
159
|
+
apply_changes = True
|
163
160
|
|
164
|
-
|
165
|
-
# Apply the changes to the drivers
|
166
|
-
if have_change:
|
161
|
+
if apply_changes:
|
167
162
|
hiddify.quick_apply_users()
|
168
163
|
|
169
|
-
|
170
|
-
|
171
|
-
|
164
|
+
return {"status": 'success', "comments": usages, "date": hutils.convert.time_to_json(datetime.datetime.now())}
|
165
|
+
|
166
|
+
|
167
|
+
# def _add_users_usage(users_usage_data: Dict[User, Dict], child_id, sync=False):
|
168
|
+
# '''
|
169
|
+
# sync: when enabled, it means we have received usages from the parent panel
|
170
|
+
# '''
|
171
|
+
# res = {}
|
172
|
+
# have_change = False
|
173
|
+
# before_enabled_users = user_driver.get_enabled_users()
|
174
|
+
# daily_usage = {}
|
175
|
+
# today = datetime.date.today()
|
176
|
+
# changes = False
|
177
|
+
# for adm in db.session.query(AdminUser).all():
|
178
|
+
# daily_usage[adm.id] = db.session.query(DailyUsage).filter(DailyUsage.date == today, DailyUsage.admin_id == adm.id, DailyUsage.child_id == child_id).first()
|
179
|
+
# if daily_usage[adm.id] is None:
|
180
|
+
# logger.info(f"creating a new daily usage {today} admin={adm.id} child={child_id}")
|
181
|
+
# daily_usage[adm.id] = DailyUsage(date=today, admin_id=adm.id, child_id=child_id)
|
182
|
+
# db.session.add(daily_usage[adm.id])
|
183
|
+
# changes = True
|
184
|
+
# daily_usage[adm.id].online = db.session.query(User).filter(User.added_by == adm.id).filter(func.DATE(User.last_online) == today).count()
|
185
|
+
# if changes:
|
186
|
+
# db.session.commit()
|
187
|
+
# _reset_priodic_usage()
|
188
|
+
|
189
|
+
# # userDetails = {p.user_id: p for p in UserDetail.query.filter(UserDetail.child_id == child_id).all()}
|
190
|
+
# for user, uinfo in users_usage_data.items():
|
191
|
+
# usage_bytes = uinfo['usage']
|
192
|
+
|
193
|
+
# # UserDetails things
|
194
|
+
# # detail = UserDetail(user_id=user.id, child_id=child_id)
|
195
|
+
# # detail = userDetails.get(user.id)
|
196
|
+
# # if not detail:
|
197
|
+
# # detail = UserDetail(user_id=user.id, child_id=child_id)
|
198
|
+
# # db.session.add(detail)
|
199
|
+
# # if uinfo['devices'] != detail.connected_devices:
|
200
|
+
# # detail.connected_devices = uinfo['devices']
|
201
|
+
|
202
|
+
# # Enable the user if isn't already
|
203
|
+
# if not before_enabled_users[user.uuid] and user.is_active:
|
204
|
+
# logger.info(f"Enabling disabled client {user.uuid} ")
|
205
|
+
# user_driver.add_client(user)
|
206
|
+
# send_bot_message(user)
|
207
|
+
# have_change = True
|
208
|
+
|
209
|
+
# # Check if there's new usage value
|
210
|
+
# if not isinstance(usage_bytes, int) or usage_bytes == 0:
|
211
|
+
# res[user.uuid] = "No usage"
|
212
|
+
# else:
|
213
|
+
# # Set new daily usage of the user
|
214
|
+
# if sync and daily_usage.get(user.added_by, daily_usage[1]).usage != usage_bytes:
|
215
|
+
# daily_usage.get(user.added_by, daily_usage[1]).usage = usage_bytes
|
216
|
+
# else:
|
217
|
+
# daily_usage.get(user.added_by, daily_usage[1]).usage += usage_bytes
|
218
|
+
|
219
|
+
# # Set new current usage of the user
|
220
|
+
# if sync and user.current_usage != usage_bytes:
|
221
|
+
# user.current_usage = usage_bytes
|
222
|
+
# # detail.current_usage_GB = in_gig
|
223
|
+
# else:
|
224
|
+
# user.current_usage += usage_bytes
|
225
|
+
# # detail.current_usage = detail.current_usage or 0
|
226
|
+
# # detail.current_usage += usage_bytes
|
227
|
+
|
228
|
+
# # Change last online time of the user
|
229
|
+
# user.last_online = datetime.datetime.now()
|
230
|
+
# # detail.last_online = datetime.datetime.now()
|
231
|
+
|
232
|
+
# # Set start date of user to the current datetime if it hasn't been set already
|
233
|
+
# if user.start_date is None:
|
234
|
+
# user.start_date = datetime.date.today()
|
235
|
+
|
236
|
+
# res[user.uuid] = f'{usage_bytes/1000000:0.3f}MB'
|
237
|
+
|
238
|
+
# # Remove user from drivers(singbox, xray, wireguard etc.) if they're inactive
|
239
|
+
# # print(before_enabled_users[user.uuid], user.is_active)
|
240
|
+
# if before_enabled_users[user.uuid] and not user.is_active:
|
241
|
+
# logger.info(f"Removing enabled client {user.uuid} ")
|
242
|
+
|
243
|
+
# user_driver.remove_client(user)
|
244
|
+
# have_change = True
|
245
|
+
# res[user.uuid] = f"{res[user.uuid]} !OUT of USAGE! Client Removed"
|
246
|
+
|
247
|
+
# db.session.commit() # type: ignore
|
248
|
+
|
249
|
+
# # Remove invalid users
|
250
|
+
# for uuid in before_enabled_users:
|
251
|
+
# if uuid in res:
|
252
|
+
# continue
|
253
|
+
|
254
|
+
# user = db.session.query(User).filter(User.uuid == uuid).first()
|
255
|
+
# if not user:
|
256
|
+
# user_driver.remove_client(User(uuid=uuid))
|
257
|
+
# elif not user.is_active:
|
258
|
+
# user_driver.remove_client(user)
|
259
|
+
|
260
|
+
# # print("------------------", res)
|
261
|
+
# # Apply the changes to the drivers
|
262
|
+
# if have_change:
|
263
|
+
# hiddify.quick_apply_users()
|
264
|
+
|
265
|
+
# # Sync the new data with the parent node if the data has not been set by the parent node itself and the current panel is a child panel
|
266
|
+
# if not sync and hutils.node.is_child():
|
267
|
+
# hutils.node.child.sync_users_usage_with_parent()
|
172
268
|
|
173
|
-
|
269
|
+
# return {"status": 'success', "comments": res, "date": hutils.convert.time_to_json(datetime.datetime.now())}
|
174
270
|
|
175
271
|
|
176
272
|
def send_bot_message(user):
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
hiddifypanel/Events.py,sha256=AlnRdjVul0jP-NCT4-zoaQgowoOo-JhdQB4ytetAFKA,723
|
2
|
-
hiddifypanel/VERSION,sha256=
|
3
|
-
hiddifypanel/VERSION.py,sha256=
|
2
|
+
hiddifypanel/VERSION,sha256=sKg8vnG-EE180T6hI9d4-w7XaYJpEtaQYHVpwLWzAb4,12
|
3
|
+
hiddifypanel/VERSION.py,sha256=RK10T65MIHlBlviFHQpfipvyKaXCPNJaKomq-NPI6Fs,191
|
4
4
|
hiddifypanel/__init__.py,sha256=kigwDO8d9jXyPZLvJAWd6zo-GX3pG_xWf-q2aStz80Y,377
|
5
5
|
hiddifypanel/__main__.py,sha256=IVchnXpK6bm8T3N--mN17HBQNLMeLAjyP7iwzULexB4,218
|
6
6
|
hiddifypanel/auth.py,sha256=LJmH4ROqZv5ej_4m1b0xvbEw2meJTzDR1mFCDm523kE,8041
|
@@ -8,24 +8,24 @@ hiddifypanel/base.py,sha256=LwEQPv6QVLY6V9EUQ_-C_Sg0p64QRajLTauACIc4m-w,2705
|
|
8
8
|
hiddifypanel/base_setup.py,sha256=W64zORy8BRukhpRXMnCb-SMejQc3bmuwtyWbanGiJ3M,2802
|
9
9
|
hiddifypanel/cache.py,sha256=YBogDyZ0jze8IIdPi34YYcbYF4iHsZgpfpt4gZLha0Q,1527
|
10
10
|
hiddifypanel/celery.py,sha256=VdU2QOJwerd7pkCQLeDsLpfMWpdARtF7sEEJwud0SDY,3200
|
11
|
-
hiddifypanel/database.py,sha256=
|
11
|
+
hiddifypanel/database.py,sha256=OkFNG9RGdtk3ZXImYjlzpVey7weu5a4Yme3Vo3qsptk,2634
|
12
12
|
hiddifypanel/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
hiddifypanel/apps/asgi_app.py,sha256=Wz1rbJylXxkKthWQI5kUUXkePA8wZ37QO8g1sIbKG5o,181
|
14
14
|
hiddifypanel/apps/celery_app.py,sha256=DWDtkbWuAVIJhStnzcTsyo3ker85gm7ZZHWm-Th7cvo,81
|
15
15
|
hiddifypanel/apps/celery_app_flask.py,sha256=OlyAUzOOdTNLtNOT_V9hZgCCnTdFOppQaF6lqW58k7g,79
|
16
16
|
hiddifypanel/apps/wsgi_app.py,sha256=lyqB3H5jvvfDqi5P34PDw64rsJKhwE8qwYbUiya89BQ,119
|
17
|
-
hiddifypanel/drivers/abstract_driver.py,sha256=
|
18
|
-
hiddifypanel/drivers/singbox_api.py,sha256
|
19
|
-
hiddifypanel/drivers/ssh_liberty_bridge_api.py,sha256=
|
20
|
-
hiddifypanel/drivers/user_driver.py,sha256=
|
21
|
-
hiddifypanel/drivers/wireguard_api.py,sha256=
|
22
|
-
hiddifypanel/drivers/xray_api.py,sha256=
|
17
|
+
hiddifypanel/drivers/abstract_driver.py,sha256=BWHWA-5btPTyUSRm0n4gulqeqA4CsEnVY3bV5OOO8U0,216
|
18
|
+
hiddifypanel/drivers/singbox_api.py,sha256=dropF7Cfi4i9fMit2omSZ62IQv30B70oH6MZfgfj5bY,2243
|
19
|
+
hiddifypanel/drivers/ssh_liberty_bridge_api.py,sha256=urB2HzFUhQQytbPz28_rMgOthwVGip2Od_tsXVbVHWQ,2263
|
20
|
+
hiddifypanel/drivers/user_driver.py,sha256=XYgvmXe2CiLAUnX3weldnGHcb8aDwQqF7TIPRjSUnIM,2856
|
21
|
+
hiddifypanel/drivers/wireguard_api.py,sha256=qeuh835tSA75npJ2AzW9NhRlAKtaljX1qK-Wjugd5bI,4291
|
22
|
+
hiddifypanel/drivers/xray_api.py,sha256=Kk7FDpNFITP085gx_yLqM7hw5vCpoF2bATrZYCXy_JE,7174
|
23
23
|
hiddifypanel/hutils/__init__.py,sha256=P0JLvth-yJza_xpSGWlU7Hmtj_Ym9oyDimo4YpURdLQ,1447
|
24
24
|
hiddifypanel/hutils/auth.py,sha256=Ci3_lBfLXx1yi2M6HvYX3ceHYtOf-cfX092evcs8528,3030
|
25
25
|
hiddifypanel/hutils/convert.py,sha256=mPEDzR64hKeQ4B_tZRk2Ci8-Ybod0bjX0BbxLHOmLZA,2075
|
26
26
|
hiddifypanel/hutils/crypto.py,sha256=C32Wj-SpjOSycmmnWD0q8g_ZG4puzJNX9T9hSkTut08,2591
|
27
27
|
hiddifypanel/hutils/encode.py,sha256=-A1VknNmtsw-YfV-h8mz6QLtlYjg2MB_ZWbUj6MSil4,837
|
28
|
-
hiddifypanel/hutils/flask.py,sha256=
|
28
|
+
hiddifypanel/hutils/flask.py,sha256=QE-u0FJpRdxVtg4u9hYkFafEvvL3-EwmqB46LfAKoX8,11949
|
29
29
|
hiddifypanel/hutils/github_issue.py,sha256=LSJCDVC_UEFDIXG4JdQReLDUnF_WmfhH7eFB-iZKwdg,6609
|
30
30
|
hiddifypanel/hutils/model.py,sha256=ajlJ-Tx0Mq68S9y5qEj0lwlDbF2xj0niZBQyw7UU670,1320
|
31
31
|
hiddifypanel/hutils/random.py,sha256=KrsarmRNL05PYzwMxDaDyv-_QcKS0YsZR2z7BnllAqI,1789
|
@@ -44,7 +44,7 @@ hiddifypanel/hutils/node/parent.py,sha256=UbyfvfP4fTSn6HN9oZDjYsKYIejiqW6eApKIfP
|
|
44
44
|
hiddifypanel/hutils/node/shared.py,sha256=FDSj3e-i3pb3mEv5vcUeX0Km1nxYg1CeAruIq7RwFmU,2540
|
45
45
|
hiddifypanel/hutils/proxy/__init__.py,sha256=V2dGkYT3tji__5YOSmKOMChFYXtlENe1fX6eHqK70Pc,129
|
46
46
|
hiddifypanel/hutils/proxy/clash.py,sha256=V9Y2UIw-CYTXD_Q73Oeq3WLw6chsPrMIiNxYnlWyNbg,7065
|
47
|
-
hiddifypanel/hutils/proxy/shared.py,sha256=
|
47
|
+
hiddifypanel/hutils/proxy/shared.py,sha256=MRfdDjfijZxJwoUA6wg9FROdf_wFp9JuJZgMo8SaLnM,22261
|
48
48
|
hiddifypanel/hutils/proxy/singbox.py,sha256=Fmmzoake-gpnRB5yfTyQvd1dB-10WKwhJt4vhiKzJZQ,11722
|
49
49
|
hiddifypanel/hutils/proxy/wireguard.py,sha256=gij01BYXII-RxAh3Yky0o3yce20HJKeHtu1KNwb0Uzk,934
|
50
50
|
hiddifypanel/hutils/proxy/xray.py,sha256=0vEHL9yq5Si7W_fgI8tn9zwNAWhwBE7djun05cAUDF8,10808
|
@@ -72,9 +72,9 @@ hiddifypanel/panel/common.py,sha256=pMxdgt37ubIZroFBuvHfN5qXNp8kytVTIzVxzZA_X_I,
|
|
72
72
|
hiddifypanel/panel/custom_widgets.py,sha256=_zA0WZRZOCyh6Z1gW62aRQLMAOM_m85B2oZoIOU59Ys,2637
|
73
73
|
hiddifypanel/panel/hiddify.py,sha256=nwLTMYa_LyNuS26BPOO8jfyrslHX2MbQxN0o4lxCTd4,15687
|
74
74
|
hiddifypanel/panel/hlogger.py,sha256=1AQQCs1lg0Y1AYIASRjxWAdFE92HENeg3z1rFycOoY0,1215
|
75
|
-
hiddifypanel/panel/init_db.py,sha256=
|
75
|
+
hiddifypanel/panel/init_db.py,sha256=eBh6K35zfxrvUA7t3UrIeo704ELx7lgl4NGEqfj08WQ,40133
|
76
76
|
hiddifypanel/panel/run_commander.py,sha256=cXCFVvZ6iTzab3EOZ-Eq3aOeIqfgzgt2ppNaxm_3OJI,3205
|
77
|
-
hiddifypanel/panel/usage.py,sha256=
|
77
|
+
hiddifypanel/panel/usage.py,sha256=Cz7KRJkHIQ6XEkbzwbL4GIzG5ycT-bCDqYmsJK0Gsxk,11923
|
78
78
|
hiddifypanel/panel/admin/Actions.py,sha256=o_ENbphriVrbRJkx9nvrkpaliuMIfp34sscMkZJ3P5s,8578
|
79
79
|
hiddifypanel/panel/admin/AdminstratorAdmin.py,sha256=X8MI3DtW62vJqFRp97M_CxSdB-NFNMlZOSDsd5hn8HA,10482
|
80
80
|
hiddifypanel/panel/admin/Backup.py,sha256=BKSoAZgw1j16P1Jh9vMqGj7ZfB2m-WafDK0C5vil5FY,3634
|
@@ -842,17 +842,17 @@ hiddifypanel/templates/redirect.html,sha256=K9x_O4P96vEkqBhOXIhoGrWw1KIqd2bL0BjI
|
|
842
842
|
hiddifypanel/templates/static.html,sha256=jp6q4wtx-k2A_cjqJoNiMS7Ee30arE45qI3ev4d5ky4,165
|
843
843
|
hiddifypanel/templates/hiddify-flask-admin/actions.html,sha256=2NeITe2e-lPKCk_o511tCIqVtrPu8LYHE1wTCtrFUrI,1331
|
844
844
|
hiddifypanel/templates/hiddify-flask-admin/list.html,sha256=MBGrTqZpzNLe4sZy0RozvXNr8seFUQc2C6v88BJtNWc,11095
|
845
|
-
hiddifypanel/translations/en/LC_MESSAGES/messages.mo,sha256=
|
845
|
+
hiddifypanel/translations/en/LC_MESSAGES/messages.mo,sha256=GncyHCVs1iGb4Vs7YRNX9bB1RQlQXBnbcslMKTr74uE,80248
|
846
846
|
hiddifypanel/translations/en/LC_MESSAGES/messages.po,sha256=ZQn1-QHu0FwpHIluExU9U1p738DrpK_vBaucF1ndyvo,83564
|
847
|
-
hiddifypanel/translations/fa/LC_MESSAGES/messages.mo,sha256=
|
847
|
+
hiddifypanel/translations/fa/LC_MESSAGES/messages.mo,sha256=155uBY6WCbMhRCW8VzOgd5OoQMeO7Awt1b6tuOTGhQg,102665
|
848
848
|
hiddifypanel/translations/fa/LC_MESSAGES/messages.po,sha256=xEU_jSeWnc70mvoPJ7f0d_9lG5U-mvo3BQzcRRvB4o8,107420
|
849
|
-
hiddifypanel/translations/my/LC_MESSAGES/messages.mo,sha256=
|
849
|
+
hiddifypanel/translations/my/LC_MESSAGES/messages.mo,sha256=S0gROMPq8mtA0QxWpf2trNWvf_PxBElc6ZaGIQolC1w,139090
|
850
850
|
hiddifypanel/translations/my/LC_MESSAGES/messages.po,sha256=GcrOHDJC2wjo1L8lLmwLOs_dwoqcf0f6rXXjDv8JnsE,141985
|
851
|
-
hiddifypanel/translations/pt/LC_MESSAGES/messages.mo,sha256=
|
851
|
+
hiddifypanel/translations/pt/LC_MESSAGES/messages.mo,sha256=8pIwiaprVdRPIX6ND1ZGOtqtNn4RvZVFlVfTKWdKTs0,80797
|
852
852
|
hiddifypanel/translations/pt/LC_MESSAGES/messages.po,sha256=pX1dG9wcQEYRBpxU3mL-gY_q2YNkVwbRmrI6wNHjkm8,85364
|
853
|
-
hiddifypanel/translations/ru/LC_MESSAGES/messages.mo,sha256=
|
853
|
+
hiddifypanel/translations/ru/LC_MESSAGES/messages.mo,sha256=qtQ7GqRYXF1YCTk0ys9y5dlESPrE6npvzmJVjDm2iYA,108594
|
854
854
|
hiddifypanel/translations/ru/LC_MESSAGES/messages.po,sha256=mc8TFxwLUu8iBH8iK-aGUpQoKDRCjb2sh6fZK1w1inU,113367
|
855
|
-
hiddifypanel/translations/zh/LC_MESSAGES/messages.mo,sha256=
|
855
|
+
hiddifypanel/translations/zh/LC_MESSAGES/messages.mo,sha256=cqDYHg2b5nAcsj0As6V2wQ4mmyV1Dt1hmiiub8jdKQs,75296
|
856
856
|
hiddifypanel/translations/zh/LC_MESSAGES/messages.po,sha256=ze5ipeKdB4ISOMkT0ERufBPdlWDT5m3xUj0OSeBdkpk,79474
|
857
857
|
hiddifypanel/translations.i18n/en.json,sha256=4rDoVjPSUqs8OCh8dHf923wjHmgJNguelTN3b1EwLqA,72605
|
858
858
|
hiddifypanel/translations.i18n/fa.json,sha256=3WMq36rLV-1E9GTVTovDlEPIoOJ5cedOBDdke-OcyXE,96515
|
@@ -861,9 +861,9 @@ hiddifypanel/translations.i18n/my.json,sha256=QAXg__5TCqfx3Ck0cw5YQsSXX_3kqUhMOd
|
|
861
861
|
hiddifypanel/translations.i18n/pt.json,sha256=bO1-qEZJ9yf6Pz_6Vz18xDLezp3pCYwK8_aTLMJA1Iw,74570
|
862
862
|
hiddifypanel/translations.i18n/ru.json,sha256=kCI1TBgj1T0VnvRfrgxCnLt_fA6ZuD9kjRt0vkmyvb0,102357
|
863
863
|
hiddifypanel/translations.i18n/zh.json,sha256=A50l-_uQ4lsZwcF3UyGcyZxsR3hAjmvnMrJLnTcVZbI,69103
|
864
|
-
hiddifypanel-10.85.
|
865
|
-
hiddifypanel-10.85.
|
866
|
-
hiddifypanel-10.85.
|
867
|
-
hiddifypanel-10.85.
|
868
|
-
hiddifypanel-10.85.
|
869
|
-
hiddifypanel-10.85.
|
864
|
+
hiddifypanel-10.85.0b14.dist-info/licenses/LICENSE.md,sha256=oDrt-cUsyiDGnRPjEJh-3dH2ddAuK_bIVBD8ntkOtZw,19807
|
865
|
+
hiddifypanel-10.85.0b14.dist-info/METADATA,sha256=VqhyecYpa68_bak3AEuGmztdV0EjbDgGQcsI0W5PMf0,25628
|
866
|
+
hiddifypanel-10.85.0b14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
867
|
+
hiddifypanel-10.85.0b14.dist-info/entry_points.txt,sha256=Xzpqlh3nwBtZhoV9AANJykano056VJvYzaujxPztJaM,60
|
868
|
+
hiddifypanel-10.85.0b14.dist-info/top_level.txt,sha256=rv-b3qFWUZQTBy0kyBfsr7L6tPpeO7AaQlLHXn-HI5M,13
|
869
|
+
hiddifypanel-10.85.0b14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|