OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [rpc/] [jsonrpc/] [server.go] - Rev 747

Compare with Previous | Blame | View Log

// 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"
)

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
        resp serverResponse

        // 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 = ""
        if r.Params != nil {
                *r.Params = (*r.Params)[0:0]
        }
        if r.Id != nil {
                *r.Id = (*r.Id)[0:0]
        }
}

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
        }
        // 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, &params)
}

var null = json.RawMessage([]byte("null"))

func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) error {
        var resp serverResponse
        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.Id = b
        resp.Result = x
        if r.Error == "" {
                resp.Error = nil
        } 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))
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.