feat: [EPIC-GW-03] 本地控制面契约硬化 (JSON-RPC 2.0 切换)#302
Conversation
实现控制面底层 IPC 传输从“裸 MessageFrame”向“标准 JSON-RPC 2.0”的直接无缝切换,硬化内部契约,为后续 Runtime 接入奠定稳定基座。 主要改动: 1. 协议归一化:新增 JSON-RPC 解析层,使用 json.RawMessage 延迟解析 params,并统一收敛至内部 MessageFrame 进行路由。 2. 错误模型重构:采用标准 JSON-RPC 错误码 (error.code),并将网关业务错误码统一映射至 error.data.gateway_code。 3. 适配器升级:url-dispatch 全面切换为 JSON-RPC 收发,并补齐了严密的 RequestID/Action 响应关联校验。 4. 稳定性增强:修复 URL 调度器的 context 取消中断逻辑(防止无界阻塞),并修复 Windows 环境下的绝对路径越界检测漏洞。 5. 测试覆盖:大幅增补 Server/Dispatcher 协议回归单测,网关核心覆盖率达 95.3%。
|
/review |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
/review |
|
/simplify |
处理结果已按你的
未执行项:无。 |
- block Windows drive-relative review paths across platforms - ensure JSON-RPC error responses keep id field (null when unknown) - strengthen dispatcher success-case RPC envelope assertions Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
|
/review |
| @@ -0,0 +1,292 @@ | |||
| package protocol | |||
There was a problem hiding this comment.
Review completed: no actionable issues identified in this PR.
| normalized := NormalizedRequest{} | ||
|
|
||
| requestID, idErr := normalizeJSONRPCID(request.ID) | ||
| normalized.ID = cloneJSONRawMessage(request.ID) |
There was a problem hiding this comment.
normalized.ID is copied from request.ID before normalizeJSONRPCID validation is checked. For invalid IDs (object/array/boolean/null), NormalizeJSONRPCRequest returns an error but still preserves the invalid ID, and dispatchRPCRequest then echoes that value in error.id. Per JSON-RPC 2.0, invalid request / invalid ID cases should return id: null when the request ID cannot be used. Suggest setting normalized.ID = nil when idErr != nil (or only assigning cloned ID after validation succeeds).
| normalized := NormalizedRequest{} | ||
|
|
||
| requestID, idErr := normalizeJSONRPCID(request.ID) | ||
| normalized.ID = cloneJSONRawMessage(request.ID) |
There was a problem hiding this comment.
normalized.ID is copied from the raw request before id validation. When id is present but invalid (e.g. object/array/bool), dispatchRPCRequest will echo that invalid id in the error response. In JSON-RPC 2.0, invalid/missing request ids should be returned as id: null for request-level errors. Consider only assigning normalized.ID after successful normalizeJSONRPCID, or forcing it to nil on idErr.
| _ = s.writeRPCResponse(conn, encoder, protocol.NewJSONRPCErrorResponse( | ||
| nil, | ||
| protocol.NewJSONRPCError( | ||
| protocol.JSONRPCCodeInvalidParams, |
There was a problem hiding this comment.
Oversized frame is classified as -32602 (Invalid params), but this failure happens before method/params parsing and is a request framing/protocol error. -32600 (Invalid Request) is a better fit (or a consistent parse-error policy). Current mapping can mislead clients and weakens error semantics for transport-level failures.
|
|
||
| response := s.dispatchFrame(ctx, frame, runtimePort) | ||
| if !s.writeFrame(conn, encoder, response) { | ||
| rpcResponse := s.dispatchRPCRequest(ctx, rpcRequest, runtimePort) |
There was a problem hiding this comment.
Review completed: no issues identified in this change set.
| normalized := NormalizedRequest{} | ||
|
|
||
| requestID, idErr := normalizeJSONRPCID(request.ID) | ||
| normalized.ID = cloneJSONRawMessage(request.ID) |
There was a problem hiding this comment.
When id validation fails, normalized.ID currently echoes the original invalid id into the error response. For JSON-RPC invalid request/id cases, the response id should be null to avoid correlating with an invalid identifier. Consider setting normalized.ID = nil when normalizeJSONRPCID returns an error.
|
/simplify |
|
已完成 处理结果
未完成项:无。 |
Generated with [codeagent](https://github.com/qbox/codeagent) Co-authored-by: pionxe <148670367+pionxe@users.noreply.github.com>
🎯 目标 (Motivation & Context)
本 PR 落地了网关重构计划的第三步 [EPIC-GW-03]。 其核心目标是将本地 IPC 控制面的通信协议从前期的“裸
MessageFrame直传”正式升级为 标准 JSON-RPC 2.0 协议。通过实现“外层 JSON-RPC 壳,内层 MessageFrame 语义”的归一化架构,我们彻底硬化了错误模型和数据契约,大幅降低了未来接入大模型 Runtime 和外部前端的改造成本。💡 架构决策提示: 本期采用了直接切换 (Hard Cutover) 策略,不保留对旧版 MessageFrame 字节流的双栈兼容。因
gateway和url-dispatch均打包在同一单体二进制内同频升级,此举有效避免了技术债务的产生。✨ 主要变更 (Key Changes)
1. JSON-RPC 协议归一化 (
internal/gateway/protocol)JSONRPCRequest,JSONRPCResponse,JSONRPCError)。params定义为json.RawMessage,在确定 Method 后再精准反序列化(如WakeIntent),提升了路由灵活性。result字段直接封装完整的MessageFrame对象,最大程度复用现有 Handler 逻辑。2. 网关服务与错误模型硬化 (
internal/gateway/server.go)NormalizeRPCRequest-> 内部MessageFrame分发。-32700,-32601),而业务层错误标识则被安全地放置在error.data.gateway_code中(如invalid_action,missing_required_field)。3. URL 派发器升级与健壮性修复 (
internal/gateway/adapters/urlscheme)url-dispatch发送方同步切换为 JSON-RPC 封包。id或action错配的幽灵响应。4. 安全漏洞修复 (
internal/gateway/handlers)/...等特殊绝对路径的越界识别边界问题。✅ 验收标准 (Acceptance Criteria)
gateway.ping和wake.openUrl等底层链路全面通过 JSON-RPC 2.0 归一化层。error.code+gateway_code)。Closes #300