github.com/v2fly/tools@v0.100.0/internal/jsonrpc2/wire.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package jsonrpc2 6 7 import ( 8 "encoding/json" 9 "fmt" 10 ) 11 12 // this file contains the go forms of the wire specification 13 // see http://www.jsonrpc.org/specification for details 14 15 var ( 16 // ErrUnknown should be used for all non coded errors. 17 ErrUnknown = NewError(-32001, "JSON RPC unknown error") 18 // ErrParse is used when invalid JSON was received by the server. 19 ErrParse = NewError(-32700, "JSON RPC parse error") 20 //ErrInvalidRequest is used when the JSON sent is not a valid Request object. 21 ErrInvalidRequest = NewError(-32600, "JSON RPC invalid request") 22 // ErrMethodNotFound should be returned by the handler when the method does 23 // not exist / is not available. 24 ErrMethodNotFound = NewError(-32601, "JSON RPC method not found") 25 // ErrInvalidParams should be returned by the handler when method 26 // parameter(s) were invalid. 27 ErrInvalidParams = NewError(-32602, "JSON RPC invalid params") 28 // ErrInternal is not currently returned but defined for completeness. 29 ErrInternal = NewError(-32603, "JSON RPC internal error") 30 31 //ErrServerOverloaded is returned when a message was refused due to a 32 //server being temporarily unable to accept any new messages. 33 ErrServerOverloaded = NewError(-32000, "JSON RPC overloaded") 34 ) 35 36 // wireRequest is sent to a server to represent a Call or Notify operaton. 37 type wireRequest struct { 38 // VersionTag is always encoded as the string "2.0" 39 VersionTag wireVersionTag `json:"jsonrpc"` 40 // Method is a string containing the method name to invoke. 41 Method string `json:"method"` 42 // Params is either a struct or an array with the parameters of the method. 43 Params *json.RawMessage `json:"params,omitempty"` 44 // The id of this request, used to tie the Response back to the request. 45 // Will be either a string or a number. If not set, the Request is a notify, 46 // and no response is possible. 47 ID *ID `json:"id,omitempty"` 48 } 49 50 // WireResponse is a reply to a Request. 51 // It will always have the ID field set to tie it back to a request, and will 52 // have either the Result or Error fields set depending on whether it is a 53 // success or failure response. 54 type wireResponse struct { 55 // VersionTag is always encoded as the string "2.0" 56 VersionTag wireVersionTag `json:"jsonrpc"` 57 // Result is the response value, and is required on success. 58 Result *json.RawMessage `json:"result,omitempty"` 59 // Error is a structured error response if the call fails. 60 Error *wireError `json:"error,omitempty"` 61 // ID must be set and is the identifier of the Request this is a response to. 62 ID *ID `json:"id,omitempty"` 63 } 64 65 // wireCombined has all the fields of both Request and Response. 66 // We can decode this and then work out which it is. 67 type wireCombined struct { 68 VersionTag wireVersionTag `json:"jsonrpc"` 69 ID *ID `json:"id,omitempty"` 70 Method string `json:"method"` 71 Params *json.RawMessage `json:"params,omitempty"` 72 Result *json.RawMessage `json:"result,omitempty"` 73 Error *wireError `json:"error,omitempty"` 74 } 75 76 // wireError represents a structured error in a Response. 77 type wireError struct { 78 // Code is an error code indicating the type of failure. 79 Code int64 `json:"code"` 80 // Message is a short description of the error. 81 Message string `json:"message"` 82 // Data is optional structured data containing additional information about the error. 83 Data *json.RawMessage `json:"data,omitempty"` 84 } 85 86 // wireVersionTag is a special 0 sized struct that encodes as the jsonrpc version 87 // tag. 88 // It will fail during decode if it is not the correct version tag in the 89 // stream. 90 type wireVersionTag struct{} 91 92 // ID is a Request identifier. 93 type ID struct { 94 name string 95 number int64 96 } 97 98 func NewError(code int64, message string) error { 99 return &wireError{ 100 Code: code, 101 Message: message, 102 } 103 } 104 105 func (err *wireError) Error() string { 106 return err.Message 107 } 108 109 func (wireVersionTag) MarshalJSON() ([]byte, error) { 110 return json.Marshal("2.0") 111 } 112 113 func (wireVersionTag) UnmarshalJSON(data []byte) error { 114 version := "" 115 if err := json.Unmarshal(data, &version); err != nil { 116 return err 117 } 118 if version != "2.0" { 119 return fmt.Errorf("invalid RPC version %v", version) 120 } 121 return nil 122 } 123 124 // NewIntID returns a new numerical request ID. 125 func NewIntID(v int64) ID { return ID{number: v} } 126 127 // NewStringID returns a new string request ID. 128 func NewStringID(v string) ID { return ID{name: v} } 129 130 // Format writes the ID to the formatter. 131 // If the rune is q the representation is non ambiguous, 132 // string forms are quoted, number forms are preceded by a # 133 func (id ID) Format(f fmt.State, r rune) { 134 numF, strF := `%d`, `%s` 135 if r == 'q' { 136 numF, strF = `#%d`, `%q` 137 } 138 switch { 139 case id.name != "": 140 fmt.Fprintf(f, strF, id.name) 141 default: 142 fmt.Fprintf(f, numF, id.number) 143 } 144 } 145 146 func (id *ID) MarshalJSON() ([]byte, error) { 147 if id.name != "" { 148 return json.Marshal(id.name) 149 } 150 return json.Marshal(id.number) 151 } 152 153 func (id *ID) UnmarshalJSON(data []byte) error { 154 *id = ID{} 155 if err := json.Unmarshal(data, &id.number); err == nil { 156 return nil 157 } 158 return json.Unmarshal(data, &id.name) 159 }