""" 客户端 API - 兼容原 CursorPro 插件 """ from fastapi import APIRouter, Depends, Request from sqlalchemy.orm import Session from app.database import get_db from app.services import AccountService, KeyService, LogService, GlobalSettingsService from app.schemas import VerifyKeyRequest, VerifyKeyResponse, SwitchAccountRequest, SwitchAccountResponse router = APIRouter(prefix="/api", tags=["Client API"]) @router.post("/verify-key", response_model=VerifyKeyResponse) async def verify_key(request: VerifyKeyRequest, req: Request, db: Session = Depends(get_db)): """验证激活码""" key = KeyService.get_by_key(db, request.key) if not key: return VerifyKeyResponse(success=False, error="激活码不存在") # 首次激活:设置激活时间和过期时间 KeyService.activate(db, key) # 检查设备限制 if request.device_id: device_ok, device_msg = KeyService.check_device(db, key, request.device_id) if not device_ok: LogService.log(db, key.id, "verify", ip_address=req.client.host, success=False, message=device_msg) return VerifyKeyResponse(success=False, error=device_msg) # 检查激活码是否有效 is_valid, message = KeyService.is_valid(key, db) if not is_valid: LogService.log(db, key.id, "verify", ip_address=req.client.host, success=False, message=message) return VerifyKeyResponse(success=False, error=message) # 获取当前绑定的账号,或分配新账号 account = None if key.current_account_id: account = AccountService.get_by_id(db, key.current_account_id) if not account or account.status != "active": # 分配新账号 account = AccountService.get_available(db, key.membership_type) if not account: LogService.log(db, key.id, "verify", ip_address=req.client.host, success=False, message="无可用账号") return VerifyKeyResponse(success=False, error="暂无可用账号,请稍后重试") KeyService.bind_account(db, key, account) AccountService.mark_used(db, account, key.id) LogService.log(db, key.id, "verify", account.id, ip_address=req.client.host, success=True) expire_date = key.expire_at.strftime("%Y-%m-%d %H:%M:%S") if key.expire_at else None quota_cost = KeyService.get_quota_cost(db, key.membership_type) return VerifyKeyResponse( success=True, email=account.email, accessToken=account.access_token, refreshToken=account.refresh_token, WorkosCursorSessionToken=account.workos_session_token, membership_type=account.membership_type.value, quota=key.quota, quotaUsed=key.quota_used, quotaRemaining=key.quota - key.quota_used, quotaCost=quota_cost, expireDate=expire_date ) @router.post("/switch-account", response_model=SwitchAccountResponse) async def switch_account(request: SwitchAccountRequest, req: Request, db: Session = Depends(get_db)): """切换账号""" key = KeyService.get_by_key(db, request.key) if not key: return SwitchAccountResponse(success=False, error="激活码不存在") # 检查设备限制 if request.device_id: device_ok, device_msg = KeyService.check_device(db, key, request.device_id) if not device_ok: LogService.log(db, key.id, "switch", ip_address=req.client.host, success=False, message=device_msg) return SwitchAccountResponse(success=False, error=device_msg) # 检查激活码是否有效 is_valid, message = KeyService.is_valid(key, db) if not is_valid: LogService.log(db, key.id, "switch", ip_address=req.client.host, success=False, message=message) return SwitchAccountResponse(success=False, error=message) # 检查换号频率限制 can_switch, switch_msg = KeyService.can_switch(db, key) if not can_switch: LogService.log(db, key.id, "switch", ip_address=req.client.host, success=False, message=switch_msg) return SwitchAccountResponse(success=False, error=switch_msg) # 释放当前账号 if key.current_account_id: old_account = AccountService.get_by_id(db, key.current_account_id) if old_account: AccountService.release(db, old_account) # 获取新账号 account = AccountService.get_available(db, key.membership_type) if not account: LogService.log(db, key.id, "switch", ip_address=req.client.host, success=False, message="无可用账号") return SwitchAccountResponse(success=False, error="暂无可用账号,请稍后重试") # 绑定新账号并扣除额度 KeyService.bind_account(db, key, account) KeyService.use_switch(db, key) AccountService.mark_used(db, account, key.id) LogService.log(db, key.id, "switch", account.id, ip_address=req.client.host, success=True) return SwitchAccountResponse( success=True, message="切换成功", email=account.email, accessToken=account.access_token, refreshToken=account.refresh_token, WorkosCursorSessionToken=account.workos_session_token, membership_type=account.membership_type.value, quotaUsed=key.quota_used, quotaRemaining=key.quota - key.quota_used ) @router.get("/version") async def get_version(): """获取版本信息""" return { "version": "1.0.0", "update_url": None, "message": None } @router.get("/seamless/status") async def seamless_status(): """无感换号状态(简化实现)""" return { "success": True, "enabled": False, "message": "无感换号功能暂未开放" }