fix: unify backend port to 18080 and make validator targets configurable

- Set default API port to 18080 in config.py
- Add configurable validation_targets to SettingsSchema and DEFAULT_SETTINGS
- Update ValidatorService to support runtime test URL updates
- Hot-reload validation_targets from DB on startup and on settings save
- Add domestic fallback URLs (baidu.com, qq.com) to reduce foreign dependency risk
- Update Settings.vue to allow adding/removing validator target URLs in UI
This commit is contained in:
祀梦
2026-04-04 22:47:54 +08:00
parent b972b64616
commit 49e440cb41
7 changed files with 107 additions and 10 deletions

View File

@@ -4,7 +4,7 @@ import random
import time
import aiohttp
import aiohttp_socks
from typing import Tuple, Optional
from typing import Tuple, Optional, List
from app.core.config import settings as app_settings
from app.core.log import logger
@@ -16,10 +16,20 @@ class ValidatorService:
支持动态读取配置,实现设置热更新。
"""
# 测试 URL
TEST_URLS = {
"http": ["http://httpbin.org/ip", "http://api.ipify.org"],
"https": ["https://httpbin.org/ip", "https://api.ipify.org"],
# 测试 URL 默认池
DEFAULT_TEST_URLS = {
"http": [
"http://httpbin.org/ip",
"http://api.ipify.org",
"http://www.baidu.com",
"http://www.qq.com",
],
"https": [
"https://httpbin.org/ip",
"https://api.ipify.org",
"https://www.baidu.com",
"https://www.qq.com",
],
}
def __init__(
@@ -37,6 +47,7 @@ class ValidatorService:
self._http_session: Optional[aiohttp.ClientSession] = None
self._semaphore: Optional[asyncio.Semaphore] = None
self._lock = asyncio.Lock()
self._test_urls: Optional[List[str]] = None
@property
def timeout(self) -> float:
@@ -75,7 +86,17 @@ class ValidatorService:
return self._semaphore
def _get_test_url(self, protocol: str) -> str:
urls = self.TEST_URLS.get(protocol.lower(), self.TEST_URLS["http"])
custom_urls = self._test_urls
if not custom_urls:
from app.core.config import settings as app_settings
custom_urls = getattr(app_settings, "validator_test_urls", None)
if custom_urls and isinstance(custom_urls, list) and len(custom_urls) > 0:
# 按协议过滤自定义 URL如果没有匹配的则使用全部
filtered = [u for u in custom_urls if u.lower().startswith(protocol.lower())]
if filtered:
return random.choice(filtered)
return random.choice(custom_urls)
urls = self.DEFAULT_TEST_URLS.get(protocol.lower(), self.DEFAULT_TEST_URLS["http"])
return random.choice(urls)
async def validate(self, ip: str, port: int, protocol: str = "http") -> Tuple[bool, float]:
@@ -133,6 +154,10 @@ class ValidatorService:
return True, latency
return False, 0.0
def update_test_urls(self, urls: List[str]) -> None:
"""运行时更新验证目标 URL 列表"""
self._test_urls = list(urls) if urls else None
async def close(self) -> None:
"""关闭共享的 HTTP ClientSession"""
if self._http_session and not self._http_session.closed: