// Author: NiuJiuRu // Email: niujiuru@qq.com package jsonrpc2 import ( "encoding/json" "errors" "fmt" ) type ErrCode int const ( 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 Error struct { Code ErrCode `json:"code"` //// 错误码 Message string `json:"message"` //// 错误信息 } func (e Error) Error() string { return e.Message } var errMessages = map[ErrCode]string{ ErrParse: "Parse error", // 解析错误 ErrInvalidRequest: "Invalid request", // 无效请求 ErrMethodNotFound: "Method not found", // 无效方法 ErrInvalidParams: "Invalid params", // 无效参数 ErrInternal: "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,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, 响应匹配请求 } // 解析请求数据 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(raw, &req); err != nil { return nil, fmt.Errorf("unmarshal request: %w", err) } if req.JSONRPC != "2.0" { return nil, errors.New(`"jsonrpc" must be "2.0"`) } if req.Method == "" { return nil, errors.New("method must be non-empty") } return &req, nil } // 解析应答数据 func ParseResponse(input any) (*Response, 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 resp Response if err := json.Unmarshal(raw, &resp); err != nil { return nil, fmt.Errorf("unmarshal response: %w", err) } if resp.JSONRPC != "2.0" { return nil, errors.New(`"jsonrpc" must be "2.0"`) } // 情况 1:result 和 error 同时为空 → 错误 if resp.Error == nil && resp.Result == nil { return nil, errors.New(`response must contain either "result" or "error" field`) } // 情况 2:result 和 error 同时存在 → 错误 if resp.Error != nil && resp.Result != nil { return nil, errors.New(`response can't contain both "result" and "error" field`) } // 情况 3:成功时的应答 → 必须有id&且不能空 if resp.Result != nil { if resp.ID == nil { return nil, errors.New(`"id" must exist and cannot be null for successful response`) } return &resp, nil } // 情况 4:错误时的应答 → 必须有id&且不能空 if resp.Error.Code == ErrParse { // 特例: Parse error (-32700)时 return &resp, nil } if resp.ID == nil { return nil, errors.New(`"id" must exist and cannot be null for error response`) } return &resp, nil } // 编码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 } var rid int if len(id) > 0 { rid = id[0] } else { rid = nextID() } req := &Request{ JSONRPC: "2.0", Method: method, ID: &rid, } if raw != nil { // 非空参数 req.Params = raw } return req, nil } // 构建一个通知 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", Method: method, } if raw != nil { // 非空参数 req.Params = raw } return req, nil } // 构建成功应答 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 BuildError(req *Request, code ErrCode, message string) *Response { id := (*int)(nil) if req != nil { id = req.ID } emsg := message if emsg == "" { emsg = errMessages[code] } return &Response{ JSONRPC: "2.0", Error: &Error{ Code: code, Message: emsg, }, ID: id, } } // 请求转字符串 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 } // 应答转字符串 func (resp *Response) String() (string, error) { b, err := json.Marshal(resp) if err != nil { return "", fmt.Errorf("marshal response: %w", err) } return string(b), nil }