github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/net/rpc/jsonrpc/server.go (about) 1 // Copyright 2010 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 jsonrpc 6 7 import ( 8 "encoding/json" 9 "errors" 10 "io" 11 "net/rpc" 12 "sync" 13 ) 14 15 var errMissingParams = errors.New("jsonrpc: request body missing params") 16 17 type serverCodec struct { 18 dec *json.Decoder // for reading JSON values 19 enc *json.Encoder // for writing JSON values 20 c io.Closer 21 22 // temporary work space 23 req serverRequest 24 25 // JSON-RPC clients can use arbitrary json values as request IDs. 26 // Package rpc expects uint64 request IDs. 27 // We assign uint64 sequence numbers to incoming requests 28 // but save the original request ID in the pending map. 29 // When rpc responds, we use the sequence number in 30 // the response to find the original request ID. 31 mutex sync.Mutex // protects seq, pending 32 seq uint64 33 pending map[uint64]*json.RawMessage 34 } 35 36 // NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn. 37 func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec { 38 return &serverCodec{ 39 dec: json.NewDecoder(conn), 40 enc: json.NewEncoder(conn), 41 c: conn, 42 pending: make(map[uint64]*json.RawMessage), 43 } 44 } 45 46 type serverRequest struct { 47 Method string `json:"method"` 48 Params *json.RawMessage `json:"params"` 49 Id *json.RawMessage `json:"id"` 50 } 51 52 func (r *serverRequest) reset() { 53 r.Method = "" 54 r.Params = nil 55 r.Id = nil 56 } 57 58 type serverResponse struct { 59 Id *json.RawMessage `json:"id"` 60 Result interface{} `json:"result"` 61 Error interface{} `json:"error"` 62 } 63 64 func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error { 65 c.req.reset() 66 if err := c.dec.Decode(&c.req); err != nil { 67 return err 68 } 69 r.ServiceMethod = c.req.Method 70 71 // JSON request id can be any JSON value; 72 // RPC package expects uint64. Translate to 73 // internal uint64 and save JSON on the side. 74 c.mutex.Lock() 75 c.seq++ 76 c.pending[c.seq] = c.req.Id 77 c.req.Id = nil 78 r.Seq = c.seq 79 c.mutex.Unlock() 80 81 return nil 82 } 83 84 func (c *serverCodec) ReadRequestBody(x interface{}) error { 85 if x == nil { 86 return nil 87 } 88 if c.req.Params == nil { 89 return errMissingParams 90 } 91 // JSON params is array value. 92 // RPC params is struct. 93 // Unmarshal into array containing struct for now. 94 // Should think about making RPC more general. 95 var params [1]interface{} 96 params[0] = x 97 return json.Unmarshal(*c.req.Params, ¶ms) 98 } 99 100 var null = json.RawMessage([]byte("null")) 101 102 func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error { 103 c.mutex.Lock() 104 b, ok := c.pending[r.Seq] 105 if !ok { 106 c.mutex.Unlock() 107 return errors.New("invalid sequence number in response") 108 } 109 delete(c.pending, r.Seq) 110 c.mutex.Unlock() 111 112 if b == nil { 113 // Invalid request so no id. Use JSON null. 114 b = &null 115 } 116 resp := serverResponse{Id: b} 117 if r.Error == "" { 118 resp.Result = x 119 } else { 120 resp.Error = r.Error 121 } 122 return c.enc.Encode(resp) 123 } 124 125 func (c *serverCodec) Close() error { 126 return c.c.Close() 127 } 128 129 // ServeConn runs the JSON-RPC server on a single connection. 130 // ServeConn blocks, serving the connection until the client hangs up. 131 // The caller typically invokes ServeConn in a go statement. 132 func ServeConn(conn io.ReadWriteCloser) { 133 rpc.ServeCodec(NewServerCodec(conn)) 134 }