VWED_server/routes/script_api.py

358 lines
12 KiB
Python
Raw Normal View History

2025-04-30 16:57:46 +08:00
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
2025-09-12 16:15:13 +08:00
脚本管理API路由
提供脚本项目和文件的CRUD操作接口
2025-04-30 16:57:46 +08:00
"""
2025-09-12 16:15:13 +08:00
from fastapi import APIRouter, HTTPException, Depends, UploadFile, File
from fastapi.responses import JSONResponse
from typing import List, Optional, Dict, Any
from pydantic import BaseModel
from services.script_file_service import get_file_service
from services.script_engine_service import get_script_engine
from utils.api_response import success_response, error_response
2025-04-30 16:57:46 +08:00
from utils.logger import get_logger
2025-09-12 16:15:13 +08:00
logger = get_logger("routes.script_api")
router = APIRouter(prefix="/api/script", tags=["在线脚本模块"])
# 请求模型定义
class ProjectCreateRequest(BaseModel):
project_name: str
description: Optional[str] = ""
created_by: Optional[str] = None
class FileCreateRequest(BaseModel):
project_id: int
file_name: str
file_path: str
content: Optional[str] = ""
file_type: Optional[str] = "python"
created_by: Optional[str] = None
class FileUpdateRequest(BaseModel):
content: str
updated_by: Optional[str] = None
class ScriptStartRequest(BaseModel):
script_path: str
start_params: Optional[Dict[str, Any]] = None
class FunctionCallRequest(BaseModel):
script_id: str
function_name: str
function_args: Any = None
@router.post("/projects", summary="创建脚本项目")
async def create_project(request: ProjectCreateRequest):
"""创建新的脚本项目"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.create_project(
project_name=request.project_name,
description=request.description,
created_by=request.created_by
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return result
# return success_response(data=result["project"], message=result["message"])
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"创建项目失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"创建项目失败: {str(e)}")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
@router.get("/projects", summary="获取项目列表")
async def get_projects(status: Optional[str] = "active"):
"""获取所有脚本项目"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.get_projects(status=status)
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result["projects"])
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"获取项目列表失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取项目列表失败: {str(e)}")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
@router.get("/projects/{project_id}/files", summary="获取项目文件列表")
async def get_project_files(project_id: int, include_content: bool = False):
"""获取指定项目的所有文件"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.get_project_files(
project_id=project_id,
include_content=include_content
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result)
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"获取项目文件列表失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取项目文件列表失败: {str(e)}")
@router.post("/files", summary="创建脚本文件")
async def create_file(request: FileCreateRequest):
"""创建新的脚本文件"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.create_file(
project_id=request.project_id,
file_name=request.file_name,
file_path=request.file_path,
content=request.content,
file_type=request.file_type,
created_by=request.created_by
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result["file"], message=result["message"])
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"创建文件失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"创建文件失败: {str(e)}")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
@router.get("/files/{file_id}", summary="获取文件内容")
async def get_file_content(file_id: int):
"""获取脚本文件的内容"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.get_file_content(file_id=file_id)
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result)
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"获取文件内容失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取文件内容失败: {str(e)}")
@router.put("/files/{file_id}", summary="更新文件内容")
async def update_file_content(file_id: int, request: FileUpdateRequest):
"""更新脚本文件的内容"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.update_file_content(
file_id=file_id,
content=request.content,
updated_by=request.updated_by
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result["file"], message=result["message"])
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"更新文件内容失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"更新文件内容失败: {str(e)}")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
@router.delete("/files/{file_id}", summary="删除文件")
async def delete_file(file_id: int):
"""删除脚本文件"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.delete_file(file_id=file_id)
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(message=result["message"])
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"删除文件失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"删除文件失败: {str(e)}")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
@router.get("/files/search", summary="搜索文件")
async def search_files(
keyword: str,
project_id: Optional[int] = None,
file_type: Optional[str] = None,
has_boot: Optional[bool] = None
2025-04-30 16:57:46 +08:00
):
2025-09-12 16:15:13 +08:00
"""搜索脚本文件"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.search_files(
keyword=keyword,
project_id=project_id,
file_type=file_type,
has_boot=has_boot
)
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result)
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"搜索文件失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"搜索文件失败: {str(e)}")
@router.post("/validate-syntax", summary="验证脚本语法")
async def validate_syntax(request: dict):
"""验证Python脚本语法"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
content = request.get("content", "")
if not content:
return error_response(message="脚本内容不能为空")
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
file_service = get_file_service()
result = await file_service.validate_script_syntax(content)
if result["success"]:
return success_response(data=result)
else:
return error_response(message=result["error"])
except Exception as e:
logger.error(f"语法验证失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"语法验证失败: {str(e)}")
@router.post("/scripts/start", summary="启动脚本服务")
async def start_script_service(request: ScriptStartRequest):
"""启动脚本服务"""
try:
script_engine = get_script_engine()
result = await script_engine.start_script_service(
script_path=request.script_path,
start_params=request.start_params
)
if result["success"]:
return success_response(data=result, message=result["message"])
else:
return error_response(message=result["error"])
except Exception as e:
logger.error(f"启动脚本服务失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"启动脚本服务失败: {str(e)}")
@router.post("/scripts/{script_id}/stop", summary="停止脚本服务")
async def stop_script_service(script_id: str):
"""停止脚本服务"""
try:
script_engine = get_script_engine()
result = await script_engine.stop_script_service(script_id=script_id)
if result["success"]:
return success_response(message=result["message"])
else:
return error_response(message=result["error"])
except Exception as e:
logger.error(f"停止脚本服务失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"停止脚本服务失败: {str(e)}")
@router.get("/scripts/running", summary="获取运行中的脚本")
async def get_running_scripts():
"""获取所有运行中的脚本"""
try:
script_engine = get_script_engine()
running_scripts = script_engine.get_running_scripts()
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
return success_response(data=running_scripts)
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
except Exception as e:
logger.error(f"获取运行中的脚本失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取运行中的脚本失败: {str(e)}")
@router.post("/scripts/execute-function", summary="执行脚本函数")
async def execute_function(request: FunctionCallRequest):
"""执行脚本中的指定函数"""
try:
script_engine = get_script_engine()
result = await script_engine.execute_script_function(
script_id=request.script_id,
function_name=request.function_name,
function_args=request.function_args
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result)
else:
return error_response(message=result["error"])
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"执行脚本函数失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"执行脚本函数失败: {str(e)}")
@router.get("/registry/status", summary="获取注册中心状态")
async def get_registry_status():
"""获取脚本注册中心状态"""
2025-04-30 16:57:46 +08:00
try:
2025-09-12 16:15:13 +08:00
from services.script_registry_service import get_global_registry
registry = get_global_registry()
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
registrations = registry.get_all_registrations()
2025-04-30 16:57:46 +08:00
2025-09-12 16:15:13 +08:00
return success_response(data=registrations)
except Exception as e:
logger.error(f"获取注册中心状态失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"获取注册中心状态失败: {str(e)}")
@router.post("/upload", summary="上传脚本文件")
async def upload_script_file(
project_id: int,
file: UploadFile = File(...)
):
"""上传脚本文件"""
try:
# 读取文件内容
content = await file.read()
content_str = content.decode('utf-8')
file_service = get_file_service()
result = await file_service.create_file(
project_id=project_id,
file_name=file.filename,
file_path=file.filename,
content=content_str,
file_type="python"
2025-04-30 16:57:46 +08:00
)
2025-09-12 16:15:13 +08:00
if result["success"]:
return success_response(data=result["file"], message=result["message"])
else:
return error_response(message=result["error"])
except UnicodeDecodeError:
return error_response(message="文件编码错误请确保文件为UTF-8编码")
2025-04-30 16:57:46 +08:00
except Exception as e:
2025-09-12 16:15:13 +08:00
logger.error(f"上传脚本文件失败: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=f"上传脚本文件失败: {str(e)}")