OSDN Git Service

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