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