| // Copyright 2010 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package jsonrpc | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"errors" | 
 | 	"io" | 
 | 	"net/rpc" | 
 | 	"sync" | 
 | ) | 
 |  | 
 | var errMissingParams = errors.New("jsonrpc: request body missing params") | 
 |  | 
 | type serverCodec struct { | 
 | 	dec *json.Decoder // for reading JSON values | 
 | 	enc *json.Encoder // for writing JSON values | 
 | 	c   io.Closer | 
 |  | 
 | 	// temporary work space | 
 | 	req serverRequest | 
 |  | 
 | 	// JSON-RPC clients can use arbitrary json values as request IDs. | 
 | 	// Package rpc expects uint64 request IDs. | 
 | 	// We assign uint64 sequence numbers to incoming requests | 
 | 	// but save the original request ID in the pending map. | 
 | 	// When rpc responds, we use the sequence number in | 
 | 	// the response to find the original request ID. | 
 | 	mutex   sync.Mutex // protects seq, pending | 
 | 	seq     uint64 | 
 | 	pending map[uint64]*json.RawMessage | 
 | } | 
 |  | 
 | // NewServerCodec returns a new rpc.ServerCodec using JSON-RPC on conn. | 
 | func NewServerCodec(conn io.ReadWriteCloser) rpc.ServerCodec { | 
 | 	return &serverCodec{ | 
 | 		dec:     json.NewDecoder(conn), | 
 | 		enc:     json.NewEncoder(conn), | 
 | 		c:       conn, | 
 | 		pending: make(map[uint64]*json.RawMessage), | 
 | 	} | 
 | } | 
 |  | 
 | type serverRequest struct { | 
 | 	Method string           `json:"method"` | 
 | 	Params *json.RawMessage `json:"params"` | 
 | 	Id     *json.RawMessage `json:"id"` | 
 | } | 
 |  | 
 | func (r *serverRequest) reset() { | 
 | 	r.Method = "" | 
 | 	r.Params = nil | 
 | 	r.Id = nil | 
 | } | 
 |  | 
 | type serverResponse struct { | 
 | 	Id     *json.RawMessage `json:"id"` | 
 | 	Result interface{}      `json:"result"` | 
 | 	Error  interface{}      `json:"error"` | 
 | } | 
 |  | 
 | func (c *serverCodec) ReadRequestHeader(r *rpc.Request) error { | 
 | 	c.req.reset() | 
 | 	if err := c.dec.Decode(&c.req); err != nil { | 
 | 		return err | 
 | 	} | 
 | 	r.ServiceMethod = c.req.Method | 
 |  | 
 | 	// JSON request id can be any JSON value; | 
 | 	// RPC package expects uint64.  Translate to | 
 | 	// internal uint64 and save JSON on the side. | 
 | 	c.mutex.Lock() | 
 | 	c.seq++ | 
 | 	c.pending[c.seq] = c.req.Id | 
 | 	c.req.Id = nil | 
 | 	r.Seq = c.seq | 
 | 	c.mutex.Unlock() | 
 |  | 
 | 	return nil | 
 | } | 
 |  | 
 | func (c *serverCodec) ReadRequestBody(x interface{}) error { | 
 | 	if x == nil { | 
 | 		return nil | 
 | 	} | 
 | 	if c.req.Params == nil { | 
 | 		return errMissingParams | 
 | 	} | 
 | 	// JSON params is array value. | 
 | 	// RPC params is struct. | 
 | 	// Unmarshal into array containing struct for now. | 
 | 	// Should think about making RPC more general. | 
 | 	var params [1]interface{} | 
 | 	params[0] = x | 
 | 	return json.Unmarshal(*c.req.Params, ¶ms) | 
 | } | 
 |  | 
 | var null = json.RawMessage([]byte("null")) | 
 |  | 
 | func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error { | 
 | 	c.mutex.Lock() | 
 | 	b, ok := c.pending[r.Seq] | 
 | 	if !ok { | 
 | 		c.mutex.Unlock() | 
 | 		return errors.New("invalid sequence number in response") | 
 | 	} | 
 | 	delete(c.pending, r.Seq) | 
 | 	c.mutex.Unlock() | 
 |  | 
 | 	if b == nil { | 
 | 		// Invalid request so no id. Use JSON null. | 
 | 		b = &null | 
 | 	} | 
 | 	resp := serverResponse{Id: b} | 
 | 	if r.Error == "" { | 
 | 		resp.Result = x | 
 | 	} else { | 
 | 		resp.Error = r.Error | 
 | 	} | 
 | 	return c.enc.Encode(resp) | 
 | } | 
 |  | 
 | func (c *serverCodec) Close() error { | 
 | 	return c.c.Close() | 
 | } | 
 |  | 
 | // ServeConn runs the JSON-RPC server on a single connection. | 
 | // ServeConn blocks, serving the connection until the client hangs up. | 
 | // The caller typically invokes ServeConn in a go statement. | 
 | func ServeConn(conn io.ReadWriteCloser) { | 
 | 	rpc.ServeCodec(NewServerCodec(conn)) | 
 | } |