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)
19class AuthorizeVar(BaseSettings): 20 """Класс для хранения параметров авторизации yoomoney.""" 21 22 client_id: SecretStr 23 """Идентификатор клиента yoomoney.""" 24 client_secret: SecretStr 25 """Секрет клиента yoomoney."""
Класс для хранения параметров авторизации yoomoney.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
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.
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.
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.
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 с данными модели.
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 с данными объектов.
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}"
Класс для хранения настроек приложения.
URL бота.
URL подсервера.
Configuration for the model, should be a dictionary conforming to [ConfigDict
][pydantic.config.ConfigDict].
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
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
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.
Время последнего запуска
Сериализованная дата последнего списания средств
Сериализованная дата последнего уведомления пользователей