|
|
@@ -5,99 +5,191 @@ package jsonrpc2
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
+ "errors"
|
|
|
"fmt"
|
|
|
)
|
|
|
|
|
|
-type ErrorCode int
|
|
|
+type ErrCode int
|
|
|
|
|
|
const (
|
|
|
- ErrParse ErrorCode = -32700 // 解析错误: "Parse error"
|
|
|
- ErrInvalidRequest ErrorCode = -32600 // 无效请求: "Invalid request"
|
|
|
- ErrMethodNotFound ErrorCode = -32601 // 无效方法: "Method not found"
|
|
|
- ErrInvalidParams ErrorCode = -32602 // 无效参数: "Invalid params"
|
|
|
- ErrInternal ErrorCode = -32603 // 内部错误: "Internal error"
|
|
|
+ ErrParse ErrCode = -32700 // 解析错误: "Parse error"
|
|
|
+ ErrInvalidRequest ErrCode = -32600 // 无效请求: "Invalid request"
|
|
|
+ ErrMethodNotFound ErrCode = -32601 // 无效方法: "Method not found"
|
|
|
+ ErrInvalidParams ErrCode = -32602 // 无效参数: "Invalid params"
|
|
|
+ ErrInternal ErrCode = -32603 // 内部错误: "Internal error"
|
|
|
)
|
|
|
|
|
|
-type Request struct {
|
|
|
- JSONRPC string `json:"jsonrpc"` // 版本号, 固定: "2.0"
|
|
|
- Method string `json:"method"` // 调用方法, 执行函数名
|
|
|
- Params json.RawMessage `json:"params,omitempty"` // 请求参数, 可选可为空
|
|
|
- ID int `json:"id"` // 请求ID, 用于标识请求
|
|
|
-}
|
|
|
-
|
|
|
type Error struct {
|
|
|
- Code ErrorCode `json:"code"` // 错误码
|
|
|
- Message string `json:"message"` // 错误信息
|
|
|
+ Code ErrCode `json:"code"` //// 错误码
|
|
|
+ Message string `json:"message"` //// 错误信息
|
|
|
}
|
|
|
|
|
|
func (e Error) Error() string {
|
|
|
return e.Message
|
|
|
}
|
|
|
|
|
|
+type Request struct {
|
|
|
+ JSONRPC string `json:"jsonrpc"` // 版本号, 固定: "2.0"
|
|
|
+ Method string `json:"method"` // 调用方法, 执行函数名
|
|
|
+ Params json.RawMessage `json:"params,omitempty"` // 请求参数, 可选可为空
|
|
|
+ ID *int `json:"id,omitempty"` // 请求ID, 用于标识请求
|
|
|
+}
|
|
|
+
|
|
|
type Response struct {
|
|
|
JSONRPC string `json:"jsonrpc"` // 版本号, 固定: "2.0"
|
|
|
Result json.RawMessage `json:"result,omitempty"` // 响应结果, 可选可为空
|
|
|
Error *Error `json:"error,omitempty"` // 错误信息, 可选可为空
|
|
|
- ID int `json:"id"` // 应答ID, 响应匹配请求
|
|
|
+ ID *int `json:"id"` // 应答ID, 响应匹配请求
|
|
|
}
|
|
|
|
|
|
// 解析请求数据
|
|
|
-func ParseRequest(jsonStr string) (*Request, error) {
|
|
|
+func ParseRequest(input any) (*Request, error) {
|
|
|
+ var raw []byte
|
|
|
+
|
|
|
+ switch v := input.(type) {
|
|
|
+ case nil:
|
|
|
+ return nil, errors.New("input is nil")
|
|
|
+ case string:
|
|
|
+ raw = []byte(v)
|
|
|
+ case []byte:
|
|
|
+ raw = v
|
|
|
+ default:
|
|
|
+ return nil, errors.New("unsupported input type: must be string or []byte")
|
|
|
+ }
|
|
|
+
|
|
|
var req Request
|
|
|
- if err := json.Unmarshal([]byte(jsonStr), &req); err != nil {
|
|
|
- return nil, err
|
|
|
+ if err := json.Unmarshal(raw, &req); err != nil {
|
|
|
+ return nil, fmt.Errorf("unmarshal request: %w", err)
|
|
|
}
|
|
|
+
|
|
|
return &req, nil
|
|
|
}
|
|
|
|
|
|
-// 构建响应数据
|
|
|
-func BuildResult(id int, result any) (*Response, error) {
|
|
|
- b, err := json.Marshal(result)
|
|
|
+// 编码JSON数据
|
|
|
+func marshalJSON(input any) (json.RawMessage, error) {
|
|
|
+ switch v := input.(type) {
|
|
|
+ case nil:
|
|
|
+ return nil, nil
|
|
|
+ case []byte:
|
|
|
+ return nil, errors.New("[]byte is not allowed: use json.RawMessage for raw JSON")
|
|
|
+ case json.RawMessage:
|
|
|
+ return v, nil
|
|
|
+ default:
|
|
|
+ b, err := json.Marshal(v)
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("marshal json: %w", err)
|
|
|
+ }
|
|
|
+ return json.RawMessage(b), nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 构建一个请求
|
|
|
+func BuildRequest(method string, params any, id int) (*Request, error) {
|
|
|
+ if method == "" {
|
|
|
+ return nil, errors.New("method must be non-empty")
|
|
|
+ }
|
|
|
+
|
|
|
+ raw, err := marshalJSON(params)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return &Response{
|
|
|
+
|
|
|
+ req := &Request{
|
|
|
JSONRPC: "2.0",
|
|
|
- Result: b,
|
|
|
- ID: id,
|
|
|
- }, nil
|
|
|
+ Method: method,
|
|
|
+ ID: &id,
|
|
|
+ }
|
|
|
+
|
|
|
+ if raw != nil { // 非空参数
|
|
|
+ req.Params = raw
|
|
|
+ }
|
|
|
+
|
|
|
+ return req, nil
|
|
|
}
|
|
|
|
|
|
-// 构建错误响应
|
|
|
-func BuildError(id int, code ErrorCode, message string) *Response {
|
|
|
- return &Response{
|
|
|
+// 构建一个通知
|
|
|
+func BuildNotification(method string, params any) (*Request, error) {
|
|
|
+ if method == "" {
|
|
|
+ return nil, errors.New("method must be non-empty")
|
|
|
+ }
|
|
|
+
|
|
|
+ raw, err := marshalJSON(params)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ req := &Request{
|
|
|
JSONRPC: "2.0",
|
|
|
- Error: &Error{
|
|
|
- Code: code,
|
|
|
- Message: message,
|
|
|
- },
|
|
|
- ID: id,
|
|
|
+ Method: method,
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-// 构建解析错误
|
|
|
-func BuildParseError(id int) *Response {
|
|
|
- return BuildError(id, ErrParse, "Parse error")
|
|
|
-}
|
|
|
+ if raw != nil { // 非空参数
|
|
|
+ req.Params = raw
|
|
|
+ }
|
|
|
|
|
|
-// 构建无效请求
|
|
|
-func BuildInvalidRequest(id int) *Response {
|
|
|
- return BuildError(id, ErrInvalidRequest, "Invalid request")
|
|
|
+ return req, nil
|
|
|
}
|
|
|
|
|
|
-// 构建无效方法
|
|
|
-func BuildMethodNotFound(id int) *Response {
|
|
|
- return BuildError(id, ErrMethodNotFound, "Method not found")
|
|
|
+// 构建成功应答
|
|
|
+func BuildResult(req *Request, result any) (*Response, error) {
|
|
|
+ if req.ID == nil { // 通知类型, 不用应答
|
|
|
+ return nil, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ raw, err := marshalJSON(result)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ if raw == nil {
|
|
|
+ raw = json.RawMessage("null")
|
|
|
+ }
|
|
|
+
|
|
|
+ return &Response{
|
|
|
+ JSONRPC: "2.0",
|
|
|
+ Result: raw,
|
|
|
+ ID: req.ID,
|
|
|
+ }, nil
|
|
|
}
|
|
|
|
|
|
-// 构建无效参数
|
|
|
-func BuildInvalidParams(id int) *Response {
|
|
|
- return BuildError(id, ErrInvalidParams, "Invalid params")
|
|
|
+// 构建错误应答
|
|
|
+func BuildError(req *Request, code ErrCode, message string) *Response {
|
|
|
+ if req.ID == nil { // 通知类型, 不用应答
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ wmsg := message
|
|
|
+
|
|
|
+ switch code {
|
|
|
+ case ErrParse:
|
|
|
+ wmsg = "解析错误"
|
|
|
+ case ErrInvalidRequest:
|
|
|
+ wmsg = "无效请求"
|
|
|
+ case ErrMethodNotFound:
|
|
|
+ wmsg = "无效调用"
|
|
|
+ case ErrInvalidParams:
|
|
|
+ wmsg = "无效参数"
|
|
|
+ case ErrInternal:
|
|
|
+ wmsg = "内部错误"
|
|
|
+ }
|
|
|
+
|
|
|
+ return &Response{
|
|
|
+ JSONRPC: "2.0",
|
|
|
+ Error: &Error{
|
|
|
+ Code: code,
|
|
|
+ Message: wmsg,
|
|
|
+ },
|
|
|
+ ID: req.ID,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// 构建内部错误
|
|
|
-func BuildInternalError(id int) *Response {
|
|
|
- return BuildError(id, ErrInternal, "Internal error")
|
|
|
+// 请求转字符串
|
|
|
+func (req *Request) String() (string, error) {
|
|
|
+ b, err := json.Marshal(req)
|
|
|
+ if err != nil {
|
|
|
+ return "", fmt.Errorf("marshal request: %w", err)
|
|
|
+ }
|
|
|
+ return string(b), nil
|
|
|
}
|
|
|
|
|
|
// 应答转字符串
|