ocfastapi / admin_interface.py
tanbushi's picture
v0.1.0: 初始完整部署
d99a1a3
# 管理界面模块
from fastapi import APIRouter, Request, Depends, HTTPException, status
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
from typing import Dict, Any, List, Optional
import psutil
import asyncio
from datetime import datetime
from auth import get_current_active_user, User, Token, create_access_token
from config import Config
from proxy import opencode_proxy
from version import get_version_info
# 创建路由
admin_router = APIRouter(prefix="/admin", tags=["管理"])
# 模板配置(稍后创建模板文件)
templates = Jinja2Templates(directory="templates")
class SystemStatus(BaseModel):
"""系统状态模型"""
cpu_percent: float
memory_percent: float
disk_percent: float
opencode_status: Dict[str, Any]
fastapi_status: str
uptime: str
version_info: Dict[str, Any]
class LoginRequest(BaseModel):
"""登录请求模型"""
username: str
password: str
class ServiceControl(BaseModel):
"""服务控制模型"""
action: str # restart, start, stop
async def get_system_info() -> Dict[str, Any]:
"""获取系统信息"""
try:
# CPU 使用率
cpu_percent = psutil.cpu_percent(interval=1)
# 内存使用率
memory = psutil.virtual_memory()
memory_percent = memory.percent
# 磁盘使用率
disk = psutil.disk_usage('/')
disk_percent = (disk.used / disk.total) * 100
# OpenCode 状态
opencode_info = await opencode_proxy.get_service_info()
# 系统启动时间
boot_time = psutil.boot_time()
uptime = datetime.now() - datetime.fromtimestamp(boot_time)
uptime_str = str(uptime).split('.')[0]
return {
"cpu_percent": cpu_percent,
"memory_percent": memory_percent,
"disk_percent": disk_percent,
"opencode_status": opencode_info,
"fastapi_status": "healthy",
"uptime": uptime_str
}
except Exception as e:
return {
"error": str(e),
"cpu_percent": 0,
"memory_percent": 0,
"disk_percent": 0,
"opencode_status": {"status": "unknown"},
"fastapi_status": "unknown",
"uptime": "unknown"
}
@admin_router.get("/", response_class=HTMLResponse)
async def admin_dashboard(request: Request):
"""管理仪表板主页"""
# 检查是否有有效的令牌
token = request.cookies.get("access_token")
if token:
try:
# 这里应该验证 token,为了简化先直接显示仪表板
return templates.TemplateResponse(
"dashboard.html",
{
"request": request,
"title": "管理仪表板"
}
)
except:
pass
# 没有有效令牌,重定向到登录页
return templates.TemplateResponse(
"login.html",
{
"request": request,
"title": "管理员登录"
}
)
@admin_router.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
"""登录页面"""
return templates.TemplateResponse(
"login.html",
{
"request": request,
"title": "管理员登录"
}
)
@admin_router.post("/login")
async def login(login_data: LoginRequest):
"""处理登录"""
if login_data.username != Config.ADMIN_USERNAME or login_data.password != Config.ADMIN_PASSWORD:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户名或密码错误"
)
# 创建访问令牌
access_token_expires = datetime.timedelta(minutes=Config.JWT_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": login_data.username},
expires_delta=access_token_expires
)
return {
"access_token": access_token,
"token_type": "bearer",
"expires_in": Config.JWT_EXPIRE_MINUTES * 60
}
@admin_router.get("/dashboard", response_class=HTMLResponse)
async def dashboard(request: Request, current_user: User = Depends(get_current_active_user)):
"""管理仪表板"""
return templates.TemplateResponse(
"dashboard.html",
{
"request": request,
"title": "管理仪表板",
"user": current_user
}
)
@admin_router.get("/api/system/status")
async def get_system_status(current_user: User = Depends(get_current_active_user)) -> SystemStatus:
"""获取系统状态"""
system_info = await get_system_info()
version_info = get_version_info()
return SystemStatus(
cpu_percent=system_info.get("cpu_percent", 0),
memory_percent=system_info.get("memory_percent", 0),
disk_percent=system_info.get("disk_percent", 0),
opencode_status=system_info.get("opencode_status", {}),
fastapi_status=system_info.get("fastapi_status", "unknown"),
uptime=system_info.get("uptime", "unknown"),
version_info=version_info
)
@admin_router.get("/api/version")
async def get_version(current_user: User = Depends(get_current_active_user)) -> Dict[str, Any]:
"""获取版本信息"""
return get_version_info()
@admin_router.post("/api/service/control")
async def control_service(
control: ServiceControl,
current_user: User = Depends(get_current_active_user)
):
"""服务控制"""
# 这里应该实现实际的服务控制逻辑
# 目前返回模拟响应
if control.action == "restart":
# TODO: 实现 OpenCode 服务重启
return {"status": "success", "message": "服务重启成功"}
elif control.action == "status":
status_info = await opencode_proxy.get_service_info()
return {"status": "success", "data": status_info}
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="不支持的操作"
)
@admin_router.get("/api/logs")
async def get_logs(
lines: int = 100,
current_user: User = Depends(get_current_active_user)
) -> Dict[str, Any]:
"""获取系统日志"""
# TODO: 实现日志获取逻辑
return {
"logs": [
f"{datetime.now().isoformat()} - [INFO] - 服务运行正常",
f"{datetime.now().isoformat()} - [INFO] - OpenCode 服务已启动",
],
"total_lines": 2
}
@admin_router.post("/logout")
async def logout():
"""登出"""
return {"message": "登出成功"}