新增设备身份管理、认证限流、并发通道、Webhook路由、RBAC权限控制、SSE/轮询降级等全套网关通道功能,包含: 1. 设备身份生成与签名验证 2. 设备令牌认证与速率限制 3. 内存+数据库双重设备注册表 4. 并发通道限流管理 5. Webhook安全处理与路由 6. RBAC权限校验系统 7. OpenAI API兼容适配层 8. Tailscale认证支持 9. HTTP轮询降级机制
111 lines
3.2 KiB
Python
111 lines
3.2 KiB
Python
from functools import wraps
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, ValidationError
|
|
|
|
from yuxi.channel.gateway.protocol import GatewayErrorCode, RpcRequest, RpcResponse
|
|
|
|
|
|
class ErrorShape(BaseModel):
|
|
code: str
|
|
message: str = ""
|
|
data: Any | None = None
|
|
retryable: bool = False
|
|
retryAfterMs: int | None = None
|
|
|
|
|
|
class RequestFrameSchema(BaseModel):
|
|
type: str = "request"
|
|
id: str
|
|
method: str
|
|
params: dict | None = None
|
|
sessionId: str | None = None
|
|
|
|
|
|
class ResponseFrameSchema(BaseModel):
|
|
type: str = "response"
|
|
id: str
|
|
ok: bool = True
|
|
result: dict | None = None
|
|
error: ErrorShape | None = None
|
|
|
|
|
|
class EventFrameSchema(BaseModel):
|
|
type: str = "event"
|
|
event: str
|
|
data: dict | None = None
|
|
timestamp: float = 0.0
|
|
seq: int | None = None
|
|
stateVersion: int | None = None
|
|
|
|
|
|
class StartAccountParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
config: dict = Field(default_factory=dict)
|
|
|
|
|
|
class StopAccountParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
force: bool = False
|
|
|
|
|
|
class SendMessageParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
target_id: str = Field(..., min_length=1, max_length=200)
|
|
text: str = Field(..., min_length=1, max_length=4096)
|
|
msg_type: str = Field(default="text")
|
|
media_url: str | None = None
|
|
extra: dict = Field(default_factory=dict)
|
|
|
|
|
|
class ProbeParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
|
|
|
|
class DiagnoseParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
|
|
|
|
class RepairParams(BaseModel):
|
|
model_config = ConfigDict(extra="allow")
|
|
|
|
channel_type: str = Field(..., min_length=1, max_length=50)
|
|
step_id: str = Field(..., min_length=1, max_length=100)
|
|
account_id: str = Field(default="default", min_length=1, max_length=100)
|
|
|
|
|
|
def validate_params(schema_cls: type[BaseModel]):
|
|
def decorator(func):
|
|
@wraps(func)
|
|
async def wrapper(request: RpcRequest, *args, **kwargs):
|
|
try:
|
|
validated = schema_cls(**(request.params or {}))
|
|
except ValidationError as e:
|
|
return RpcResponse(
|
|
id=request.id,
|
|
ok=False,
|
|
error_code=GatewayErrorCode.INVALID_PARAMS,
|
|
error_message=f"参数校验失败: {e}",
|
|
)
|
|
request._validated_params = validated
|
|
return await func(request, *args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|