- 后端改为 config/app.json;pytest 使用 config/app.test.json 与 set_config_file,不再依赖环境变量;移除 pydantic-settings。 - 前端 API/WebSocket 由 config/webui.json 经 Vite define 注入。 - 代理分数按延迟与随机取用次数计算,新增 use_count 与 proxy_scoring;保存设置时同步调度器启停。 - 仪表盘双饼图(可用/待验证协议);设置页去掉调度器启停按钮并移动立即验证;爬取全部结束后自动提交全量验证。 - 删除 script/settings_maintain.py(此前已标记删除)。 Made-with: Cursor
63 lines
1.7 KiB
Python
63 lines
1.7 KiB
Python
"""领域模型 - 纯数据结构,不依赖任何框架"""
|
||
from dataclasses import dataclass, field
|
||
from datetime import datetime
|
||
from typing import List, Optional
|
||
|
||
|
||
@dataclass
|
||
class ProxyRaw:
|
||
"""爬虫爬取的原始代理数据"""
|
||
ip: str
|
||
port: int
|
||
protocol: str = "http"
|
||
|
||
def __post_init__(self):
|
||
self.protocol = self.protocol.lower().strip()
|
||
if self.protocol not in ("http", "https", "socks4", "socks5"):
|
||
self.protocol = "http"
|
||
if not isinstance(self.port, int) or not (1 <= self.port <= 65535):
|
||
raise ValueError(f"port must be between 1 and 65535, got {self.port}")
|
||
|
||
|
||
@dataclass
|
||
class Proxy:
|
||
"""数据库中的代理实体"""
|
||
|
||
ip: str
|
||
port: int
|
||
protocol: str
|
||
score: int
|
||
response_time_ms: Optional[float] = None
|
||
last_check: Optional[datetime] = None
|
||
created_at: Optional[datetime] = None
|
||
validated: int = 0 # 0 待验证 1 已验证(可参与分数与对外取用)
|
||
use_count: int = 0 # 被随机 API 取用的累计次数(用于降权)
|
||
|
||
|
||
@dataclass
|
||
class PluginInfo:
|
||
"""插件元数据"""
|
||
id: str
|
||
name: str
|
||
display_name: str
|
||
description: str
|
||
enabled: bool
|
||
last_run: Optional[datetime] = None
|
||
success_count: int = 0
|
||
failure_count: int = 0
|
||
|
||
|
||
@dataclass
|
||
class CrawlResult:
|
||
"""插件爬取结果
|
||
|
||
success_count: 最近一轮成功爬取到的代理条数(去重后),非「验证通过数」
|
||
failure_count: 最近一轮是否爬取失败(健康检查/超时/异常为 1,否则为 0)
|
||
"""
|
||
|
||
plugin_name: str
|
||
proxies: List[ProxyRaw] = field(default_factory=list)
|
||
success_count: int = 0
|
||
failure_count: int = 0
|
||
error: Optional[str] = None
|