hiddifypanel 10.80.12.dev0__py3-none-any.whl → 10.85.0b1__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.
Files changed (75) hide show
  1. hiddifypanel/VERSION +1 -1
  2. hiddifypanel/VERSION.py +3 -3
  3. hiddifypanel/apps/asgi_app.py +1 -1
  4. hiddifypanel/apps/celery_app.py +2 -2
  5. hiddifypanel/apps/celery_app_flask.py +3 -0
  6. hiddifypanel/apps/wsgi_app.py +1 -1
  7. hiddifypanel/base.py +5 -5
  8. hiddifypanel/celery.py +68 -1
  9. hiddifypanel/database.py +62 -5
  10. hiddifypanel/drivers/singbox_api.py +2 -1
  11. hiddifypanel/drivers/user_driver.py +4 -1
  12. hiddifypanel/hutils/__init__.py +46 -14
  13. hiddifypanel/hutils/crypto.py +2 -1
  14. hiddifypanel/hutils/encode.py +1 -2
  15. hiddifypanel/hutils/flask.py +1 -1
  16. hiddifypanel/hutils/network/auto_ip_selector.py +15 -12
  17. hiddifypanel/hutils/network/cf_api.py +7 -2
  18. hiddifypanel/hutils/proxy/xrayjson.py +1 -0
  19. hiddifypanel/hutils/system.py +9 -8
  20. hiddifypanel/hutils/utils.py +2 -1
  21. hiddifypanel/models/admin.py +7 -5
  22. hiddifypanel/models/base_account.py +3 -3
  23. hiddifypanel/models/child.py +4 -4
  24. hiddifypanel/models/config.py +5 -5
  25. hiddifypanel/models/config_enum.py +3 -1
  26. hiddifypanel/models/domain.py +5 -5
  27. hiddifypanel/models/proxy.py +4 -2
  28. hiddifypanel/models/report.py +3 -3
  29. hiddifypanel/models/usage.py +2 -2
  30. hiddifypanel/models/user.py +3 -3
  31. hiddifypanel/panel/admin/templates/index.html +6 -6
  32. hiddifypanel/panel/cli.py +1 -1
  33. hiddifypanel/panel/commercial/restapi/v1/tgbot.py +2 -3
  34. hiddifypanel/panel/commercial/restapi/v2/user/apps_api.py +76 -6
  35. hiddifypanel/panel/common.py +5 -1
  36. hiddifypanel/panel/common_bp/login.py +3 -2
  37. hiddifypanel/panel/hiddify.py +9 -9
  38. hiddifypanel/panel/hlogger.py +3 -1
  39. hiddifypanel/panel/init_db.py +71 -87
  40. hiddifypanel/panel/run_commander.py +3 -4
  41. hiddifypanel/panel/usage.py +10 -9
  42. hiddifypanel/panel/user/templates/base_singbox_config.json.j2 +19 -34
  43. hiddifypanel/panel/user/templates/base_xray_config.json.j2 +4 -2
  44. hiddifypanel/panel/user/templates/clash_config.yml +33 -3
  45. hiddifypanel/panel/user/templates/new.html +3 -2
  46. hiddifypanel/static/apps-icon/clash_verge_rev.ico +0 -0
  47. hiddifypanel/static/apps-icon/cmfa.ico +0 -0
  48. hiddifypanel/templates/master.html +2 -2
  49. hiddifypanel/translations/en/LC_MESSAGES/messages.mo +0 -0
  50. hiddifypanel/translations/en/LC_MESSAGES/messages.po +13 -1
  51. hiddifypanel/translations/fa/LC_MESSAGES/messages.mo +0 -0
  52. hiddifypanel/translations/fa/LC_MESSAGES/messages.po +13 -1
  53. hiddifypanel/translations/my/LC_MESSAGES/messages.mo +0 -0
  54. hiddifypanel/translations/my/LC_MESSAGES/messages.po +0 -2
  55. hiddifypanel/translations/pt/LC_MESSAGES/messages.mo +0 -0
  56. hiddifypanel/translations/pt/LC_MESSAGES/messages.po +13 -1
  57. hiddifypanel/translations/ru/LC_MESSAGES/messages.mo +0 -0
  58. hiddifypanel/translations/ru/LC_MESSAGES/messages.po +13 -1
  59. hiddifypanel/translations/zh/LC_MESSAGES/messages.mo +0 -0
  60. hiddifypanel/translations/zh/LC_MESSAGES/messages.po +13 -1
  61. hiddifypanel/translations.i18n/en.json +9 -1
  62. hiddifypanel/translations.i18n/fa.json +9 -1
  63. hiddifypanel/translations.i18n/fr.json +1 -0
  64. hiddifypanel/translations.i18n/my.json +4 -0
  65. hiddifypanel/translations.i18n/pt.json +9 -1
  66. hiddifypanel/translations.i18n/ru.json +9 -1
  67. hiddifypanel/translations.i18n/zh.json +9 -1
  68. hiddifypanel-10.85.0b1.dist-info/METADATA +331 -0
  69. {hiddifypanel-10.80.12.dev0.dist-info → hiddifypanel-10.85.0b1.dist-info}/RECORD +120 -116
  70. {hiddifypanel-10.80.12.dev0.dist-info → hiddifypanel-10.85.0b1.dist-info}/WHEEL +2 -1
  71. hiddifypanel-10.85.0b1.dist-info/entry_points.txt +2 -0
  72. hiddifypanel-10.85.0b1.dist-info/top_level.txt +1 -0
  73. hiddifypanel-10.80.12.dev0.dist-info/METADATA +0 -137
  74. hiddifypanel-10.80.12.dev0.dist-info/entry_points.txt +0 -3
  75. {hiddifypanel-10.80.12.dev0.dist-info → hiddifypanel-10.85.0b1.dist-info/licenses}/LICENSE.md +0 -0
hiddifypanel/VERSION CHANGED
@@ -1 +1 @@
1
- 10.80.12.dev0
1
+ 10.85.0b1
hiddifypanel/VERSION.py CHANGED
@@ -1,6 +1,6 @@
1
- import importlib.metadata
1
+ # import importlib.metadata
2
2
  from datetime import datetime
3
3
 
4
- __version__ = importlib.metadata.version(__package__ or __name__)
5
- __release_time__= datetime.strptime('2024-12-19T23:50:29','%Y-%m-%dT%H:%M:%S')
4
+ __version__ = '10.85.0b1'
5
+ __release_time__= datetime.strptime('2025-04-13T22:25:18','%Y-%m-%dT%H:%M:%S')
6
6
  is_released_version=True
@@ -1,4 +1,4 @@
1
- #!/opt/hiddify-manager/.venv/bin/python
1
+ #!/opt/hiddify-manager/.venv313/bin/python
2
2
 
3
3
  from hiddifypanel import create_app_wsgi
4
4
  from asgiref.wsgi import WsgiToAsgi
@@ -1,3 +1,3 @@
1
- from hiddifypanel.base import create_celery_app
1
+ from hiddifypanel.celery import init_app_no_flask
2
2
 
3
- celery_app=create_celery_app()
3
+ celery_app=init_app_no_flask()
@@ -0,0 +1,3 @@
1
+ from hiddifypanel.base import create_celery_app
2
+
3
+ celery_app=create_celery_app()
@@ -1,4 +1,4 @@
1
- #!/opt/hiddify-manager/.venv/bin/python
1
+ #!/opt/hiddify-manager/.venv313/bin/python
2
2
 
3
3
  from hiddifypanel import create_app_wsgi
4
4
 
hiddifypanel/base.py CHANGED
@@ -8,13 +8,13 @@ import datetime
8
8
  from dotenv import dotenv_values
9
9
  import os
10
10
  import sys
11
- from apiflask import APIFlask
12
- from loguru import logger
13
11
 
12
+ def create_app(*args, app_mode="web", **config):
13
+ from apiflask import APIFlask
14
+ from loguru import logger
14
15
 
15
- from dynaconf import FlaskDynaconf
16
16
 
17
- def create_app(*args, app_mode="web", **config):
17
+ from dynaconf import FlaskDynaconf
18
18
 
19
19
  app = APIFlask(__name__, static_url_path="/<proxy_path>/static/", instance_relative_config=True, version='2.2.0', title="Hiddify API",
20
20
  openapi_blueprint_url_prefix="/<proxy_path>/api", docs_ui='elements', json_errors=False, enable_openapi=app_mode=="web")
@@ -36,7 +36,7 @@ def create_app(*args, app_mode="web", **config):
36
36
  ]
37
37
 
38
38
  if app_mode=="celery":
39
- extensions.append("hiddifypanel.celery:init_app")
39
+ extensions=["hiddifypanel.celery:init_app"]
40
40
  elif app_mode=="cli":
41
41
  extensions.append("hiddifypanel.panel.cli:init_app")
42
42
  else:
hiddifypanel/celery.py CHANGED
@@ -1,5 +1,10 @@
1
+ import os
2
+ import sys
1
3
  from celery import Celery, Task
2
4
  from celery.schedules import crontab
5
+ from dotenv import dotenv_values
6
+ from loguru import logger
7
+
3
8
 
4
9
  def init_app(app):
5
10
  class FlaskTask(Task):
@@ -42,4 +47,66 @@ def init_app(app):
42
47
  )
43
48
 
44
49
  celery_app.set_default()
45
- return celery_app
50
+ return celery_app
51
+
52
+
53
+
54
+ def init_app_no_flask():
55
+ config={}
56
+ for c, v in dotenv_values(os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')).items():
57
+ if v.isdecimal():
58
+ v = int(v)
59
+ else:
60
+ v = True if v.lower() == "true" else (False if v.lower() == "false" else v)
61
+ config[c] = v
62
+ import hiddifypanel.database
63
+ hiddifypanel.database.init_no_flask()
64
+
65
+ from hiddifypanel.panel import init_db
66
+ if not init_db.is_db_latest():
67
+ logger.error("The database upgrade is required before proceeding. Terminating the process.")
68
+ import time
69
+ time.sleep(20)
70
+ sys.exit(1)
71
+
72
+ celery_app = Celery()
73
+
74
+ celery_app.config_from_object(dict(
75
+ broker_url=config['REDIS_URI_MAIN'],
76
+ result_backend=config['REDIS_URI_MAIN'],
77
+ # task_ignore_result=True,
78
+ ))
79
+
80
+
81
+
82
+ # Calls test('hello') every 10 seconds.
83
+ from hiddifypanel.panel import usage
84
+ celery_app.add_periodic_task(60.0, usage.update_local_usage.s(), name='update usage')
85
+ # celery_app.conf.beat_schedule = {
86
+ # 'update_usage': {
87
+ # 'task': 'hiddifypanel.panel.usage.update_local_usage',
88
+ # 'schedule': 30.0,
89
+
90
+ # },
91
+ # }
92
+ from hiddifypanel.panel.cli import backup_task
93
+ celery_app.autodiscover_tasks()
94
+ # celery_app.add_periodic_task(30.0, backup_task.s(), name='backup task')
95
+ # celery_app.add_periodic_task(
96
+ # crontab(hour="*/6", minute=30),
97
+ # backup_task.delay(),
98
+ # )
99
+
100
+ celery_app.add_periodic_task(
101
+ crontab(hour="*/6", minute="0"),
102
+ # crontab(hour="*", minute="*"),
103
+ backup_task.s(),
104
+ name="backup_task "
105
+ )
106
+
107
+ celery_app.set_default()
108
+
109
+ return celery_app
110
+
111
+
112
+
hiddifypanel/database.py CHANGED
@@ -1,19 +1,75 @@
1
1
  from typing import Optional
2
- from flask_sqlalchemy import SQLAlchemy
3
- from sqlalchemy_utils import UUIDType
2
+ from sqlalchemy.orm import sessionmaker
3
+ from sqlalchemy.orm import as_declarative, declared_attr,relationship
4
+ import sqlalchemy.orm as sa_orm
5
+
6
+ # from sqlalchemy_utils import UUIDType
4
7
  import re
5
8
  import os
6
- from sqlalchemy import Row, text, Sequence
9
+ from sqlalchemy import Row, create_engine, text, Sequence
10
+ import sqlalchemy as sa
11
+
12
+
13
+ # class SQLAlchemy:
14
+
15
+ # def __init__(self):
16
+ # self.engine = create_engine(os.environ.get("SQLALCHEMY_DATABASE_URI"))
17
+ # self.session_maker = sessionmaker(bind=self.engine)
18
+ # self.session=self.session_maker()
19
+ # @as_declarative()
20
+ # class Base:
21
+ # @declared_attr
22
+ # def __tablename__(cls):
23
+ # return cls.__name__.lower()
24
+
25
+ # @classmethod
26
+ # @property
27
+ # def query(cls):
28
+ # return self.session.query(cls)
29
+
30
+
31
+ # self.Query=sa_orm.Query
32
+ # self.Model=Base
33
+ # self.Table=sa.Table
34
+ # self.Column=sa.Column
35
+ # self.Integer=sa.Integer
36
+ # self.ForeignKey=sa.ForeignKey
7
37
 
38
+ # def _set_rel_query(self, kwargs) -> None:
39
+ # """Apply the extension's :attr:`Query` class as the default for relationships
40
+ # and backrefs.
8
41
 
42
+ # :meta private:
43
+ # """
44
+ # kwargs.setdefault("query_class", self.Query)
9
45
 
46
+ # if "backref" in kwargs:
47
+ # backref = kwargs["backref"]
10
48
 
49
+ # if isinstance(backref, str):
50
+ # backref = (backref, {})
11
51
 
12
- db: SQLAlchemy = SQLAlchemy()
13
- db.UUID = UUIDType # type: ignore
52
+ # backref[1].setdefault("query_class", self.Query)
14
53
 
54
+
55
+ # def relationship(
56
+ # self, *args, **kwargs
57
+ # ) :
58
+
59
+ # self._set_rel_query(kwargs)
60
+ # return sa_orm.relationship(*args, **kwargs)
61
+ from flask_sqlalchemy import SQLAlchemy
62
+
63
+
64
+ db = SQLAlchemy()
65
+ # db.UUID = UUIDType # type: ignore
66
+
67
+ def init_no_flask():
68
+ engine = create_engine(os.environ.get("SQLALCHEMY_DATABASE_URI"))
69
+ db.session = sessionmaker(bind=engine)()
15
70
 
16
71
  def init_app(app):
72
+
17
73
  app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
18
74
  db.init_app(app)
19
75
  with app.app_context():
@@ -33,3 +89,4 @@ def db_execute(query: str, return_val: bool = False, commit: bool = False, **par
33
89
  # res = connection.execute(text(query), params)
34
90
  # connection.commit()s
35
91
  # return res
92
+
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import xtlsapi
2
3
  from hiddifypanel.models import *
3
4
  from .abstract_driver import DriverABS
@@ -15,7 +16,7 @@ class SingboxApi(DriverABS):
15
16
  return xtlsapi.SingboxClient('127.0.0.1', 10086)
16
17
 
17
18
  def get_enabled_users(self):
18
- config_dir = current_app.config['HIDDIFY_CONFIG_PATH']
19
+ config_dir = os.environ['HIDDIFY_CONFIG_PATH']
19
20
  with open(f"{config_dir}/singbox/configs/01_api.json") as f:
20
21
  json_data = json.load(f)
21
22
  return {u.split("@")[0]: 1 for u in json_data['experimental']['v2ray_api']['stats']['users']}
@@ -16,7 +16,10 @@ def enabled_drivers():
16
16
 
17
17
  def get_users_usage(reset=True):
18
18
  res = {}
19
- users = list(User.query.all())
19
+ from hiddifypanel.database import db
20
+
21
+ users = db.session.query(User).all()
22
+ # users = list(User.query.all())
20
23
  res = defaultdict(lambda: {'usage': 0, 'devices': ''})
21
24
  for driver in enabled_drivers():
22
25
  try:
@@ -1,14 +1,46 @@
1
- from . import network
2
- from . import system
3
- from . import importer
4
- from . import github_issue
5
- from . import flask
6
- from . import convert
7
- from . import random
8
- from . import encode
9
- from . import auth
10
- from . import utils
11
- from . import model
12
- from . import crypto
13
- from . import proxy
14
- from . import node
1
+ from typing import TYPE_CHECKING
2
+ import importlib
3
+
4
+ class LazyLoader:
5
+ def __init__(self, module_name: str,package=None):
6
+ self.module_name = module_name
7
+ self._module = None
8
+ self.package=package
9
+
10
+
11
+ def __getattr__(self, item):
12
+ if self._module is None:
13
+ self._module = importlib.import_module(self.module_name,self.package)
14
+ return getattr(self._module, item)
15
+
16
+ if TYPE_CHECKING:
17
+ from . import system
18
+ from . import importer
19
+ from . import github_issue
20
+ from . import flask
21
+ from . import convert
22
+ from . import random
23
+ from . import encode
24
+ from . import auth
25
+ from . import model
26
+ from . import crypto
27
+ from . import proxy
28
+ from . import node
29
+ from . import utils
30
+ from . import network
31
+ else:
32
+ # Define modules for lazy loading
33
+ network = LazyLoader(".network",__name__)
34
+ system = LazyLoader(".system",__name__)
35
+ importer = LazyLoader(".importer",__name__)
36
+ github_issue = LazyLoader(".github_issue",__name__)
37
+ flask = LazyLoader(".flask",__name__)
38
+ convert = LazyLoader(".convert",__name__)
39
+ random = LazyLoader(".random",__name__)
40
+ encode = LazyLoader(".encode",__name__)
41
+ auth = LazyLoader(".auth",__name__)
42
+ utils = LazyLoader(".utils",__name__)
43
+ model = LazyLoader(".model",__name__)
44
+ crypto = LazyLoader(".crypto",__name__)
45
+ proxy = LazyLoader(".proxy",__name__)
46
+ node = LazyLoader(".node",__name__)
@@ -1,5 +1,6 @@
1
1
  import os
2
2
  import subprocess
3
+ import sys
3
4
  from cryptography.hazmat.primitives import serialization
4
5
  from cryptography.hazmat.primitives.asymmetric import x25519, ed25519
5
6
 
@@ -62,7 +63,7 @@ def generate_ssh_host_keys():
62
63
  "ssh-keygen", "-t", key_type,
63
64
  "-f", key_file,
64
65
  "-N", ""
65
- ], check=True)
66
+ ], check=True,stdout=sys.stderr)
66
67
 
67
68
  keys_dict[key_type]={}
68
69
  with open(key_file, "r") as f:
@@ -1,10 +1,9 @@
1
1
  import urllib.parse
2
2
  import base64
3
3
  import uuid
4
- from slugify import slugify
5
-
6
4
 
7
5
  def unicode_slug(instr: str) -> str:
6
+ from slugify import slugify
8
7
  return slugify(instr, lowercase=False, allow_unicode=True)
9
8
 
10
9
 
@@ -150,7 +150,7 @@ def is_admin_panel_call(deprecated_format: bool = False) -> bool:
150
150
  if deprecated_format:
151
151
  if f'{request.path}'.startswith(f'/{hconfig(ConfigEnum.proxy_path)}/') and "admin" in f'{request.path}':
152
152
  return True
153
- elif f'{request.path}'.startswith(f'/{hconfig(ConfigEnum.proxy_path_admin)}/admin/'):
153
+ elif f'{request.path}'.startswith(f'/{hconfig(ConfigEnum.proxy_path_admin)}/'):
154
154
  return True
155
155
  return False
156
156
 
@@ -1,6 +1,7 @@
1
1
  from flask_babel import gettext as _
2
2
  from typing import List, Union
3
3
  from flask import request
4
+ from loguru import logger
4
5
  import maxminddb
5
6
  import random
6
7
  import os
@@ -37,13 +38,15 @@ apt.ircf.space APT
37
38
  """
38
39
 
39
40
  try:
40
- IPASN = maxminddb.open_database('GeoLite2-ASN.mmdb') if os.path.exists('GeoLite2-ASN.mmdb') else {}
41
- IPCOUNTRY = maxminddb.open_database('GeoLite2-Country.mmdb') if os.path.exists('GeoLite2-Country.mmdb') else {}
42
- __ipcity = maxminddb.open_database('GeoLite2-City.mmdb') if os.path.exists('GeoLite2-City.mmdb') else {}
43
- except Exception as e:
44
- print("Error can not load maxminddb", file=sys.stderr)
41
+
42
+ IPASN = maxminddb.open_database('GeoLite2-ASN.mmdb')
43
+ IPCOUNTRY = maxminddb.open_database('GeoLite2-Country.mmdb')
44
+ # __ipcity = maxminddb.open_database('GeoLite2-City.mmdb')
45
+ except BaseException as e:
46
+ logger.error("Error can not load maxminddb")
45
47
  IPASN = {}
46
48
  IPCOUNTRY = {}
49
+ # __ipcity = {}
47
50
 
48
51
  __asn_map = {
49
52
  '58224': 'MKH',
@@ -101,13 +104,13 @@ def get_country(user_ip: str = '') -> Union[dict, str]:
101
104
  return 'unknown'
102
105
 
103
106
 
104
- def get_city(user_ip: str = '') -> Union[dict, str]:
105
- try:
106
- user_ip = user_ip or get_real_user_ip()
107
- res = __ipcity.get(user_ip)
108
- return {'city': res.get('city').get('name'), 'latitude': res.get('latitude'), 'longitude': res.get('longitude'), 'accuracy_radius': res.get('accuracy_radius')}
109
- except BaseException:
110
- return 'unknown'
107
+ # def get_city(user_ip: str = '') -> Union[dict, str]:
108
+ # try:
109
+ # user_ip = user_ip or get_real_user_ip()
110
+ # res = __ipcity.get(user_ip)
111
+ # return {'city': res.get('city').get('name'), 'latitude': res.get('latitude'), 'longitude': res.get('longitude'), 'accuracy_radius': res.get('accuracy_radius')}
112
+ # except BaseException:
113
+ # return 'unknown'
111
114
 
112
115
 
113
116
  def get_real_user_ip_debug(user_ip: str = '') -> str:
@@ -1,10 +1,15 @@
1
- import cloudflare
1
+
2
+ from typing import TYPE_CHECKING
2
3
  from hiddifypanel.models import hconfig, ConfigEnum
4
+ if TYPE_CHECKING:
5
+ import cloudflare
3
6
 
4
- __cf: cloudflare.Cloudflare # type: ignore
7
+ __cf: "cloudflare.Cloudflare" # type: ignore
5
8
 
6
9
 
7
10
  def __prepare_cf_api_client() -> bool:
11
+ import cloudflare
12
+
8
13
  '''Prepares cloudflare client if it's not already'''
9
14
  global __cf
10
15
  if __cf and isinstance(__cf, cloudflare.Cloudflare):
@@ -271,6 +271,7 @@ def add_stream_settings(base: dict, proxy: dict):
271
271
  add_httpupgrade_stream(ss, proxy)
272
272
  if proxy['transport'] == ProxyTransport.xhttp:
273
273
  ss['network'] = proxy['transport']
274
+ ss['transport'] = "xhttp"
274
275
  add_xhttp_stream(ss, proxy)
275
276
  if proxy['transport'] == 'ws':
276
277
  ss['network'] = proxy['transport']
@@ -19,7 +19,7 @@ def get_folder_size(folder_path: str) -> int:
19
19
 
20
20
  def top_processes() -> dict:
21
21
  # Get the process information
22
- processes = [p for p in psutil.process_iter(['name', 'memory_full_info', 'cpu_percent']) if p.info['name'] != '']
22
+ processes = [p for p in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent', 'memory_info']) if p.info['name'] != '']
23
23
  num_cores = psutil.cpu_count()
24
24
  # Calculate memory usage, RAM usage, and CPU usage for each process
25
25
  memory_usage = {}
@@ -27,20 +27,21 @@ def top_processes() -> dict:
27
27
  cpu_usage = {}
28
28
  for p in processes:
29
29
  name = p.info['name']
30
- if "python3" in name or "uwsgi" in name or 'flask' in name:
30
+ if p.info['username']=="hiddify-panel":
31
31
  name = "Hiddify"
32
- mem_info = p.info['memory_full_info']
33
- if mem_info is None:
34
- continue
35
- mem_usage = mem_info.uss
32
+ # mem_info = p.info['memory_full_info']
33
+ # if mem_info is None:
34
+ # continue
35
+ # mem_usage = mem_info.uss
36
+ mem_usage = p.info['memory_info'].rss
36
37
  cpu_percent = p.info['cpu_percent'] / num_cores
37
38
  if name in memory_usage:
38
39
  memory_usage[name] += mem_usage / (1024 ** 3)
39
- ram_usage[name] += mem_info.rss / (1024 ** 3)
40
+ ram_usage[name] += mem_usage / (1024 ** 3)
40
41
  cpu_usage[name] += cpu_percent
41
42
  else:
42
43
  memory_usage[name] = mem_usage / (1024 ** 3)
43
- ram_usage[name] = mem_info.rss / (1024 ** 3)
44
+ ram_usage[name] = mem_usage / (1024 ** 3)
44
45
  cpu_usage[name] = cpu_percent
45
46
 
46
47
  while len(cpu_usage) < 5:
@@ -1,5 +1,6 @@
1
1
  from flask_babel import lazy_gettext as _
2
- import requests
2
+ from hiddifypanel.hutils import LazyLoader
3
+ requests=LazyLoader("requests")
3
4
  from packaging.version import Version
4
5
  import re
5
6
  import sys
@@ -4,13 +4,13 @@ from flask import g
4
4
  from hiddifypanel.models.usage import DailyUsage
5
5
  from sqlalchemy import event, Column, Integer, Enum, Boolean, ForeignKey
6
6
  from strenum import StrEnum
7
- from apiflask import abort
8
- from flask_babel import gettext as __
9
- from flask_babel import lazy_gettext as _
7
+
8
+
9
+
10
10
  from hiddifypanel.database import db, db_execute
11
11
  from hiddifypanel.models.role import Role
12
12
  from hiddifypanel.models.base_account import BaseAccount
13
- from sqlalchemy_serializer import SerializerMixin
13
+
14
14
 
15
15
 
16
16
  class AdminMode(StrEnum):
@@ -25,7 +25,7 @@ class AdminMode(StrEnum):
25
25
  agent = auto()
26
26
 
27
27
 
28
- class AdminUser(BaseAccount, SerializerMixin):
28
+ class AdminUser(BaseAccount):
29
29
  """
30
30
  This is a model class for a user in a database that includes columns for their ID, UUID, name, online status,
31
31
  account expiration date, usage limit, package days, mode, start date, current usage, last reset time, and comment.
@@ -150,6 +150,8 @@ class AdminUser(BaseAccount, SerializerMixin):
150
150
  def remove(self):
151
151
  if self.id == 1 or self.id == g.account.id:
152
152
  # raise ValidationError(_("Owner can not be deleted!"))
153
+ from flask_babel import gettext as __
154
+ from apiflask import abort
153
155
  abort(422, __("Owner can not be deleted!"))
154
156
  users = self.recursive_users_query().all()
155
157
  for u in users:
@@ -6,10 +6,10 @@ from sqlalchemy import Column, String, BigInteger, Enum
6
6
  from flask_login import UserMixin as FlaskLoginUserMixin
7
7
  from hiddifypanel.models import Lang
8
8
  from hiddifypanel.database import db
9
- from sqlalchemy_serializer import SerializerMixin
10
9
 
11
10
 
12
- class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: ignore
11
+
12
+ class BaseAccount(db.Model, FlaskLoginUserMixin): # type: ignore
13
13
  __abstract__ = True
14
14
  uuid = Column(String(36), default=lambda: str(uuid.uuid4()), nullable=False, unique=True, index=True)
15
15
  name = Column(String(512), nullable=False, default='')
@@ -48,7 +48,7 @@ class BaseAccount(db.Model, SerializerMixin, FlaskLoginUserMixin): # type: igno
48
48
  @classmethod
49
49
  def by_id(cls, id: int):
50
50
  # return cls.query.filter(cls.id == id).first()
51
- return cls.query.get(id)
51
+ return db.session.query(cls).get(id)
52
52
 
53
53
  @classmethod
54
54
  def by_uuid(cls, uuid: str, create: bool = False):
@@ -8,7 +8,7 @@ from flask import g, has_app_context
8
8
 
9
9
 
10
10
  from hiddifypanel.database import db, db_execute
11
- from sqlalchemy_serializer import SerializerMixin
11
+
12
12
 
13
13
 
14
14
  class ChildMode(StrEnum):
@@ -19,7 +19,7 @@ class ChildMode(StrEnum):
19
19
  # the child model is node
20
20
 
21
21
 
22
- class Child(db.Model, SerializerMixin): # type: ignore
22
+ class Child(db.Model): # type: ignore
23
23
  id = Column(Integer, primary_key=True, autoincrement=True)
24
24
  name = Column(String(200), nullable=False, unique=False)
25
25
  mode = Column(Enum(ChildMode), nullable=False, default=ChildMode.virtual)
@@ -61,11 +61,11 @@ class Child(db.Model, SerializerMixin): # type: ignore
61
61
 
62
62
  @classmethod
63
63
  def by_id(cls, id: int) -> 'Child':
64
- return Child.query.filter(Child.id == id).first()
64
+ return db.session.query(Child).filter(Child.id == id).first()
65
65
 
66
66
  @classmethod
67
67
  def by_unique_id(cls, unique_id: str) -> 'Child':
68
- return Child.query.filter(Child.unique_id == unique_id).first()
68
+ return db.session.query(Child).filter(Child.unique_id == unique_id).first()
69
69
 
70
70
  @classmethod
71
71
  def current(cls) -> "Child":
@@ -8,11 +8,11 @@ from hiddifypanel.cache import cache
8
8
  from hiddifypanel.models.child import Child, ChildMode
9
9
  from sqlalchemy import Column, String, Boolean, Enum, ForeignKey, Integer
10
10
  from strenum import StrEnum
11
- from sqlalchemy_serializer import SerializerMixin
11
+
12
12
  from loguru import logger
13
13
 
14
14
 
15
- class BoolConfig(db.Model, SerializerMixin):
15
+ class BoolConfig(db.Model):
16
16
  child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
17
17
  # category = db.Column(db.String(128), primary_key=True)
18
18
  key = Column(Enum(ConfigEnum), primary_key=True)
@@ -35,7 +35,7 @@ class BoolConfig(db.Model, SerializerMixin):
35
35
  return HConfigSchema().load(conf_dict)
36
36
 
37
37
 
38
- class StrConfig(db.Model, SerializerMixin):
38
+ class StrConfig(db.Model):
39
39
  child_id = Column(Integer, ForeignKey('child.id'), primary_key=True, default=0)
40
40
  # category = db.Column(db.String(128), primary_key=True)
41
41
  key = Column(Enum(ConfigEnum), primary_key=True, default=ConfigEnum.admin_secret)
@@ -66,13 +66,13 @@ def hconfig(key: ConfigEnum, child_id: Optional[int] = None): # -> str | int |
66
66
  value = None
67
67
  try:
68
68
  if key.type == bool:
69
- bool_conf = BoolConfig.query.filter(BoolConfig.key == key, BoolConfig.child_id == child_id).first()
69
+ bool_conf = db.session.query(BoolConfig).filter(BoolConfig.key == key, BoolConfig.child_id == child_id).first()
70
70
  if bool_conf:
71
71
  value = bool_conf.value
72
72
  else:
73
73
  logger.warning(f'bool {key} not found ')
74
74
  else:
75
- str_conf = StrConfig.query.filter(StrConfig.key == key, StrConfig.child_id == child_id).first()
75
+ str_conf = db.session.query(StrConfig).filter(StrConfig.key == key, StrConfig.child_id == child_id).first()
76
76
  if str_conf:
77
77
  value = str_conf.value
78
78
  else:
@@ -1,4 +1,5 @@
1
1
  from enum import auto, Enum
2
+ import os
2
3
  from typing import Union
3
4
 
4
5
  from strenum import StrEnum
@@ -17,6 +18,7 @@ class Lang(HEnum):
17
18
  ru = auto()
18
19
  pt = auto()
19
20
  zh = auto()
21
+ my = auto()
20
22
 
21
23
 
22
24
  class PanelMode(HEnum):
@@ -193,7 +195,7 @@ class ConfigEnum(metaclass=FastEnum):
193
195
  http_proxy_enable = _BoolConfigDscr(ConfigCategory.http)
194
196
  block_iran_sites = _BoolConfigDscr(ConfigCategory.proxies, ApplyMode.apply_config, hide_in_virtual_child=True)
195
197
  allow_invalid_sni = _BoolConfigDscr(ConfigCategory.tls, ApplyMode.apply_config, hide_in_virtual_child=True)
196
- auto_update = _BoolConfigDscr(ConfigCategory.general, ApplyMode.apply_config, True, hide_in_virtual_child=True)
198
+ auto_update = _BoolConfigDscr(ConfigCategory.hidden if os.environ.get('HIDDIFY_DISABLE_UPDATE',"").lower() in {'1',"true"} else ConfigCategory.general, ApplyMode.apply_config, True, hide_in_virtual_child=True)
197
199
  speed_test = _BoolConfigDscr(ConfigCategory.general, ApplyMode.reinstall, hide_in_virtual_child=True)
198
200
  only_ipv4 = _BoolConfigDscr(ConfigCategory.general, ApplyMode.apply_config, hide_in_virtual_child=True)
199
201