feat: support dynamic daemon refill

This commit is contained in:
mmc
2026-03-19 15:15:05 +08:00
parent 2904e43b1f
commit fc0a2968ae
5 changed files with 31 additions and 9 deletions

View File

@@ -432,6 +432,11 @@ ocxxxxxxx@cursors.online
拿到什么就写什么,缺失字段会写空值或 `NULL` 拿到什么就写什么,缺失字段会写空值或 `NULL`
关于 `auto_register_max_per_loop`
- `0`:按当前差值动态补齐
- `1/2/3...`:每轮最多补指定数量
## 推荐的最小可用配置 ## 推荐的最小可用配置
如果你要先跑注册,再决定同步哪个平台,可以先这样: 如果你要先跑注册,再决定同步哪个平台,可以先这样:
@@ -440,7 +445,7 @@ ocxxxxxxx@cursors.online
{ {
"proxy": "http://127.0.0.1:17891", "proxy": "http://127.0.0.1:17891",
"auto_register": false, "auto_register": false,
"auto_register_max_per_loop": 1, "auto_register_max_per_loop": 0,
"db_enabled": false, "db_enabled": false,
"db_host": "150.158.105.6", "db_host": "150.158.105.6",
"db_port": 54321, "db_port": 54321,

View File

@@ -218,7 +218,7 @@ docker compose up --build
- 按配置周期检查号池状态 - 按配置周期检查号池状态
- 号池不足且 `auto_register = true` 时自动补号 - 号池不足且 `auto_register = true` 时自动补号
-`threshold - candidates` 估算补号差值,并受 `auto_register_max_per_loop` 限制 -`threshold - candidates` 估算补号差值;当 `auto_register_max_per_loop = 0` 时按差值动态补齐,否则受该值限制
- 号池满足阈值时不执行注册 - 号池满足阈值时不执行注册
-`maintain_interval_minutes` / `sub2api_maintain_interval_minutes` 自动维护 -`maintain_interval_minutes` / `sub2api_maintain_interval_minutes` 自动维护

View File

@@ -1,7 +1,7 @@
{ {
"proxy": "http://127.0.0.1:17891", "proxy": "http://127.0.0.1:17891",
"auto_register": false, "auto_register": false,
"auto_register_max_per_loop": 1, "auto_register_max_per_loop": 0,
"db_enabled": false, "db_enabled": false,
"db_host": "150.158.105.6", "db_host": "150.158.105.6",
"db_port": 54321, "db_port": 54321,

27
main.py
View File

@@ -287,7 +287,7 @@ def _derive_register_cap(cfg: dict[str, Any], explicit_cap: int) -> int:
if explicit_cap and explicit_cap > 0: if explicit_cap and explicit_cap > 0:
return explicit_cap return explicit_cap
try: try:
return max(1, int(cfg.get("auto_register_max_per_loop", 1) or 1)) return max(0, int(cfg.get("auto_register_max_per_loop", 1) or 0))
except (TypeError, ValueError): except (TypeError, ValueError):
return 1 return 1
@@ -356,8 +356,11 @@ def handle_daemon(args: argparse.Namespace) -> dict[str, Any]:
if unhealthy: if unhealthy:
names = ", ".join(item["name"] for item in unhealthy) names = ", ".join(item["name"] for item in unhealthy)
deficit = _calculate_register_deficit(unhealthy) deficit = _calculate_register_deficit(unhealthy)
planned = max(1, min(register_cap, deficit or 1)) planned = max(1, deficit or 1) if register_cap == 0 else max(1, min(register_cap, deficit or 1))
print(f"[!] 号池不足,开始自动补号: {names},差值约 {deficit},本轮计划补 {planned}") if register_cap == 0:
print(f"[!] 号池不足,开始自动补号: {names},差值约 {deficit},本轮按差值动态补 {planned}")
else:
print(f"[!] 号池不足,开始自动补号: {names},差值约 {deficit},本轮计划补 {planned}")
for index in range(planned): for index in range(planned):
print(f"[*] 自动补号进度: {index + 1}/{planned}") print(f"[*] 自动补号进度: {index + 1}/{planned}")
try: try:
@@ -477,6 +480,20 @@ def _prompt_int(prompt: str, default: int) -> int:
print("请输入整数。") print("请输入整数。")
def _prompt_non_negative_int(prompt: str, default: int) -> int:
while True:
value = _prompt_text(prompt, str(default)).strip()
try:
parsed = int(value)
except ValueError:
print("请输入大于等于 0 的整数。")
continue
if parsed < 0:
print("请输入大于等于 0 的整数。")
continue
return parsed
def _prompt_choice(prompt: str, options: list[str], default: str) -> str: def _prompt_choice(prompt: str, options: list[str], default: str) -> str:
option_text = "/".join(options) option_text = "/".join(options)
default_value = default if default in options else options[0] default_value = default if default in options else options[0]
@@ -499,8 +516,8 @@ def handle_config_setup(args: argparse.Namespace) -> dict[str, Any]:
cfg["proxy"] = _prompt_text("1) 注册代理地址", str(cfg.get("proxy") or "http://127.0.0.1:17891")) cfg["proxy"] = _prompt_text("1) 注册代理地址", str(cfg.get("proxy") or "http://127.0.0.1:17891"))
cfg["auto_register"] = _prompt_bool("2) 池不足时自动注册", bool(cfg.get("auto_register", False))) cfg["auto_register"] = _prompt_bool("2) 池不足时自动注册", bool(cfg.get("auto_register", False)))
cfg["auto_register_max_per_loop"] = _prompt_int(" 每轮最多自动补号数量", int(cfg.get("auto_register_max_per_loop", 1) or 1)) cfg["auto_register_max_per_loop"] = _prompt_non_negative_int(" 每轮最多自动补号数量(0 表示按差值动态补齐)", int(cfg.get("auto_register_max_per_loop", 1) or 1))
print(" 提示: 这个值越大补号越快,也会更激进。一般先用 1 或 2") print(" 提示: 0 表示按差值动态补齐;值越大补号越快,也会更激进。一般先用 1、20")
cfg["db_enabled"] = _prompt_bool(" 是否启用 PostgreSQL 注册信息入库", bool(cfg.get("db_enabled", False))) cfg["db_enabled"] = _prompt_bool(" 是否启用 PostgreSQL 注册信息入库", bool(cfg.get("db_enabled", False)))
if cfg["db_enabled"]: if cfg["db_enabled"]:
cfg["db_host"] = _prompt_text(" DB 主机", str(cfg.get("db_host") or "150.158.105.6")) cfg["db_host"] = _prompt_text(" DB 主机", str(cfg.get("db_host") or "150.158.105.6"))

View File

@@ -184,7 +184,7 @@ def normalize_config(cfg: Dict[str, Any]) -> Dict[str, Any]:
cfg["sub2api_maintain_actions"] = normalize_sub2api_maintain_actions(cfg.get("sub2api_maintain_actions")) cfg["sub2api_maintain_actions"] = normalize_sub2api_maintain_actions(cfg.get("sub2api_maintain_actions"))
cfg["auto_register"] = _as_bool(cfg.get("auto_register", False), default=False) cfg["auto_register"] = _as_bool(cfg.get("auto_register", False), default=False)
try: try:
cfg["auto_register_max_per_loop"] = max(1, min(int(cfg.get("auto_register_max_per_loop", 1)), 20)) cfg["auto_register_max_per_loop"] = max(0, min(int(cfg.get("auto_register_max_per_loop", 1)), 20))
except (TypeError, ValueError): except (TypeError, ValueError):
cfg["auto_register_max_per_loop"] = 1 cfg["auto_register_max_per_loop"] = 1
cfg["db_enabled"] = _as_bool(cfg.get("db_enabled", False), default=False) cfg["db_enabled"] = _as_bool(cfg.get("db_enabled", False), default=False)