Просмотр исходного кода

优化修改jsonrpc2模块代码, 构建请求时允许不传入请求id, 内部自动生成

niujiuru 1 неделя назад
Родитель
Сommit
133c474825
2 измененных файлов с 57 добавлено и 10 удалено
  1. 21 0
      utils/jsonrpc2/id.go
  2. 36 10
      utils/jsonrpc2/rpc.go

+ 21 - 0
utils/jsonrpc2/id.go

@@ -0,0 +1,21 @@
+package jsonrpc2
+
+import (
+	"sync"
+)
+
+var (
+	idCounter int
+	idMu      sync.Mutex
+)
+
+func nextID() int {
+	idMu.Lock()
+	defer idMu.Unlock()
+
+	idCounter++
+	if idCounter < 0 {
+		idCounter = 1
+	}
+	return idCounter
+}

+ 36 - 10
utils/jsonrpc2/rpc.go

@@ -70,6 +70,10 @@ func ParseRequest(input any) (*Request, error) {
 		return nil, fmt.Errorf("unmarshal request: %w", err)
 		return nil, fmt.Errorf("unmarshal request: %w", err)
 	}
 	}
 
 
+	if req.JSONRPC != "2.0" {
+		return nil, errors.New(`"jsonrpc" must be "2.0"`)
+	}
+
 	return &req, nil
 	return &req, nil
 }
 }
 
 
@@ -93,20 +97,35 @@ func ParseResponse(input any) (*Response, error) {
 		return nil, fmt.Errorf("unmarshal response: %w", err)
 		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 {
 	if resp.Error == nil && resp.Result == nil {
 		return nil, errors.New(`response must contain either "result" or "error" field`)
 		return nil, errors.New(`response must contain either "result" or "error" field`)
 	}
 	}
 
 
+	// 情况 2:result 和 error 同时存在 → 错误
 	if resp.Error != nil && resp.Result != nil {
 	if resp.Error != nil && resp.Result != nil {
 		return nil, errors.New(`response can't contain both "result" and "error" field`)
 		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`)
+	// 情况 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
 	}
 	}
 
 
-	if resp.Result != nil && resp.ID == nil {
-		return nil, errors.New(`"result" must contain an "id" field`)
+	// 情况 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
 	return &resp, nil
@@ -131,7 +150,7 @@ func marshalJSON(input any) (json.RawMessage, error) {
 }
 }
 
 
 // 构建一个请求
 // 构建一个请求
-func BuildRequest(method string, params any, id int) (*Request, error) {
+func BuildRequest(method string, params any, id ...int) (*Request, error) {
 	if method == "" {
 	if method == "" {
 		return nil, errors.New("method must be non-empty")
 		return nil, errors.New("method must be non-empty")
 	}
 	}
@@ -141,10 +160,17 @@ func BuildRequest(method string, params any, id int) (*Request, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
+	var rid int
+	if len(id) > 0 {
+		rid = id[0]
+	} else {
+		rid = nextID()
+	}
+
 	req := &Request{
 	req := &Request{
 		JSONRPC: "2.0",
 		JSONRPC: "2.0",
 		Method:  method,
 		Method:  method,
-		ID:      &id,
+		ID:      &rid,
 	}
 	}
 
 
 	if raw != nil { // 非空参数
 	if raw != nil { // 非空参数
@@ -203,13 +229,13 @@ func BuildResult(req *Request, result any) (*Response, error) {
 func BuildError(req *Request, code ErrCode, message string) *Response {
 func BuildError(req *Request, code ErrCode, message string) *Response {
 	id := (*int)(nil)
 	id := (*int)(nil)
 
 
-	if code != ErrParse && req != nil && req.ID != nil {
+	if req != nil {
 		id = req.ID
 		id = req.ID
 	}
 	}
 
 
-	emsg, ok := errMessages[code]
-	if !ok {
-		emsg = message
+	emsg := message
+	if emsg == "" {
+		emsg = errMessages[code]
 	}
 	}
 
 
 	return &Response{
 	return &Response{