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 inteface 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 handler Handler 72 decoder *json.Decoder 73 74 encoder *json.Encoder 75 writer io.Writer 76 } 77 78 // New creates a new Server connection 79 func New(conn io.ReadWriter, handler Handler) *Server { 80 return &Server{ 81 handler: handler, 82 decoder: json.NewDecoder(conn), 83 encoder: json.NewEncoder(conn), 84 writer: conn, 85 } 86 } 87 88 // Handle starts the server's handling loop. 89 // 90 // The func will return only when it encounters a read error, be it from a 91 // closed connection, or from some fault on the wire. 92 func (s *Server) Handle() error { 93 for { 94 var req request 95 if err := s.decoder.Decode(&req); err != nil { 96 return fmt.Errorf("error decoding JSON request: %w", err) 97 } 98 go s.handleRequest(req) 99 } 100 } 101 102 func (s *Server) handleRequest(req request) error { 103 result, err := s.handler.HandleRPC(req.Method, req.Params) 104 return s.send(req.ID, result, err) 105 } 106 107 // Send sends the encoded Response to the client 108 func (s *Server) Send(resp Response) error { 109 return s.encoder.Encode(resp) 110 } 111 112 const ( 113 jsonHead = "{\"id\":" 114 jsonMid = ",\"result\":" 115 jsonErr = ",\"error\":" 116 jsonTail = '}' 117 ) 118 119 var jsonNil = json.RawMessage{'n', 'u', 'l', 'l'} 120 121 func (s *Server) send(id json.RawMessage, data any, e error) error { 122 var ( 123 err error 124 rm json.RawMessage 125 ok bool 126 ) 127 mid := jsonMid 128 if e != nil { 129 if errr, ok := e.(*Error); ok { 130 rm, err = json.Marshal(errr) 131 } else { 132 rm, err = json.Marshal(Error{ 133 Message: e.Error(), 134 Data: e, 135 }) 136 } 137 mid = jsonErr 138 } else if data == nil { 139 rm = jsonNil 140 } else { 141 rm, ok = data.(json.RawMessage) 142 if !ok { 143 rm, err = json.Marshal(data) 144 } else if len(rm) == 0 { 145 rm = jsonNil 146 } 147 } 148 if err != nil { 149 return fmt.Errorf("error marshaling JSON: %w", err) 150 } 151 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 { 152 return fmt.Errorf("error writing to socket: %w", err) 153 } 154 return nil 155 } 156 157 // SendData sends the raw bytes (unencoded) to the client 158 func (s *Server) SendData(data json.RawMessage) error { 159 if _, err := s.writer.Write(data); err != nil { 160 return fmt.Errorf("error sending data: %w", err) 161 } 162 return nil 163 } 164