Просмотр исходного кода

Refactor config module:
- Enforce SRP by moving Config model assembly into models
- Unify Config entry point

Librellium 3 месяцев назад
Родитель
Сommit
97f8ce5057
3 измененных файлов с 58 добавлено и 20 удалено
  1. 1 1
      anonflow/config/__init__.py
  2. 23 14
      anonflow/config/config.py
  3. 34 5
      anonflow/config/models.py

+ 1 - 1
anonflow/config/__init__.py

@@ -1,3 +1,3 @@
 from .config import Config
 
-__all__ = ["Config"]
+__all__ = ["Config"]

+ 23 - 14
anonflow/config/config.py

@@ -3,15 +3,19 @@ from pathlib import Path
 import yaml
 from pydantic import BaseModel, SecretStr
 
-from .models import *
+from .models import Config as MainConfig
 
 
 class Config(BaseModel):
-    bot: Bot = Bot()
-    forwarding: Forwarding = Forwarding()
-    openai: OpenAI = OpenAI()
-    moderation: Moderation = Moderation()
-    logging: Logging = Logging()
+    config: MainConfig = MainConfig()
+
+    def __getattr__(self, name: str, /):
+        config = object.__getattribute__(self, "config")
+
+        if name in config.model_fields:
+            return object.__getattribute__(config, name)
+
+        return object.__getattribute__(self, name)
 
     @classmethod
     def _serialize(cls, obj):
@@ -27,18 +31,23 @@ class Config(BaseModel):
     @classmethod
     def load(cls, filepath: Path):
         filepath = Path(filepath)
-        filepath.parent.mkdir(parents = True, exist_ok = True)
-
-        config = cls()
+        filepath.parent.mkdir(parents=True, exist_ok=True)
 
         if filepath.exists():
-            with filepath.open(encoding = "utf-8") as f:
-                config = cls(**yaml.safe_load(f))
+            with filepath.open(encoding="utf-8") as f:
+                data = yaml.safe_load(f) or {}
+            return cls(config=MainConfig(**data))
 
-        return config
+        return cls(config=MainConfig())
 
     def save(self, filepath: Path):
-        filepath.parent.mkdir(parents = True, exist_ok = True)
+        filepath.parent.mkdir(parents=True, exist_ok=True)
 
         with filepath.open("w", encoding="utf-8") as config_file:
-            yaml.dump(self._serialize(self.model_dump()), config_file, width = float("inf"), sort_keys = False)
+            yaml.dump(
+                self._serialize(self.config.model_dump()),
+                config_file,
+                width=float("inf"),
+                sort_keys=False,
+                default_flow_style=False
+            )

+ 34 - 5
anonflow/config/models.py

@@ -2,32 +2,61 @@ from typing import List, Literal, Optional, TypeAlias
 
 from pydantic import BaseModel, SecretStr
 
-ForwardingMode: TypeAlias = Literal["both", "moderation", "publication"]
+SlowmodeMode: TypeAlias = Literal["global", "user"]
 ForwardingType: TypeAlias = Literal["text", "photo", "video"]
 ModerationType: TypeAlias = Literal["omni", "gpt"]
 LoggingLevel: TypeAlias = Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
 
+
 class Bot(BaseModel):
     token: Optional[SecretStr] = None
     timeout: int = 10
 
+
+class BehaviorSlowmode(BaseModel):
+    enabled: bool = True
+    mode: SlowmodeMode = "user"
+    delay: float = 120
+
+
+class BehaviorSubscriptionRequirement(BaseModel):
+    enabled: bool = True
+    channel_ids: Optional[List[int]] = None
+
+
+class Behavior(BaseModel):
+    slowmode: BehaviorSlowmode = BehaviorSlowmode()
+    subscription_requirement: BehaviorSubscriptionRequirement = BehaviorSubscriptionRequirement()
+
+
 class Forwarding(BaseModel):
-    mode: Optional[ForwardingMode] = "both"
-    moderation_chat_id: Optional[int] = None
-    publication_chat_id: Optional[int] = None
+    moderation_chat_ids: Optional[List[int]] = None
+    publication_channel_ids: Optional[List[int]] = None
     types: List[ForwardingType] = ["text", "photo", "video"]
 
+
 class OpenAI(BaseModel):
     api_key: Optional[SecretStr] = None
     timeout: int = 10
     max_retries: int = 0
 
+
 class Moderation(BaseModel):
     enabled: bool = True
     model: str = "gpt-5-mini"
     types: List[ModerationType] = ["omni", "gpt"]
 
+
 class Logging(BaseModel):
     level: LoggingLevel = "INFO"
     fmt: Optional[str] = "%(asctime)s.%(msecs)03d %(levelname)s [%(name)s] %(message)s"
-    date_fmt: Optional[str] = "%Y-%m-%d %H:%M:%S"
+    date_fmt: Optional[str] = "%Y-%m-%d %H:%M:%S"
+
+
+class Config(BaseModel):
+    bot: Bot = Bot()
+    behavior: Behavior = Behavior()
+    forwarding: Forwarding = Forwarding()
+    openai: OpenAI = OpenAI()
+    moderation: Moderation = Moderation()
+    logging: Logging = Logging()