Edit on GitHub

src.core.config

Основная конфигурация (настройки, параметры) приложения

  1"""Основная конфигурация (настройки, параметры) приложения"""
  2
  3import logging
  4import os
  5import pickle
  6from datetime import datetime
  7
  8from pandas import DataFrame
  9from pydantic import HttpUrl, SecretStr
 10from pydantic_settings import BaseSettings, SettingsConfigDict
 11from sqlalchemy.orm import DeclarativeBase
 12
 13from core.path import PATH
 14
 15logger = logging.getLogger()
 16
 17
 18class AuthorizeVar(BaseSettings):
 19    """Класс для хранения параметров авторизации yoomoney."""
 20
 21    client_id: SecretStr
 22    """Идентификатор клиента yoomoney."""
 23    client_secret: SecretStr
 24    """Секрет клиента yoomoney."""
 25
 26
 27class Base(DeclarativeBase):
 28    """Базовый класс для моделей SQLAlchemy."""
 29
 30    def __repr__(self):
 31        """Строковое представление экземпляра модели.
 32
 33        Returns:
 34            str: Строковое представление.
 35        """
 36        cols = [f"{col}={getattr(self, col)}" for col in self.__table__.columns.keys()]
 37        return f"<{self.__class__.__name__} {', '.join(cols)}>"
 38
 39    @property
 40    def __udict__(self):
 41        """Возвращает словарь атрибутов модели.
 42
 43        Returns:
 44            dict: Словарь с данными модели.
 45        """
 46        model_data = {col: getattr(self, col) for col in self.__table__.columns.keys()}
 47        return model_data
 48
 49    @property
 50    def __ustr_dict__(self):
 51        """Возвращает словарь атрибутов модели в виде строк.
 52
 53        Returns:
 54            dict: Словарь с данными модели в виде строк.
 55        """
 56        model_data = {
 57            col: str(getattr(self, col)) for col in self.__table__.columns.keys()
 58        }
 59        return model_data
 60
 61    @property
 62    def frame(self):
 63        """Возвращает DataFrame с данными модели.
 64
 65        Returns:
 66            DataFrame: DataFrame с данными модели.
 67        """
 68        return DataFrame([self.__udict__]).dropna(how="all")
 69
 70    def get_frame(self, *objects):
 71        """Возвращает DataFrame для переданных объектов.
 72
 73        Args:
 74            *objects: Объекты для извлечения данных.
 75
 76        Returns:
 77            DataFrame: DataFrame с данными объектов.
 78        """
 79        res = []
 80        for obj in objects:
 81            if type(obj) is type(self):
 82                res.append(obj.__udict__)
 83            else:
 84                res.append(self.__udict__)
 85        return DataFrame(res).dropna(how="all")
 86
 87
 88class Settings(BaseSettings):
 89    """Класс для хранения настроек приложения."""
 90
 91    BOT_TOKEN: SecretStr
 92    """Токен бота."""
 93    YOO_TOKEN: SecretStr
 94    """Токен Yoomoney."""
 95
 96    BOT_CHAT: int
 97    """ID чата бота."""
 98    BOT_URL: HttpUrl = "https://t.me/vpn_dan_bot"
 99    """URL бота."""
100    subserver_url: HttpUrl = "http:/assa.ddns.net"
101    """URL подсервера."""
102
103    DB_HOST: str
104    """Хост базы данных."""
105    DB_PORT: int
106    """Порт базы данных."""
107    DB_USER: str
108    """Имя пользователя базы данных."""
109    DB_PASS: SecretStr
110    """Пароль базы данных."""
111    DB_NAME: str
112    """Имя базы данных."""
113
114    ADMIN_LOGIN: str
115    """Логин администратора."""
116    ADMIN_PASS: SecretStr
117    """Пароль администратора."""
118    ADMIN_HASH: SecretStr
119    """Хеш пароля администратора."""
120    JWT_SECRET: SecretStr
121    """Секрет для JWT."""
122    ALGORITHM: str
123    """Алгоритм шифрования jwt токена"""
124
125    WG_HOST: str
126    """Хост WireGuard."""
127    WG_PORT: int
128    """Порт WireGuard."""
129    WG_USER: str
130    """Имя пользователя WireGuard."""
131    WG_PASS: SecretStr
132    """Пароль WireGuard."""
133    WG_KEY: SecretStr
134    """Ключ WireGuard."""
135    WG_SERVER_KEY: str
136    """Ключ сервера WireGuard."""
137
138    REDIS_HOST: str
139    """Хост Redis."""
140    REDIS_PORT: int
141    """Порт Redis."""
142    REDIS_USER: str
143    """Имя пользователя Redis."""
144    REDIS_PASS: SecretStr
145    """Пароль Redis."""
146    REDIS_NAME: str
147    """Имя базы данных Redis."""
148
149    acceptable_config: dict = {0: 0, 0.3: 1, 1: 3, 2.5: 8, 5: 15}
150    """Допустимое количество конфигураций для разных тарифов."""
151    cost: float
152    """Стоимость подписки."""
153    cash_ttl: int
154    """Время жизни кэша."""
155    transfer_fee: float
156    """Комиссия за перевод."""
157    max_dumps: int
158    """Максимальное количество дампов."""
159
160    model_config = SettingsConfigDict(
161        env_file=os.path.join(PATH, ".env"),
162        env_file_encoding="utf-8",
163        extra="ignore",
164    )
165
166    @property
167    def DATABASE_URL(self) -> str:
168        """URL для подключения к базе данных.
169
170        Returns:
171            str: URL подключения к базе данных в формате
172            postgresql+asyncpg://username:password@localhost:port/base
173        """
174        return f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS.get_secret_value()}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
175
176    @property
177    def CASHBASE_URL(self) -> str:
178        """URL для подключения к базе данных Redis.
179
180        Returns:
181            str: URL подключения к Redis в формате
182            redis://LOGIN:PASSWORD@HOST:PORT/NUM_DB
183        """
184        return f"redis://{self.REDIS_USER}:{self.REDIS_PASS.get_secret_value()}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_NAME}"
185
186
187try:
188    settings = Settings()
189
190except ValueError:
191    logger.exception("Ошибка загрузки входных параметров")
192    raise
193
194
195last_updated = datetime.today()
196"""Время последнего запуска"""
197decr_time = os.path.join(
198    PATH, "src", "scheduler", "timepoint", "last_decremented.pickle"
199)
200"""Сериализованная дата последнего списания средств"""
201noticed_time = os.path.join(
202    PATH, "src", "scheduler", "timepoint", "last_noticed.pickle"
203)
204"""Сериализованная дата последнего уведомления пользователей"""
205
206for timefile in (decr_time, noticed_time):
207    if not os.path.isfile(timefile):
208        with open(timefile, "wb") as file:
209            pickle.dump(last_updated, file)
logger = <RootLogger root (DEBUG)>
class AuthorizeVar(pydantic_settings.main.BaseSettings):
19class AuthorizeVar(BaseSettings):
20    """Класс для хранения параметров авторизации yoomoney."""
21
22    client_id: SecretStr
23    """Идентификатор клиента yoomoney."""
24    client_secret: SecretStr
25    """Секрет клиента yoomoney."""

Класс для хранения параметров авторизации yoomoney.

client_id: pydantic.types.SecretStr

Идентификатор клиента yoomoney.

client_secret: pydantic.types.SecretStr

Секрет клиента yoomoney.

model_config: ClassVar[pydantic_settings.main.SettingsConfigDict] = {'extra': 'forbid', 'arbitrary_types_allowed': True, 'validate_default': True, 'case_sensitive': False, 'env_prefix': '', 'nested_model_default_partial_update': False, 'env_file': None, 'env_file_encoding': None, 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_none_str': None, 'env_parse_enums': None, 'cli_prog_name': None, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_hide_none_type': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_use_class_docs_for_groups': False, 'cli_exit_on_error': True, 'cli_prefix': '', 'cli_flag_prefix_char': '-', 'cli_implicit_flags': False, 'cli_ignore_unknown_args': False, 'json_file': None, 'json_file_encoding': None, 'yaml_file': None, 'yaml_file_encoding': None, 'toml_file': None, 'secrets_dir': None, 'protected_namespaces': ('model_', 'settings_')}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, pydantic.fields.FieldInfo]] = {'client_id': FieldInfo(annotation=SecretStr, required=True), 'client_secret': FieldInfo(annotation=SecretStr, required=True)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

model_computed_fields: ClassVar[Dict[str, pydantic.fields.ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

class Base(sqlalchemy.inspection.Inspectable[sqlalchemy.orm.state.InstanceState[typing.Any]]):
28class Base(DeclarativeBase):
29    """Базовый класс для моделей SQLAlchemy."""
30
31    def __repr__(self):
32        """Строковое представление экземпляра модели.
33
34        Returns:
35            str: Строковое представление.
36        """
37        cols = [f"{col}={getattr(self, col)}" for col in self.__table__.columns.keys()]
38        return f"<{self.__class__.__name__} {', '.join(cols)}>"
39
40    @property
41    def __udict__(self):
42        """Возвращает словарь атрибутов модели.
43
44        Returns:
45            dict: Словарь с данными модели.
46        """
47        model_data = {col: getattr(self, col) for col in self.__table__.columns.keys()}
48        return model_data
49
50    @property
51    def __ustr_dict__(self):
52        """Возвращает словарь атрибутов модели в виде строк.
53
54        Returns:
55            dict: Словарь с данными модели в виде строк.
56        """
57        model_data = {
58            col: str(getattr(self, col)) for col in self.__table__.columns.keys()
59        }
60        return model_data
61
62    @property
63    def frame(self):
64        """Возвращает DataFrame с данными модели.
65
66        Returns:
67            DataFrame: DataFrame с данными модели.
68        """
69        return DataFrame([self.__udict__]).dropna(how="all")
70
71    def get_frame(self, *objects):
72        """Возвращает DataFrame для переданных объектов.
73
74        Args:
75            *objects: Объекты для извлечения данных.
76
77        Returns:
78            DataFrame: DataFrame с данными объектов.
79        """
80        res = []
81        for obj in objects:
82            if type(obj) is type(self):
83                res.append(obj.__udict__)
84            else:
85                res.append(self.__udict__)
86        return DataFrame(res).dropna(how="all")

Базовый класс для моделей SQLAlchemy.

Base(**kwargs: Any)
2165def _declarative_constructor(self: Any, **kwargs: Any) -> None:
2166    """A simple constructor that allows initialization from kwargs.
2167
2168    Sets attributes on the constructed instance using the names and
2169    values in ``kwargs``.
2170
2171    Only keys that are present as
2172    attributes of the instance's class are allowed. These could be,
2173    for example, any mapped columns or relationships.
2174    """
2175    cls_ = type(self)
2176    for k in kwargs:
2177        if not hasattr(cls_, k):
2178            raise TypeError(
2179                "%r is an invalid keyword argument for %s" % (k, cls_.__name__)
2180            )
2181        setattr(self, k, kwargs[k])

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance's class are allowed. These could be, for example, any mapped columns or relationships.

frame
62    @property
63    def frame(self):
64        """Возвращает DataFrame с данными модели.
65
66        Returns:
67            DataFrame: DataFrame с данными модели.
68        """
69        return DataFrame([self.__udict__]).dropna(how="all")

Возвращает DataFrame с данными модели.

Returns:

DataFrame: DataFrame с данными модели.

def get_frame(self, *objects):
71    def get_frame(self, *objects):
72        """Возвращает DataFrame для переданных объектов.
73
74        Args:
75            *objects: Объекты для извлечения данных.
76
77        Returns:
78            DataFrame: DataFrame с данными объектов.
79        """
80        res = []
81        for obj in objects:
82            if type(obj) is type(self):
83                res.append(obj.__udict__)
84            else:
85                res.append(self.__udict__)
86        return DataFrame(res).dropna(how="all")

Возвращает DataFrame для переданных объектов.

Arguments:
  • *objects: Объекты для извлечения данных.
Returns:

DataFrame: DataFrame с данными объектов.

registry = <sqlalchemy.orm.decl_api.registry object>
metadata = MetaData()
class Settings(pydantic_settings.main.BaseSettings):
 89class Settings(BaseSettings):
 90    """Класс для хранения настроек приложения."""
 91
 92    BOT_TOKEN: SecretStr
 93    """Токен бота."""
 94    YOO_TOKEN: SecretStr
 95    """Токен Yoomoney."""
 96
 97    BOT_CHAT: int
 98    """ID чата бота."""
 99    BOT_URL: HttpUrl = "https://t.me/vpn_dan_bot"
100    """URL бота."""
101    subserver_url: HttpUrl = "http:/assa.ddns.net"
102    """URL подсервера."""
103
104    DB_HOST: str
105    """Хост базы данных."""
106    DB_PORT: int
107    """Порт базы данных."""
108    DB_USER: str
109    """Имя пользователя базы данных."""
110    DB_PASS: SecretStr
111    """Пароль базы данных."""
112    DB_NAME: str
113    """Имя базы данных."""
114
115    ADMIN_LOGIN: str
116    """Логин администратора."""
117    ADMIN_PASS: SecretStr
118    """Пароль администратора."""
119    ADMIN_HASH: SecretStr
120    """Хеш пароля администратора."""
121    JWT_SECRET: SecretStr
122    """Секрет для JWT."""
123    ALGORITHM: str
124    """Алгоритм шифрования jwt токена"""
125
126    WG_HOST: str
127    """Хост WireGuard."""
128    WG_PORT: int
129    """Порт WireGuard."""
130    WG_USER: str
131    """Имя пользователя WireGuard."""
132    WG_PASS: SecretStr
133    """Пароль WireGuard."""
134    WG_KEY: SecretStr
135    """Ключ WireGuard."""
136    WG_SERVER_KEY: str
137    """Ключ сервера WireGuard."""
138
139    REDIS_HOST: str
140    """Хост Redis."""
141    REDIS_PORT: int
142    """Порт Redis."""
143    REDIS_USER: str
144    """Имя пользователя Redis."""
145    REDIS_PASS: SecretStr
146    """Пароль Redis."""
147    REDIS_NAME: str
148    """Имя базы данных Redis."""
149
150    acceptable_config: dict = {0: 0, 0.3: 1, 1: 3, 2.5: 8, 5: 15}
151    """Допустимое количество конфигураций для разных тарифов."""
152    cost: float
153    """Стоимость подписки."""
154    cash_ttl: int
155    """Время жизни кэша."""
156    transfer_fee: float
157    """Комиссия за перевод."""
158    max_dumps: int
159    """Максимальное количество дампов."""
160
161    model_config = SettingsConfigDict(
162        env_file=os.path.join(PATH, ".env"),
163        env_file_encoding="utf-8",
164        extra="ignore",
165    )
166
167    @property
168    def DATABASE_URL(self) -> str:
169        """URL для подключения к базе данных.
170
171        Returns:
172            str: URL подключения к базе данных в формате
173            postgresql+asyncpg://username:password@localhost:port/base
174        """
175        return f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS.get_secret_value()}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
176
177    @property
178    def CASHBASE_URL(self) -> str:
179        """URL для подключения к базе данных Redis.
180
181        Returns:
182            str: URL подключения к Redis в формате
183            redis://LOGIN:PASSWORD@HOST:PORT/NUM_DB
184        """
185        return f"redis://{self.REDIS_USER}:{self.REDIS_PASS.get_secret_value()}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_NAME}"

Класс для хранения настроек приложения.

BOT_TOKEN: pydantic.types.SecretStr

Токен бота.

YOO_TOKEN: pydantic.types.SecretStr

Токен Yoomoney.

BOT_CHAT: int

ID чата бота.

BOT_URL: Annotated[pydantic_core._pydantic_core.Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]

URL бота.

subserver_url: Annotated[pydantic_core._pydantic_core.Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]

URL подсервера.

DB_HOST: str

Хост базы данных.

DB_PORT: int

Порт базы данных.

DB_USER: str

Имя пользователя базы данных.

DB_PASS: pydantic.types.SecretStr

Пароль базы данных.

DB_NAME: str

Имя базы данных.

ADMIN_LOGIN: str

Логин администратора.

ADMIN_PASS: pydantic.types.SecretStr

Пароль администратора.

ADMIN_HASH: pydantic.types.SecretStr

Хеш пароля администратора.

JWT_SECRET: pydantic.types.SecretStr

Секрет для JWT.

ALGORITHM: str

Алгоритм шифрования jwt токена

WG_HOST: str

Хост WireGuard.

WG_PORT: int

Порт WireGuard.

WG_USER: str

Имя пользователя WireGuard.

WG_PASS: pydantic.types.SecretStr

Пароль WireGuard.

WG_KEY: pydantic.types.SecretStr

Ключ WireGuard.

WG_SERVER_KEY: str

Ключ сервера WireGuard.

REDIS_HOST: str

Хост Redis.

REDIS_PORT: int

Порт Redis.

REDIS_USER: str

Имя пользователя Redis.

REDIS_PASS: pydantic.types.SecretStr

Пароль Redis.

REDIS_NAME: str

Имя базы данных Redis.

acceptable_config: dict

Допустимое количество конфигураций для разных тарифов.

cost: float

Стоимость подписки.

cash_ttl: int

Время жизни кэша.

transfer_fee: float

Комиссия за перевод.

max_dumps: int

Максимальное количество дампов.

model_config = {'extra': 'ignore', 'arbitrary_types_allowed': True, 'validate_default': True, 'case_sensitive': False, 'env_prefix': '', 'nested_model_default_partial_update': False, 'env_file': '/home/bot/vpn_dan_bot/.env', 'env_file_encoding': 'utf-8', 'env_ignore_empty': False, 'env_nested_delimiter': None, 'env_parse_none_str': None, 'env_parse_enums': None, 'cli_prog_name': None, 'cli_parse_args': None, 'cli_parse_none_str': None, 'cli_hide_none_type': False, 'cli_avoid_json': False, 'cli_enforce_required': False, 'cli_use_class_docs_for_groups': False, 'cli_exit_on_error': True, 'cli_prefix': '', 'cli_flag_prefix_char': '-', 'cli_implicit_flags': False, 'cli_ignore_unknown_args': False, 'json_file': None, 'json_file_encoding': None, 'yaml_file': None, 'yaml_file_encoding': None, 'toml_file': None, 'secrets_dir': None, 'protected_namespaces': ('model_', 'settings_')}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

DATABASE_URL: str
167    @property
168    def DATABASE_URL(self) -> str:
169        """URL для подключения к базе данных.
170
171        Returns:
172            str: URL подключения к базе данных в формате
173            postgresql+asyncpg://username:password@localhost:port/base
174        """
175        return f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS.get_secret_value()}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"

URL для подключения к базе данных.

Returns:

str: URL подключения к базе данных в формате postgresql+asyncpg://username:password@localhost:port/base

CASHBASE_URL: str
177    @property
178    def CASHBASE_URL(self) -> str:
179        """URL для подключения к базе данных Redis.
180
181        Returns:
182            str: URL подключения к Redis в формате
183            redis://LOGIN:PASSWORD@HOST:PORT/NUM_DB
184        """
185        return f"redis://{self.REDIS_USER}:{self.REDIS_PASS.get_secret_value()}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_NAME}"

URL для подключения к базе данных Redis.

Returns:

str: URL подключения к Redis в формате redis://LOGIN:PASSWORD@HOST:PORT/NUM_DB

model_fields: ClassVar[Dict[str, pydantic.fields.FieldInfo]] = {'BOT_TOKEN': FieldInfo(annotation=SecretStr, required=True), 'YOO_TOKEN': FieldInfo(annotation=SecretStr, required=True), 'BOT_CHAT': FieldInfo(annotation=int, required=True), 'BOT_URL': FieldInfo(annotation=Url, required=False, default='https://t.me/vpn_dan_bot', metadata=[UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]), 'subserver_url': FieldInfo(annotation=Url, required=False, default='http:/assa.ddns.net', metadata=[UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)]), 'DB_HOST': FieldInfo(annotation=str, required=True), 'DB_PORT': FieldInfo(annotation=int, required=True), 'DB_USER': FieldInfo(annotation=str, required=True), 'DB_PASS': FieldInfo(annotation=SecretStr, required=True), 'DB_NAME': FieldInfo(annotation=str, required=True), 'ADMIN_LOGIN': FieldInfo(annotation=str, required=True), 'ADMIN_PASS': FieldInfo(annotation=SecretStr, required=True), 'ADMIN_HASH': FieldInfo(annotation=SecretStr, required=True), 'JWT_SECRET': FieldInfo(annotation=SecretStr, required=True), 'ALGORITHM': FieldInfo(annotation=str, required=True), 'WG_HOST': FieldInfo(annotation=str, required=True), 'WG_PORT': FieldInfo(annotation=int, required=True), 'WG_USER': FieldInfo(annotation=str, required=True), 'WG_PASS': FieldInfo(annotation=SecretStr, required=True), 'WG_KEY': FieldInfo(annotation=SecretStr, required=True), 'WG_SERVER_KEY': FieldInfo(annotation=str, required=True), 'REDIS_HOST': FieldInfo(annotation=str, required=True), 'REDIS_PORT': FieldInfo(annotation=int, required=True), 'REDIS_USER': FieldInfo(annotation=str, required=True), 'REDIS_PASS': FieldInfo(annotation=SecretStr, required=True), 'REDIS_NAME': FieldInfo(annotation=str, required=True), 'acceptable_config': FieldInfo(annotation=dict, required=False, default={0: 0, 0.3: 1, 1: 3, 2.5: 8, 5: 15}), 'cost': FieldInfo(annotation=float, required=True), 'cash_ttl': FieldInfo(annotation=int, required=True), 'transfer_fee': FieldInfo(annotation=float, required=True), 'max_dumps': FieldInfo(annotation=int, required=True)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

model_computed_fields: ClassVar[Dict[str, pydantic.fields.ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

last_updated = datetime.datetime(2025, 1, 24, 14, 9, 39, 750410)

Время последнего запуска

decr_time = '/home/bot/vpn_dan_bot/src/scheduler/timepoint/last_decremented.pickle'

Сериализованная дата последнего списания средств

noticed_time = '/home/bot/vpn_dan_bot/src/scheduler/timepoint/last_noticed.pickle'

Сериализованная дата последнего уведомления пользователей

settings = Settings(BOT_TOKEN=SecretStr('**********'), YOO_TOKEN=SecretStr('**********'), BOT_CHAT=-1002478942767, BOT_URL=Url('https://t.me/vpn_dan_bot'), subserver_url=Url('http://assa.ddns.net/'), DB_HOST='localhost', DB_PORT=5432, DB_USER='bot', DB_PASS=SecretStr('**********'), DB_NAME='devbotbase', ADMIN_LOGIN='admin', ADMIN_PASS=SecretStr('**********'), ADMIN_HASH=SecretStr('**********'), JWT_SECRET=SecretStr('**********'), ALGORITHM='HS256', WG_HOST='185.242.107.63', WG_PORT=51830, WG_USER='zadira', WG_PASS=SecretStr('**********'), WG_KEY=SecretStr('**********'), WG_SERVER_KEY='xlaQzDNN/L5VWGVfW2r4pR9ufa0tr0kXwA1U2kilNho=', REDIS_HOST='localhost', REDIS_PORT=6379, REDIS_USER='default', REDIS_PASS=SecretStr('**********'), REDIS_NAME='0', acceptable_config={0: 0, 0.3: 1, 1: 3, 2.5: 8, 5: 15}, cost=3.3, cash_ttl=24, transfer_fee=1.03, max_dumps=168)