5bc05fd0a718fcc0df2f9e34470d1bd3b0462cf2
[platform/upstream/gcc48.git] / libgo / go / net / rpc / jsonrpc / server.go
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, &params)
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 }