// 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) } 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.Error == nil && resp.Result == nil { return nil, errors.New(`response must contain either "result" or "error" field`) } if resp.Error != nil && resp.Result != nil { return nil, errors.New(`response can't contain both "result" and "error" field`) } if resp.Error != nil && resp.ID == nil && resp.Error.Code != ErrParse { return nil, errors.New(`"error" must contain an "id" field`) } if resp.Result != nil && resp.ID == nil { return nil, errors.New(`"result" must contain an "id" field`) } 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 } req := &Request{ JSONRPC: "2.0", Method: method, ID: &id, } 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 code != ErrParse && req != nil && req.ID != nil { id = req.ID } emsg, ok := errMessages[code] if !ok { emsg = message } 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 }