|
@@ -21,11 +21,10 @@ from utils.mihomo_service import port_is_using,find_free_port
|
|
|
from utils.sub import update_config
|
|
from utils.sub import update_config
|
|
|
from utils.processes_mgr import process_manager
|
|
from utils.processes_mgr import process_manager
|
|
|
from database.models.subscription import SubscriptionManager,SubscriptFile,MihomoMeta
|
|
from database.models.subscription import SubscriptionManager,SubscriptFile,MihomoMeta
|
|
|
-# 初始化全局变量来保存进程池
|
|
|
|
|
|
|
+
|
|
|
POOL = None
|
|
POOL = None
|
|
|
mihomo_router = APIRouter()
|
|
mihomo_router = APIRouter()
|
|
|
|
|
|
|
|
-
|
|
|
|
|
class MihomoBatchRequest(BaseModel):
|
|
class MihomoBatchRequest(BaseModel):
|
|
|
id: int
|
|
id: int
|
|
|
port: Optional[int] = None
|
|
port: Optional[int] = None
|
|
@@ -42,8 +41,7 @@ class MihomoResponse(MihomoBatchRequest):
|
|
|
detail: Optional[Dict] = None
|
|
detail: Optional[Dict] = None
|
|
|
|
|
|
|
|
class MihomoMetaWithURL(MihomoMeta, table=False):
|
|
class MihomoMetaWithURL(MihomoMeta, table=False):
|
|
|
- # 覆盖导致问题的关系字段
|
|
|
|
|
- subscript_file: Optional[int] = None # 使用外键类型替代关系对象
|
|
|
|
|
|
|
+ subscript_file: Optional[int] = None
|
|
|
external_controller_url: Optional[str] = None
|
|
external_controller_url: Optional[str] = None
|
|
|
|
|
|
|
|
class Config:
|
|
class Config:
|
|
@@ -57,20 +55,30 @@ async def request_select_proxy_name(external_ctl: str, provider_name: str, proxy
|
|
|
for attempt in range(max_retries):
|
|
for attempt in range(max_retries):
|
|
|
try:
|
|
try:
|
|
|
response = await client.put(url, json=payload)
|
|
response = await client.put(url, json=payload)
|
|
|
- response.raise_for_status() # 如果请求失败,抛出异常
|
|
|
|
|
- return response # 该接口没有返回值,直接返回response
|
|
|
|
|
|
|
+ response.raise_for_status()
|
|
|
|
|
+ return response
|
|
|
except (httpx.HTTPError, httpx.RequestError) as e:
|
|
except (httpx.HTTPError, httpx.RequestError) as e:
|
|
|
if attempt < max_retries - 1:
|
|
if attempt < max_retries - 1:
|
|
|
- await asyncio.sleep(delay) # 等待一段时间后重试
|
|
|
|
|
|
|
+ await asyncio.sleep(delay)
|
|
|
else:
|
|
else:
|
|
|
raise HTTPException(status_code=500, detail=f"Failed to select proxy after {max_retries} attempts: {str(e)}")
|
|
raise HTTPException(status_code=500, detail=f"Failed to select proxy after {max_retries} attempts: {str(e)}")
|
|
|
|
|
+
|
|
|
|
|
+async def async_proxy_delay(provider_name: str, external_controller: str) -> dict:
|
|
|
|
|
+ """异步获取代理延迟"""
|
|
|
|
|
+ url = f"http://{external_controller}/group/{provider_name}/delay?url=https%3A%2F%2Fwww.gstatic.com%2Fgenerate_204&timeout=2000"
|
|
|
|
|
+ async with httpx.AsyncClient() as client:
|
|
|
|
|
+ try:
|
|
|
|
|
+ response = await client.get(url, timeout=30)
|
|
|
|
|
+ response.raise_for_status()
|
|
|
|
|
+ return response.json()
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ return {"error": str(e)}
|
|
|
|
|
+
|
|
|
@mihomo_router.post("/start")
|
|
@mihomo_router.post("/start")
|
|
|
async def post_start_mihomo(request: MihomoBatchRequest) -> MihomoMetaWithURL:
|
|
async def post_start_mihomo(request: MihomoBatchRequest) -> MihomoMetaWithURL:
|
|
|
db = SubscriptionManager()
|
|
db = SubscriptionManager()
|
|
|
logger.info(f"{request}")
|
|
logger.info(f"{request}")
|
|
|
- # 获取对应的订阅文件
|
|
|
|
|
with Session(db.engine) as session:
|
|
with Session(db.engine) as session:
|
|
|
- # 查找对应的订阅文件
|
|
|
|
|
miho_model = session.exec(
|
|
miho_model = session.exec(
|
|
|
select(MihomoMeta)
|
|
select(MihomoMeta)
|
|
|
.where(MihomoMeta.id == request.id)
|
|
.where(MihomoMeta.id == request.id)
|
|
@@ -79,19 +87,15 @@ async def post_start_mihomo(request: MihomoBatchRequest) -> MihomoMetaWithURL:
|
|
|
if not miho_model:
|
|
if not miho_model:
|
|
|
raise HTTPException(status_code=404, detail="Provider not found")
|
|
raise HTTPException(status_code=404, detail="Provider not found")
|
|
|
sub_file = miho_model.subscript_file
|
|
sub_file = miho_model.subscript_file
|
|
|
- # logger.info(f"miho_model.subscript_file {miho_model.subscript_file}")
|
|
|
|
|
- # return miho_model
|
|
|
|
|
|
|
+
|
|
|
if miho_model.pid:
|
|
if miho_model.pid:
|
|
|
return miho_model
|
|
return miho_model
|
|
|
mixed_port = request.port
|
|
mixed_port = request.port
|
|
|
- # 如果端口未指定,查找可用端口
|
|
|
|
|
if not mixed_port:
|
|
if not mixed_port:
|
|
|
mixed_port = find_free_port()
|
|
mixed_port = find_free_port()
|
|
|
external_controller_port = find_free_port((mixed_port+1, 18000))
|
|
external_controller_port = find_free_port((mixed_port+1, 18000))
|
|
|
config = {}
|
|
config = {}
|
|
|
- # 保存临时配置文件
|
|
|
|
|
temp_path = settings.MIHOMO_TEMP_PATH / f"{miho_model.provider_name}_{external_controller_port}.yaml"
|
|
temp_path = settings.MIHOMO_TEMP_PATH / f"{miho_model.provider_name}_{external_controller_port}.yaml"
|
|
|
- # 更新端口配置
|
|
|
|
|
config['mixed-port'] = mixed_port
|
|
config['mixed-port'] = mixed_port
|
|
|
config['external-controller'] = f'127.0.0.1:{external_controller_port}'
|
|
config['external-controller'] = f'127.0.0.1:{external_controller_port}'
|
|
|
config['bind-address'] = '127.0.0.1'
|
|
config['bind-address'] = '127.0.0.1'
|
|
@@ -100,7 +104,6 @@ async def post_start_mihomo(request: MihomoBatchRequest) -> MihomoMetaWithURL:
|
|
|
logger.info(f"config {config}")
|
|
logger.info(f"config {config}")
|
|
|
res = update_config(Path(sub_file.file_path), config, Path(temp_path))
|
|
res = update_config(Path(sub_file.file_path), config, Path(temp_path))
|
|
|
|
|
|
|
|
- # 启动进程
|
|
|
|
|
try:
|
|
try:
|
|
|
command = [str(settings.MIHOMO_BIN_PATH), "-f", str(temp_path)]
|
|
command = [str(settings.MIHOMO_BIN_PATH), "-f", str(temp_path)]
|
|
|
logger.info(f"Executing command: {' '.join(command)}")
|
|
logger.info(f"Executing command: {' '.join(command)}")
|
|
@@ -119,7 +122,6 @@ async def post_start_mihomo(request: MihomoBatchRequest) -> MihomoMetaWithURL:
|
|
|
logger.error(f"Failed to select proxy: {str(e)}")
|
|
logger.error(f"Failed to select proxy: {str(e)}")
|
|
|
process_manager.stop_process(external_controller_port)
|
|
process_manager.stop_process(external_controller_port)
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
- # 更新数据库记录
|
|
|
|
|
|
|
|
|
|
session.add(miho_model)
|
|
session.add(miho_model)
|
|
|
session.commit()
|
|
session.commit()
|
|
@@ -147,6 +149,7 @@ async def post_start_each_provider() -> List[MihomoMetaWithURL]:
|
|
|
logger.exception(f"Failed to start mihomo: {str(e)}")
|
|
logger.exception(f"Failed to start mihomo: {str(e)}")
|
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
return ret
|
|
return ret
|
|
|
|
|
+
|
|
|
@mihomo_router.post("/stop")
|
|
@mihomo_router.post("/stop")
|
|
|
async def post_stop_mihomo(request: MihomoBatchRequest):
|
|
async def post_stop_mihomo(request: MihomoBatchRequest):
|
|
|
db = SubscriptionManager()
|
|
db = SubscriptionManager()
|
|
@@ -188,19 +191,47 @@ async def get_mihomo_running_status():
|
|
|
|
|
|
|
|
return result
|
|
return result
|
|
|
|
|
|
|
|
-@mihomo_router.get("/proxies_reachability")
|
|
|
|
|
|
|
+@mihomo_router.post("/proxies_reachability")
|
|
|
async def get_proxies_reachability():
|
|
async def get_proxies_reachability():
|
|
|
|
|
+ # 1. 启动所有服务商
|
|
|
|
|
+ await post_start_each_provider()
|
|
|
|
|
+
|
|
|
|
|
+ # 2. 获取所有运行中的代理
|
|
|
db = SubscriptionManager()
|
|
db = SubscriptionManager()
|
|
|
- res = db.get_each_provider_running_proxies()
|
|
|
|
|
- logger.info(f"get_each_provider_running_proxies {res}")
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
|
|
+ running_proxies = db.get_running_proxies()
|
|
|
|
|
+
|
|
|
|
|
+ # 3. 测试延迟并更新数据库
|
|
|
|
|
+ results = []
|
|
|
|
|
+ for proxy in running_proxies:
|
|
|
|
|
+ if not proxy.external_controller:
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
|
|
+ try:
|
|
|
|
|
+ # 获取延迟数据
|
|
|
|
|
+ delay_data = await async_proxy_delay(proxy.provider_name, proxy.external_controller)
|
|
|
|
|
+
|
|
|
|
|
+ db.update_proxy_delays(
|
|
|
|
|
+ provider_name=proxy.provider_name,
|
|
|
|
|
+ delays=delay_data
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ # 收集结果
|
|
|
|
|
+ results.append({
|
|
|
|
|
+ "provider": proxy.provider_name,
|
|
|
|
|
+ "delays": delay_data
|
|
|
|
|
+ })
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ logger.error(f"Failed to update delays for {proxy.provider_name}: {str(e)}")
|
|
|
|
|
+ results.append({
|
|
|
|
|
+ "provider": proxy.provider_name,
|
|
|
|
|
+ "error": str(e)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return results
|
|
|
|
|
|
|
|
@mihomo_router.get("/external-controller")
|
|
@mihomo_router.get("/external-controller")
|
|
|
async def get_controller_urls():
|
|
async def get_controller_urls():
|
|
|
running_list = await get_mihomo_running_status()
|
|
running_list = await get_mihomo_running_status()
|
|
|
- logger.info(f"running_list {running_list}")
|
|
|
|
|
- # https://yacd.metacubex.one/?hostname=127.0.0.1&port=9351&secret=#/proxies
|
|
|
|
|
urls = []
|
|
urls = []
|
|
|
for item in running_list:
|
|
for item in running_list:
|
|
|
host, port = item.external_controller.split(":")
|
|
host, port = item.external_controller.split(":")
|
|
@@ -213,4 +244,3 @@ async def stop_all_mihomo():
|
|
|
if item.pid:
|
|
if item.pid:
|
|
|
logger.info(f"stop mihomo {item}")
|
|
logger.info(f"stop mihomo {item}")
|
|
|
await post_stop_mihomo(MihomoBatchRequest(id=item.id))
|
|
await post_stop_mihomo(MihomoBatchRequest(id=item.id))
|
|
|
- # logger.info(f"running_list {running_list}")
|
|
|