1 // Package jsonrpc implements simple JSON RPC client/server message handling systems. 2 package jsonrpc // import "vimagination.zapto.org/jsonrpc" 3 4 import ( 5 "encoding/json" 6 "fmt" 7 "io" 8 "reflect" 9 ) 10 11 type request struct { 12 Method string `json:"method"` 13 Params json.RawMessage `json:"params"` 14 ID json.RawMessage `json:"id"` 15 } 16 17 // Response represents a response to a client. 18 type Response struct { 19 ID int `json:"id"` 20 Result any `json:"result,omitempty"` 21 Error *Error `json:"error,omitempty"` 22 } 23 24 // Error represents the error type for RPC requests. 25 type Error struct { 26 Code int `json:"code"` 27 Message string `json:"message"` 28 Data any `json:"data,omitempty"` 29 } 30 31 func (e *Error) Is(target error) bool { 32 err, ok := target.(Error) 33 if ok { 34 return e.Is(&err) 35 } 36 37 errr, ok := target.(*Error) 38 if !ok { 39 return false 40 } 41 42 if (errr == nil) != (e == nil) { 43 return false 44 } 45 46 return errr.Code == e.Code && reflect.DeepEqual(errr.Data, e.Data) && errr.Message == e.Message 47 } 48 49 func (e Error) Error() string { 50 return e.Message 51 } 52 53 // Handler takes a method name and a JSON Raw Message byte slice and should 54 // return data OR an error, not both. 55 type Handler interface { 56 HandleRPC(method string, data json.RawMessage) (any, error) 57 } 58 59 // HandlerFunc is a convenience type to wrap a function for the Handler 60 // interface. 61 type HandlerFunc func(string, json.RawMessage) (any, error) 62 63 // HandleRPC implements the Handler interface. 64 func (r HandlerFunc) HandleRPC(method string, data json.RawMessage) (any, error) { 65 return r(method, data) 66 } 67 68 // Server represents a RPC server connection that will handle responses from a 69 // single client. 70 type Server struct { 71 decoder *json.Decoder 72 encoder *json.Encoder 73 74 serverHandler 75 } 76 77 type serverHandler struct { 78 handler Handler 79 writer io.Writer 80 } 81 82 // New creates a new Server connection. 83 func New(conn io.ReadWriter, handler Handler) *Server { 84 return &Server{ 85 decoder: json.NewDecoder(conn), 86 encoder: json.NewEncoder(conn), 87 serverHandler: serverHandler{ 88 handler: handler, 89 writer: conn, 90 }, 91 } 92 } 93 94 // Handle starts the server's handling loop. 95 // 96 // The func will return only when it encounters a read error, be it from a 97 // closed connection, or from some fault on the wire. 98 func (s *Server) Handle() error { 99 for { 100 var req request 101 102 if err := s.decoder.Decode(&req); err != nil { 103 return fmt.Errorf("error decoding JSON request: %w", err) 104 } 105 106 go s.handleRequest(req) 107 } 108 } 109 110 func (s *serverHandler) handleRequest(req request) error { 111 result, err := s.handler.HandleRPC(req.Method, req.Params) 112 113 return s.send(req.ID, result, err) 114 } 115 116 // Send sends the encoded Response to the client. 117 func (s *Server) Send(resp Response) error { 118 return s.encoder.Encode(resp) 119 } 120 121 const ( 122 jsonHead = "{\"id\":" 123 jsonMid = ",\"result\":" 124 jsonErr = ",\"error\":" 125 jsonTail = '}' 126 ) 127 128 var jsonNil = json.RawMessage{'n', 'u', 'l', 'l'} 129 130 func (s *serverHandler) send(id json.RawMessage, data any, e error) error { 131 var ( 132 err error 133 rm json.RawMessage 134 ok bool 135 ) 136 137 mid := jsonMid 138 139 if e != nil { 140 if errr, ok := e.(*Error); ok { 141 rm, err = json.Marshal(errr) 142 } else { 143 rm, err = json.Marshal(Error{Message: e.Error(), Data: e}) 144 } 145 146 mid = jsonErr 147 } else if data == nil { 148 rm = jsonNil 149 } else if rm, ok = data.(json.RawMessage); !ok { 150 rm, err = json.Marshal(data) 151 } else if len(rm) == 0 { 152 rm = jsonNil 153 } 154 155 if err != nil { 156 return fmt.Errorf("error marshalling JSON: %w", err) 157 } 158 159 if _, err = s.writer.Write(append(append(append(append(append(make([]byte, 0, len(jsonHead)+len(id)+len(mid)+len(rm)+1), jsonHead...), id...), mid...), rm...), jsonTail)); err != nil { 160 return fmt.Errorf("error writing to socket: %w", err) 161 } 162 163 return nil 164 } 165 166 // SendData sends the raw bytes (unencoded) to the client. 167 func (s *serverHandler) SendData(data json.RawMessage) error { 168 if _, err := s.writer.Write(data); err != nil { 169 return fmt.Errorf("error sending data: %w", err) 170 } 171 172 return nil 173 } 174