diff --git a/hiddifypanel/base.py b/hiddifypanel/base.py index 45b92a4c4..20b69885a 100644 --- a/hiddifypanel/base.py +++ b/hiddifypanel/base.py @@ -1,11 +1,7 @@ from flask import request, g # from hiddifypanel.cache import cache -from hiddifypanel.models import * -import flask_bootstrap -import hiddifypanel -from flask_babel import Babel -from flask_session import Session + import datetime @@ -13,130 +9,54 @@ import os import sys from apiflask import APIFlask -from werkzeug.middleware.proxy_fix import ProxyFix from loguru import logger -from hiddifypanel.panel.init_db import init_db -from hiddifypanel.hutils import hlogger -from sonora.wsgi import grpcWSGI +from dynaconf import FlaskDynaconf + def create_app(*args, cli=False, **config): app = APIFlask(__name__, static_url_path="//static/", instance_relative_config=True, version='2.2.0', title="Hiddify API", openapi_blueprint_url_prefix="//api", docs_ui='elements', json_errors=False, enable_openapi=not cli) # app = Flask(__name__, static_url_path="//static/", instance_relative_config=True) # app.asgi_app = WsgiToAsgi(app) - - if not cli: - - from hiddifypanel import auth - app.config["PREFERRED_URL_SCHEME"] = "https" - app.wsgi_app = ProxyFix( - app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1, - ) - - - app.secret_key="asdsad" - app.servers = { - 'name': 'current', - 'url': '', - } # type: ignore - app.info = { - 'description': 'Hiddify is a free and open source software. It is as it is.', - 'termsOfService': 'https://hiddify.com', - 'contact': { - 'name': 'API Support', - 'url': 'https://www.hiddify.com/support', - 'email': 'panel@hiddify.com' - }, - 'license': { - 'name': 'Creative Commons Zero v1.0 Universal', - 'url': 'https://github.com/hiddify/Hiddify-Manager/blob/main/LICENSE' - } - } - # setup flask server-side session - # app.config['APPLICATION_ROOT'] = './' - # app.config['SESSION_COOKIE_DOMAIN'] = '/' - - - app.jinja_env.line_statement_prefix = '%' - from hiddifypanel import hutils - app.jinja_env.filters['b64encode'] = hutils.encode.do_base_64 - app.view_functions['admin.static'] = {} # fix bug in apiflask - flask_bootstrap.Bootstrap4(app) - + for c, v in dotenv_values(os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')).items(): if v.isdecimal(): v = int(v) else: v = True if v.lower() == "true" else (False if v.lower() == "false" else v) - app.config[c] = v - hlogger.init_logger(app, cli) - hiddifypanel.database.init_app(app) - with app.app_context(): - init_db() - hlogger.set_level(app,hconfig(ConfigEnum.log_level)) - - def get_locale(): - # Put your logic here. Application can store locale in - # user profile, cookie, session, etc. - if "admin" in request.base_url: - g.locale = hconfig(ConfigEnum.admin_lang) or 'en' - else: - g.locale = auth.current_account.lang or hconfig(ConfigEnum.lang) or 'en' - return g.locale - app.jinja_env.globals['get_locale'] = get_locale - babel = Babel(app, locale_selector=get_locale) - if not cli: - app.config['SESSION_TYPE'] = 'redis' - from hiddifypanel.cache import redis_client - app.config['SESSION_REDIS'] = redis_client - app.config['SESSION_PERMANENT'] = True - app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=10) - app.security_schemes = { # equals to use config SECURITY_SCHEMES - 'Hiddify-API-Key': { - 'type': 'apiKey', - 'in': 'header', - 'name': 'Hiddify-API-Key', - } - } - Session(app) - app.wsgi_app = grpcWSGI(app.wsgi_app) - hiddifypanel.panel.common.init_app(app) - hiddifypanel.panel.common_bp.init_app(app) - - from hiddifypanel.panel import user, commercial, admin - admin.init_app(app) - user.init_app(app) - commercial.init_app(app) - from .panel import node - node.init_app(app) - + dyn=FlaskDynaconf(app,settings_files=[os.environ.get("HIDDIFY_CFG_PATH", 'app.cfg')]) + + if cli: + app.config['EXTENSIONS']=[ + # "hiddifypanel.cache:init_app", + "hiddifypanel.database:init_app", + "hiddifypanel.panel.hlogger:init_cli", + "hiddifypanel.panel.cli:init_app", + "hiddifypanel.celery:init_app", + ] + else: + app.config['EXTENSIONS']=[ + # "hiddifypanel.cache:init_app", + "hiddifypanel.database:init_app", + "hiddifypanel.panel.hlogger:init_app", + "hiddifypanel.base_setup:init_app", + "hiddifypanel.panel.common:init_app", + "hiddifypanel.panel.common_bp:init_app", + "hiddifypanel.panel.admin:init_app", + "hiddifypanel.panel.user:init_app", + "hiddifypanel.panel.commercial:init_app", + "hiddifypanel.panel.node:init_app", + "hiddifypanel.celery:init_app", + ] + app.config.update(config) # Override with passed config - # app.config['WTF_CSRF_CHECK_DEFAULT'] = False - # app.config['WTF_CSRF_ENABLED'] = False - # app.config['BABEL_TRANSLATION_DIRECTORIES'] = '/workspace/Hiddify-Server/hiddify-panel/src/translations.i18n' - - # from flask_wtf.csrf import CSRFProtect - - # csrf = CSRFProtect(app) - - # @app.before_request - # def check_csrf(): - # # if "/admin/user/" in request.base_url: - # # return - # # if "/admin/domain/" in request.base_url: - # # return - # # if "/admin/actions/" in request.base_url: - # # return - # # if "/api/" in request.base_url: - # # return - # csrf.protect() - - hiddifypanel.panel.cli.init_app(app) + + app.config.load_extensions("EXTENSIONS") return app @@ -145,16 +65,18 @@ def create_app_wsgi(*args, **kwargs): # that doesn't allow **config # to be passed to create_app # https://github.com/pallets/flask/issues/4170 - cli = ("hiddifypanel" in sys.argv[0]) or (sys.argv[1] in ["update-usage", "all-configs", "admin_links", "admin_path"]) + cli = ("hiddifypanel" in sys.argv[0] ) or (sys.argv[1] in ["update-usage", "all-configs", "admin_links", "admin_path"]) + app = create_app(cli=cli) return app -# def create_cli_app(*args, **kwargs): -# # # workaround for Flask issue -# # # that doesn't allow **config -# # # to be passed to create_app -# # # https://github.com/pallets/flask/issues/4170 -# # print(kwargs) -# app = create_app(*args, cli=True, **kwargs) -# return app + +def create_celery_app(): + # # workaround for Flask issue + # # that doesn't allow **config + # # to be passed to create_app + # # https://github.com/pallets/flask/issues/4170 + # print(kwargs) + app = create_app(cli=True) + return app.extensions["celery"] diff --git a/hiddifypanel/base_setup.py b/hiddifypanel/base_setup.py new file mode 100644 index 000000000..fe2da0690 --- /dev/null +++ b/hiddifypanel/base_setup.py @@ -0,0 +1,82 @@ +from flask import request, g +import redis +# from hiddifypanel.cache import cache +from hiddifypanel.models import * + +import flask_bootstrap +from flask_babel import Babel +from flask_session import Session + +import datetime + +from dotenv import dotenv_values +import os +import sys +from werkzeug.middleware.proxy_fix import ProxyFix +from loguru import logger +from sonora.wsgi import grpcWSGI + + + +def init_app(app): + from hiddifypanel import auth + app.config["PREFERRED_URL_SCHEME"] = "https" + app.wsgi_app = ProxyFix( + app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1, + ) + + + app.secret_key="asdsad" + app.servers = { + 'name': 'current', + 'url': '', + } # type: ignore + app.info = { + 'description': 'Hiddify is a free and open source software. It is as it is.', + 'termsOfService': 'https://hiddify.com', + 'contact': { + 'name': 'API Support', + 'url': 'https://www.hiddify.com/support', + 'email': 'panel@hiddify.com' + }, + 'license': { + 'name': 'Creative Commons Zero v1.0 Universal', + 'url': 'https://github.com/hiddify/Hiddify-Manager/blob/main/LICENSE' + } + } + # setup flask server-side session + # app.config['APPLICATION_ROOT'] = './' + # app.config['SESSION_COOKIE_DOMAIN'] = '/' + + + app.jinja_env.line_statement_prefix = '%' + from hiddifypanel import hutils + app.jinja_env.filters['b64encode'] = hutils.encode.do_base_64 + app.view_functions['admin.static'] = {} # fix bug in apiflask + flask_bootstrap.Bootstrap4(app) + + def get_locale(): + # Put your logic here. Application can store locale in + # user profile, cookie, session, etc. + if "admin" in request.base_url: + g.locale = hconfig(ConfigEnum.admin_lang) or 'en' + else: + g.locale = auth.current_account.lang or hconfig(ConfigEnum.lang) or 'en' + return g.locale + app.jinja_env.globals['get_locale'] = get_locale + babel = Babel(app, locale_selector=get_locale) + + app.config['SESSION_TYPE'] = 'redis' + + app.config['SESSION_REDIS'] = redis.from_url(os.environ['REDIS_URI_MAIN']) + app.config['SESSION_PERMANENT'] = True + app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=10) + app.security_schemes = { # equals to use config SECURITY_SCHEMES + 'Hiddify-API-Key': { + 'type': 'apiKey', + 'in': 'header', + 'name': 'Hiddify-API-Key', + } + } + Session(app) + app.wsgi_app = grpcWSGI(app.wsgi_app) \ No newline at end of file diff --git a/hiddifypanel/cache.py b/hiddifypanel/cache.py index c9acbbd87..b568de2b5 100644 --- a/hiddifypanel/cache.py +++ b/hiddifypanel/cache.py @@ -5,7 +5,7 @@ from loguru import logger redis_client = redis.from_url(os.environ["REDIS_URI_MAIN"]) - +# print(os.environ["REDIS_URI_MAIN"]) class CustomRedisCache(RedisCache): def __init__(self, redis_client, prefix="rc", serializer=compact_dump, deserializer=loads, key_serializer=None, support_cluster=True, exception_handler=None): diff --git a/hiddifypanel/celery.py b/hiddifypanel/celery.py new file mode 100644 index 000000000..8676e8acb --- /dev/null +++ b/hiddifypanel/celery.py @@ -0,0 +1,45 @@ +from celery import Celery, Task +from celery.schedules import crontab + +def init_app(app): + class FlaskTask(Task): + def __call__(self, *args: object, **kwargs: object) -> object: + with app.app_context(): + return self.run(*args, **kwargs) + + celery_app = Celery(app.name, task_cls=FlaskTask) + + celery_app.config_from_object(dict( + broker_url=app.config['REDIS_URI_MAIN'], + result_backend=app.config['REDIS_URI_MAIN'], + # task_ignore_result=True, + )) + app.extensions["celery"] = celery_app + + + # Calls test('hello') every 10 seconds. + from hiddifypanel.panel import usage + celery_app.add_periodic_task(60.0, usage.update_local_usage.s(), name='update usage') + # celery_app.conf.beat_schedule = { + # 'update_usage': { + # 'task': 'hiddifypanel.panel.usage.update_local_usage', + # 'schedule': 30.0, + + # }, +# } + from hiddifypanel.panel.cli import backup_task + celery_app.autodiscover_tasks() + # celery_app.add_periodic_task(30.0, backup_task.s(), name='backup task') + # celery_app.add_periodic_task( + # crontab(hour="*/6", minute=30), + # backup_task.delay(), + # ) + + celery_app.add_periodic_task( + crontab(hour="*/6", minute="0"), + backup_task.s(), + name="backup_task " + ) + + celery_app.set_default() + return celery_app \ No newline at end of file diff --git a/hiddifypanel/database.py b/hiddifypanel/database.py index 619e8ad1b..1b9ed1e47 100644 --- a/hiddifypanel/database.py +++ b/hiddifypanel/database.py @@ -6,6 +6,9 @@ from sqlalchemy import Row, text, Sequence + + + db: SQLAlchemy = SQLAlchemy() db.UUID = UUIDType # type: ignore @@ -13,6 +16,10 @@ def init_app(app): app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db.init_app(app) + with app.app_context(): + from hiddifypanel.panel.init_db import init_db + init_db() + def db_execute(query: str, return_val: bool = False, commit: bool = False, **params: dict): diff --git a/hiddifypanel/panel/__init__.py b/hiddifypanel/panel/__init__.py index 1b267ae7b..4c05e592a 100644 --- a/hiddifypanel/panel/__init__.py +++ b/hiddifypanel/panel/__init__.py @@ -1,9 +1,9 @@ -from . import user -# from . import admin -from . import cli -# from .. import database -from . import common -# from . import commercial -# from .. import auth -from . import common_bp +# from . import user +# # from . import admin +# from . import cli +# # from .. import database +# from . import common +# # from . import commercial +# # from .. import auth +# from . import common_bp diff --git a/hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py b/hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py index b95b40003..d294f165d 100644 --- a/hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py +++ b/hiddifypanel/panel/commercial/restapi/v2/admin/system_actions.py @@ -1,3 +1,5 @@ +import asyncio +import time from flask import current_app as app, request from flask import g from flask.views import MethodView @@ -16,7 +18,9 @@ class UpdateUserUsageApi(MethodView): def get(self): """System: Update User Usage""" - return json.dumps(usage.update_local_usage(), indent=2) + # time.sleep(5) + + return json.dumps(usage.update_local_usage_not_lock(), indent=2) class AllConfigsApi(MethodView): diff --git a/hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py b/hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py index f615caa47..13cefdffd 100644 --- a/hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py +++ b/hiddifypanel/panel/commercial/restapi/v2/admin/user_api.py @@ -6,7 +6,8 @@ from hiddifypanel.models import * from hiddifypanel.panel import hiddify from hiddifypanel.drivers import user_driver -from hiddifypanel.panel import hiddify + + from . import has_permission from .schema import UserSchema, PostUserSchema, PatchUserSchema, SuccessfulSchema diff --git a/hiddifypanel/hutils/hlogger.py b/hiddifypanel/panel/hlogger.py similarity index 78% rename from hiddifypanel/hutils/hlogger.py rename to hiddifypanel/panel/hlogger.py index 7e7e186a9..5fd354e98 100644 --- a/hiddifypanel/hutils/hlogger.py +++ b/hiddifypanel/panel/hlogger.py @@ -7,14 +7,25 @@ def logger_dynamic_formatter(record) -> str: fmt += ' | {extra}' return fmt + '\n' +def init_app(app): + init_logger(app,False) + +def init_cli(app): + init_logger(app,True) + def init_logger(app, cli): # configure logger + logger.remove() logger.add(sys.stderr if cli else sys.stdout, format=logger_dynamic_formatter, level=app.config['STDOUT_LOG_LEVEL'], colorize=True, catch=True, enqueue=True, diagnose=False, backtrace=True) logger.trace('Logger initiated :)') + with app.app_context(): + from hiddifypanel.models.config import hconfig,ConfigEnum + set_level(app,hconfig(ConfigEnum.log_level)) + def set_level(app, level): logger.add(app.config['HIDDIFY_CONFIG_PATH'] + "/log/system/panel.log", format=logger_dynamic_formatter, level=level, diff --git a/hiddifypanel/panel/usage.py b/hiddifypanel/panel/usage.py index 123e451e6..f62bde63f 100644 --- a/hiddifypanel/panel/usage.py +++ b/hiddifypanel/panel/usage.py @@ -11,16 +11,18 @@ from loguru import logger to_gig_d = 1024**3 +from celery import shared_task +@shared_task(ignore_result=False) def update_local_usage(): lock_key = "lock-update-local-usage" if not cache.redis_client.set(lock_key, "locked", nx=True, ex=600): return {"msg": "last update task is not finished yet."} try: - res = user_driver.get_users_usage(reset=True) - # cache.redis_client.delete(lock_key) + res=update_local_usage_not_lock() cache.redis_client.set(lock_key, "locked", nx=False, ex=60) - return _add_users_usage(res, child_id=0) + + return res except Exception as e: cache.redis_client.set(lock_key, "locked", nx=False, ex=60) logger.exception("Exception in update usage") @@ -28,6 +30,14 @@ def update_local_usage(): return {"msg": f"Exception in update usage: {e}"} # return {"status": 'success', "comments":res} +def update_local_usage_not_lock(): + + try: + res = user_driver.get_users_usage(reset=True) + return _add_users_usage(res, child_id=0) + except Exception as e: + raise + def add_users_usage_uuid(uuids_bytes: Dict[str, Dict], child_id, sync=False): diff --git a/poetry.lock b/poetry.lock index e783c877a..5ff46416c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -138,6 +138,25 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "amqp" +version = "5.3.1" +description = "Low-level AMQP client for Python (fork of amqplib)." +optional = false +python-versions = ">=3.6" +files = [ + {file = "amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2"}, + {file = "amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432"}, +] + +[package.dependencies] +vine = ">=5.0.0,<6.0.0" + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "aniso8601" version = "9.0.1" @@ -380,6 +399,22 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "billiard" +version = "4.2.1" +description = "Python multiprocessing fork with improvements and bugfixes" +optional = false +python-versions = ">=3.7" +files = [ + {file = "billiard-4.2.1-py3-none-any.whl", hash = "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb"}, + {file = "billiard-4.2.1.tar.gz", hash = "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "bjoern" version = "3.2.2" @@ -546,6 +581,67 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "celery" +version = "5.4.0" +description = "Distributed Task Queue." +optional = false +python-versions = ">=3.8" +files = [ + {file = "celery-5.4.0-py3-none-any.whl", hash = "sha256:369631eb580cf8c51a82721ec538684994f8277637edde2dfc0dacd73ed97f64"}, + {file = "celery-5.4.0.tar.gz", hash = "sha256:504a19140e8d3029d5acad88330c541d4c3f64c789d85f94756762d8bca7e706"}, +] + +[package.dependencies] +billiard = ">=4.2.0,<5.0" +click = ">=8.1.2,<9.0" +click-didyoumean = ">=0.3.0" +click-plugins = ">=1.1.1" +click-repl = ">=0.2.0" +kombu = ">=5.3.4,<6.0" +python-dateutil = ">=2.8.2" +tzdata = ">=2022.7" +vine = ">=5.1.0,<6.0" + +[package.extras] +arangodb = ["pyArango (>=2.0.2)"] +auth = ["cryptography (==42.0.5)"] +azureblockblob = ["azure-storage-blob (>=12.15.0)"] +brotli = ["brotli (>=1.0.0)", "brotlipy (>=0.7.0)"] +cassandra = ["cassandra-driver (>=3.25.0,<4)"] +consul = ["python-consul2 (==0.1.5)"] +cosmosdbsql = ["pydocumentdb (==2.3.5)"] +couchbase = ["couchbase (>=3.0.0)"] +couchdb = ["pycouchdb (==1.14.2)"] +django = ["Django (>=2.2.28)"] +dynamodb = ["boto3 (>=1.26.143)"] +elasticsearch = ["elastic-transport (<=8.13.0)", "elasticsearch (<=8.13.0)"] +eventlet = ["eventlet (>=0.32.0)"] +gcs = ["google-cloud-storage (>=2.10.0)"] +gevent = ["gevent (>=1.5.0)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +memcache = ["pylibmc (==1.6.3)"] +mongodb = ["pymongo[srv] (>=4.0.2)"] +msgpack = ["msgpack (==1.0.8)"] +pymemcache = ["python-memcached (>=1.61)"] +pyro = ["pyro4 (==4.82)"] +pytest = ["pytest-celery[all] (>=1.0.0)"] +redis = ["redis (>=4.5.2,!=4.5.5,<6.0.0)"] +s3 = ["boto3 (>=1.26.143)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +solar = ["ephem (==4.1.5)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "kombu[sqs] (>=5.3.4)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +tblib = ["tblib (>=1.3.0)", "tblib (>=1.5.0)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=1.3.1)"] +zstd = ["zstandard (==0.22.0)"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "certifi" version = "2024.8.30" @@ -784,6 +880,70 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "click-didyoumean" +version = "0.3.1" +description = "Enables git-like *did-you-mean* feature in click" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c"}, + {file = "click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463"}, +] + +[package.dependencies] +click = ">=7" + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + +[[package]] +name = "click-plugins" +version = "1.1.1" +description = "An extension module for click to enable registering CLI commands via setuptools entry-points." +optional = false +python-versions = "*" +files = [ + {file = "click-plugins-1.1.1.tar.gz", hash = "sha256:46ab999744a9d831159c3411bb0c79346d94a444df9a3a3742e9ed63645f264b"}, + {file = "click_plugins-1.1.1-py2.py3-none-any.whl", hash = "sha256:5d262006d3222f5057fd81e1623d4443e41dcda5dc815c06b442aa3c02889fc8"}, +] + +[package.dependencies] +click = ">=4.0" + +[package.extras] +dev = ["coveralls", "pytest (>=3.6)", "pytest-cov", "wheel"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + +[[package]] +name = "click-repl" +version = "0.3.0" +description = "REPL plugin for Click" +optional = false +python-versions = ">=3.6" +files = [ + {file = "click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9"}, + {file = "click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812"}, +] + +[package.dependencies] +click = ">=7.0" +prompt-toolkit = ">=3.0.36" + +[package.extras] +testing = ["pytest (>=7.2.1)", "pytest-cov (>=4.0.0)", "tox (>=4.4.3)"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "cloudflare" version = "3.1.0" @@ -1008,6 +1168,32 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "dynaconf" +version = "3.2.6" +description = "The dynamic configurator for your Python Project" +optional = false +python-versions = ">=3.8" +files = [ + {file = "dynaconf-3.2.6-py2.py3-none-any.whl", hash = "sha256:3911c740d717df4576ed55f616c7cbad6e06bc8ef23ffca444b6e2a12fb1c34c"}, + {file = "dynaconf-3.2.6.tar.gz", hash = "sha256:74cc1897396380bb957730eb341cc0976ee9c38bbcb53d3307c50caed0aedfb8"}, +] + +[package.extras] +all = ["configobj", "hvac", "redis", "ruamel.yaml"] +configobj = ["configobj"] +ini = ["configobj"] +redis = ["redis"] +test = ["configobj", "django", "flask (>=0.12)", "hvac (>=1.1.0)", "pytest", "pytest-cov", "pytest-mock", "pytest-xdist", "python-dotenv", "radon", "redis", "toml"] +toml = ["toml"] +vault = ["hvac"] +yaml = ["ruamel.yaml"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -2058,6 +2244,44 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "kombu" +version = "5.4.2" +description = "Messaging library for Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "kombu-5.4.2-py3-none-any.whl", hash = "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763"}, + {file = "kombu-5.4.2.tar.gz", hash = "sha256:eef572dd2fd9fc614b37580e3caeafdd5af46c1eff31e7fba89138cdb406f2cf"}, +] + +[package.dependencies] +amqp = ">=5.1.1,<6.0.0" +tzdata = {version = "*", markers = "python_version >= \"3.9\""} +vine = "5.1.0" + +[package.extras] +azureservicebus = ["azure-servicebus (>=7.10.0)"] +azurestoragequeues = ["azure-identity (>=1.12.0)", "azure-storage-queue (>=12.6.0)"] +confluentkafka = ["confluent-kafka (>=2.2.0)"] +consul = ["python-consul2 (==0.1.5)"] +librabbitmq = ["librabbitmq (>=2.0.0)"] +mongodb = ["pymongo (>=4.1.1)"] +msgpack = ["msgpack (==1.1.0)"] +pyro = ["pyro4 (==4.82)"] +qpid = ["qpid-python (>=0.26)", "qpid-tools (>=0.26)"] +redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2)"] +slmq = ["softlayer-messaging (>=1.0.3)"] +sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] +sqs = ["boto3 (>=1.26.143)", "pycurl (>=7.43.0.5)", "urllib3 (>=1.26.16)"] +yaml = ["PyYAML (>=3.10)"] +zookeeper = ["kazoo (>=2.8.0)"] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "loguru" version = "0.7.2" @@ -4106,6 +4330,22 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "tzdata" +version = "2024.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "ua-parser" version = "0.18.0" @@ -4162,6 +4402,22 @@ type = "legacy" url = "https://pypi.org/simple" reference = "pypi-public" +[[package]] +name = "vine" +version = "5.1.0" +description = "Python promises." +optional = false +python-versions = ">=3.6" +files = [ + {file = "vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc"}, + {file = "vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0"}, +] + +[package.source] +type = "legacy" +url = "https://pypi.org/simple" +reference = "pypi-public" + [[package]] name = "watchdog" version = "6.0.0" @@ -4457,4 +4713,4 @@ reference = "pypi-public" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "7fce77c62d0195e809f5d85735322cd5c760bea79a0ff3052ee7246aa97cc84c" +content-hash = "84805559c0af67431360836acb822c8234c6d7ceaf3bd5b7ef564ad6dd3d99d9" diff --git a/pyproject.toml b/pyproject.toml index 7edc8b858..e277bc735 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,6 +77,8 @@ sqlalchemy-serializer = "^1.4.22" sonora = "^0.2.3" protobuf = "^5.26.1" asgiref = "^3.8.1" +celery = "^5.4.0" +dynaconf = "^3.2.6" [tool.poetry.group.dev.dependencies] diff --git a/wsgi.py b/wsgi.py index 28cbb2fa7..c07955591 100755 --- a/wsgi.py +++ b/wsgi.py @@ -5,6 +5,6 @@ app = application = create_app_wsgi() # noqa from asgiref.wsgi import WsgiToAsgi asgi_app = WsgiToAsgi(app) - +celery_app=app.extensions["celery"] if __name__ == "__main__": app.run()