ForcePilot/backend/package/yuxi/channels/adapters/signal/exec_auth.py
Kris 1f78c44b03 refactor: 整理并清理项目中的冗余代码与格式问题
这是一个批量整理提交,包含以下主要改动:
1.  删除多处冗余的空行和未使用的导入
2.  修复文件末尾缺少换行符的问题
3.  调整部分模块的导入顺序与代码排版
4.  修复部分配置默认值与策略逻辑
5.  新增多个功能模块与辅助工具
6.  完善异常处理与日志记录
7.  修复速率限制、消息缓存、权限校验等逻辑bug
8.  废弃部分旧有API与配置项并添加警告提示
2026-05-12 14:51:53 +08:00

95 lines
3.1 KiB
Python

from __future__ import annotations
import asyncio
import logging
from enum import StrEnum
from typing import Any
from collections.abc import Awaitable, Callable
logger = logging.getLogger(__name__)
EXEC_AUTH_TIMEOUT = 30.0
class ExecAuthResult(StrEnum):
APPROVED = "approved"
DENIED = "denied"
PENDING = "pending"
class ExecAuthAdapter:
def __init__(self, auto_approve: bool = False):
self._auto_approve = auto_approve
self._pending_requests: dict[str, dict] = {}
self._request_events: dict[str, asyncio.Event] = {}
self._request_counter = 0
self._on_approval_request: Callable[[dict], Awaitable[None]] | None = None
@property
def auto_approve(self) -> bool:
return self._auto_approve
def on_approval_request(self, handler: Callable[[dict], Awaitable[None]]) -> None:
self._on_approval_request = handler
async def request_approval(
self, action: str, params: dict[str, Any], user_id: str, timeout: float = EXEC_AUTH_TIMEOUT
) -> ExecAuthResult:
if self._auto_approve:
return ExecAuthResult.APPROVED
self._request_counter += 1
request_id = f"exec_auth_{self._request_counter}"
event = asyncio.Event()
request = {
"id": request_id,
"action": action,
"params": params,
"user_id": user_id,
"result": ExecAuthResult.PENDING,
}
self._pending_requests[request_id] = request
self._request_events[request_id] = event
if self._on_approval_request:
await self._on_approval_request(request)
try:
await asyncio.wait_for(event.wait(), timeout=timeout)
except TimeoutError:
logger.warning(f"Exec auth request {request_id} timed out after {timeout}s")
request["result"] = ExecAuthResult.DENIED
self._cleanup_request(request_id)
return ExecAuthResult.DENIED
result = request.get("result", ExecAuthResult.DENIED)
self._cleanup_request(request_id)
return ExecAuthResult(result)
def approve(self, request_id: str) -> ExecAuthResult:
request = self._pending_requests.get(request_id)
if not request:
return ExecAuthResult.DENIED
request["result"] = ExecAuthResult.APPROVED
event = self._request_events.get(request_id)
if event:
event.set()
return ExecAuthResult.APPROVED
def deny(self, request_id: str) -> ExecAuthResult:
request = self._pending_requests.get(request_id)
if not request:
return ExecAuthResult.DENIED
request["result"] = ExecAuthResult.DENIED
event = self._request_events.get(request_id)
if event:
event.set()
return ExecAuthResult.DENIED
def get_pending(self) -> list[dict]:
return [r for r in self._pending_requests.values() if r["result"] == ExecAuthResult.PENDING]
def _cleanup_request(self, request_id: str) -> None:
self._pending_requests.pop(request_id, None)
self._request_events.pop(request_id, None)