174 lines
4.8 KiB
Go
174 lines
4.8 KiB
Go
package json
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
|
|
"git.loafle.net/commons/rpc-go/codec"
|
|
"git.loafle.net/commons/rpc-go/protocol"
|
|
cuej "git.loafle.net/commons/util-go/encoding/json"
|
|
)
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Request
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// serverRequest represents a JSON-RPC request received by the server.
|
|
type serverRequest struct {
|
|
// JSON-RPC protocol.
|
|
Version string `json:"jsonrpc"`
|
|
|
|
// A String containing the name of the method to be invoked.
|
|
Method string `json:"method"`
|
|
|
|
// A Structured value to pass as arguments to the method.
|
|
Params *json.RawMessage `json:"params,omitempty"`
|
|
|
|
// The request id. MUST be a string, number or null.
|
|
// Our implementation will not do type checking for id.
|
|
// It will be copied as it is.
|
|
ID *json.RawMessage `json:"id,omitempty"`
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ServerRequestCodec
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// newRequestCodec returns a new ServerRequestCodec.
|
|
func newServerRequestCodec(codecSelector codec.CodecSelector, buf []byte) (protocol.ServerRequestCodec, error) {
|
|
|
|
req := &serverRequest{}
|
|
err := json.Unmarshal(buf, req)
|
|
|
|
if err != nil {
|
|
err = &protocol.Error{
|
|
Code: protocol.E_PARSE,
|
|
Message: err.Error(),
|
|
Data: req,
|
|
}
|
|
}
|
|
|
|
if req.Version != Version {
|
|
err = &protocol.Error{
|
|
Code: protocol.E_INVALID_REQ,
|
|
Message: "jsonrpc must be " + Version,
|
|
Data: req,
|
|
}
|
|
}
|
|
|
|
return &ServerRequestCodec{codecSelector: codecSelector, req: req, err: err}, nil
|
|
}
|
|
|
|
// ServerRequestCodec decodes and encodes a single request.
|
|
type ServerRequestCodec struct {
|
|
codecSelector codec.CodecSelector
|
|
req *serverRequest
|
|
err error
|
|
}
|
|
|
|
func (src *ServerRequestCodec) HasResponse() bool {
|
|
return src.req.ID != nil
|
|
}
|
|
|
|
// Method returns the RPC method for the current request.
|
|
//
|
|
// The method uses a dotted notation as in "Service.Method".
|
|
func (src *ServerRequestCodec) Method() string {
|
|
return src.req.Method
|
|
}
|
|
|
|
// ReadRequest fills the request object for the RPC method.
|
|
//
|
|
// ReadRequest parses request parameters in two supported forms in
|
|
// accordance with http://www.jsonrpc.org/specification#parameter_structures
|
|
//
|
|
// by-position: params MUST be an Array, containing the
|
|
// values in the Server expected order.
|
|
//
|
|
// by-name: params MUST be an Object, with member names
|
|
// that match the Server expected parameter names. The
|
|
// absence of expected names MAY result in an error being
|
|
// generated. The names MUST match exactly, including
|
|
// case, to the method's expected parameters.
|
|
func (src *ServerRequestCodec) ReadParams(args []interface{}) error {
|
|
if src.err == nil && src.req.Params != nil {
|
|
// Note: if scr.request.Params is nil it's not an error, it's an optional member.
|
|
// JSON params structured object. Unmarshal to the args object.
|
|
if err := cuej.SetValueWithJSONStringArrayBytes(*src.req.Params, args); nil != err {
|
|
src.err = &protocol.Error{
|
|
Code: protocol.E_BAD_PARAMS,
|
|
Message: err.Error(),
|
|
Data: src.req.Params,
|
|
}
|
|
return src.err
|
|
}
|
|
return nil
|
|
}
|
|
return src.err
|
|
}
|
|
|
|
func (src *ServerRequestCodec) Params() ([]string, error) {
|
|
if src.err == nil && src.req.Params != nil {
|
|
var values []string
|
|
|
|
if err := json.Unmarshal(*src.req.Params, &values); err != nil {
|
|
src.err = &protocol.Error{
|
|
Code: protocol.E_BAD_PARAMS,
|
|
Message: err.Error(),
|
|
Data: src.req.Params,
|
|
}
|
|
return nil, src.err
|
|
}
|
|
|
|
return values, nil
|
|
}
|
|
return nil, src.err
|
|
}
|
|
|
|
func (src *ServerRequestCodec) encodeResponse(res *serverResponse) (messageType int, message []byte, err error) {
|
|
buf, err := json.Marshal(res)
|
|
if nil != err {
|
|
return 0, nil, err
|
|
}
|
|
|
|
return src.codecSelector.Encode(buf)
|
|
}
|
|
|
|
func (src *ServerRequestCodec) NewResponse(reply interface{}, replyErr error) (messageType int, message []byte, err error) {
|
|
res := src.newServerResponse(reply, replyErr)
|
|
return src.encodeResponse(res)
|
|
}
|
|
|
|
func (src *ServerRequestCodec) NewResponseWithString(reply string, replyErr error) (messageType int, message []byte, err error) {
|
|
res := src.newServerResponse(nil, replyErr)
|
|
|
|
r := strings.TrimSpace(reply)
|
|
if nil == err && "" != r {
|
|
var i interface{}
|
|
mErr := json.Unmarshal([]byte(r), &i)
|
|
if nil != mErr {
|
|
return 0, nil, mErr
|
|
}
|
|
|
|
res.Result = i
|
|
}
|
|
return src.encodeResponse(res)
|
|
}
|
|
|
|
func (src *ServerRequestCodec) newServerResponse(reply interface{}, err error) *serverResponse {
|
|
res := &serverResponse{Version: Version, Result: reply, ID: src.req.ID}
|
|
|
|
if nil != err {
|
|
jsonErr, ok := err.(*protocol.Error)
|
|
if !ok {
|
|
jsonErr = &protocol.Error{
|
|
Code: protocol.E_SERVER,
|
|
Message: err.Error(),
|
|
}
|
|
}
|
|
res.Error = jsonErr
|
|
}
|
|
|
|
return res
|
|
}
|