| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- """持久化网页配置:账号数 / 接码 URL / 邮件助手 / CPA 等。"""
- from __future__ import annotations
- import json
- import os
- import threading
- from dataclasses import asdict, dataclass, field, fields
- CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "config.local.json")
- _LOCK = threading.Lock()
- @dataclass
- class AppConfig:
- # 注册控制
- account_count: int = 1
- headless: bool = False
- # 邮件
- mail_helper_url: str = "http://ali.ss5.xyz:17373"
- mail_domain: str = "edu.a4sky.com"
- mail_poll_interval_sec: int = 4
- mail_poll_max_attempts: int = 60 # 4s * 60 = 4min
- # PayPal / 接码
- phone_e164: str = "+15822201173"
- sms_api_url: str = "http://a.62-us.com/api/get_sms?key=a5d3262e05efaba982aba7cfae20b8bc"
- # CPA
- cpa_url: str = ""
- cpa_management_key: str = ""
- # 调试
- use_promo: bool = True
- @classmethod
- def load(cls) -> "AppConfig":
- if not os.path.exists(CONFIG_PATH):
- return cls()
- try:
- with open(CONFIG_PATH, "r", encoding="utf-8") as f:
- raw = json.load(f)
- except Exception:
- return cls()
- valid = {f.name for f in fields(cls)}
- cleaned = {k: v for k, v in (raw or {}).items() if k in valid}
- return cls(**cleaned)
- def save(self):
- with _LOCK:
- with open(CONFIG_PATH, "w", encoding="utf-8") as f:
- json.dump(asdict(self), f, ensure_ascii=False, indent=2)
- def update(self, patch: dict) -> "AppConfig":
- valid = {f.name for f in fields(self)}
- for k, v in (patch or {}).items():
- if k not in valid:
- continue
- current = getattr(self, k)
- if isinstance(current, bool):
- setattr(self, k, bool(v) if not isinstance(v, str) else v.lower() in ("1", "true", "yes", "on"))
- elif isinstance(current, int):
- try:
- setattr(self, k, int(v))
- except Exception:
- pass
- else:
- setattr(self, k, "" if v is None else str(v))
- self.save()
- return self
|