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, &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  }