| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- from fastapi import APIRouter, HTTPException, Request, Depends
- from fastapi.responses import JSONResponse, StreamingResponse
- import httpx
- import os
- from pathlib import Path
- from typing import Dict
- from pydantic import BaseModel
- from typing import Optional
- import pathlib
- import os
- from utils.config import WORKER_SERVICE_URL,config,Browser
- from utils.logu import logger
- router = APIRouter()
- class Endpoint(BaseModel):
- service_url: str = WORKER_SERVICE_URL
- token: Optional[str] = "temp_token_123"
- health: Optional[Dict] = {}
- class BrowserPathValidationRequest(BaseModel):
- exe_path: str
- class PathValidationRequest(BaseModel):
- file_path: str
- class PathValidationResponse(BaseModel):
- valid: bool
- message: str
- file_name: Optional[str] = None
- file_size: Optional[int] = None
- class ResponseStatus(BaseModel):
- endpoint: Endpoint = Endpoint()
- browser_config: Optional[Browser] = None
-
- @router.post("/browser_config", tags=["worker"])
- async def update_browser_config(new_config: Browser):
- """更新浏览器配置"""
- config.browser = new_config
- config.save()
- return {"status": "success", "browser_config": config.browser}
- @router.post("/reset_browser_config", tags=["worker"])
- async def reset_browser_config():
- """重置浏览器配置为默认"""
- config.browser = Browser()
- config.save()
- return {"status": "success", "browser_config": config.browser}
- @router.get("/status", tags=["worker"])
- async def status():
- global config
- try:
- health = await health_check()
- except Exception as e:
- logger.error(e)
- health = {"err": 1, "msg": str(e)}
- """获取当前请求的端点"""
- return ResponseStatus(endpoint=Endpoint(health=health), browser_config=config.browser)
- @router.post("/validate_browser_path", tags=["worker"])
- async def validate_browser_path(request: BrowserPathValidationRequest):
- """验证浏览器路径是否有效"""
- path = Path(request.exe_path)
- try:
- if not path.exists():
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "路径不存在"
- })
-
- if not path.is_file():
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "路径不是文件"
- })
-
- if not os.access(path, os.X_OK):
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "文件不可执行"
- })
-
- if path.suffix.lower() != '.exe':
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "仅支持可执行文件 (.exe)"
- })
-
- return {
- "valid": True,
- "message": "浏览器路径有效"
- }
-
- except Exception as e:
- logger.error(f"浏览器路径验证失败: {str(e)}")
- return JSONResponse(status_code=500, content={
- "valid": False,
- "message": f"路径验证异常: {str(e)}"
- })
- @router.post("/validate_path", tags=["worker"])
- async def validate_file_path(request: PathValidationRequest):
- """验证文件路径是否有效"""
- path = Path(request.file_path)
- try:
- if not path.exists():
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "路径不存在"
- })
-
- if not path.is_file():
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "路径不是文件"
- })
-
- if not os.access(path, os.R_OK):
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "文件不可读"
- })
-
- if path.suffix.lower() not in ('.xlsx', '.xls'):
- return JSONResponse(status_code=400, content={
- "valid": False,
- "message": "仅支持Excel文件 (.xlsx/.xls)"
- })
-
- return {
- "valid": True,
- "message": "文件有效",
- "file_name": path.name,
- "file_size": path.stat().st_size
- }
-
- except Exception as e:
- logger.error(f"路径验证失败: {str(e)}")
- return JSONResponse(status_code=500, content={
- "valid": False,
- "message": f"路径验证异常: {str(e)}"
- })
- async def health_check():
- """健康检查"""
- async with httpx.AsyncClient(base_url=WORKER_SERVICE_URL) as client:
- response = await client.get("/health")
- response.raise_for_status()
- ret = response.json()
- ret.update({"err": 0})
- return ret
- async def get_request_body(request: Request):
- """获取原始请求体"""
- return await request.body()
- @router.api_route("/fuck/{path:path}", methods=["GET", "POST", "PUT", "DELETE"], tags=["worker"])
- async def proxy_worker_requests(
- path: str,
- request: Request,
- body: bytes = Depends(get_request_body)
- ):
- """全局反向代理到搜索微服务"""
- async with httpx.AsyncClient(base_url=WORKER_SERVICE_URL) as client:
- try:
- # 构造目标请求头(过滤掉不需要的 headers)
- headers = {
- "Content-Type": request.headers.get("Content-Type", ""),
- "Accept": request.headers.get("Accept", "application/json")
- }
- # 转发请求到目标服务
- response = await client.request(
- request.method,
- f"/{path}",
- content=body,
- headers=headers,
- timeout=60
- )
- # 流式返回响应内容
- return StreamingResponse(
- response.aiter_bytes(),
- status_code=response.status_code,
- headers=dict(response.headers)
- )
-
- except httpx.ConnectError:
- raise HTTPException(status_code=502, detail="搜索服务不可用")
- except Exception as e:
- raise HTTPException(status_code=500, detail=str(e))
-
-
|