package json import ( "encoding/json" "strings" "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(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{req: req, err: err}, nil } // ServerRequestCodec decodes and encodes a single request. type ServerRequestCodec struct { 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.SetValueWithJSONStringArray(*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) NewResponse(reply interface{}, err error) ([]byte, error) { res := src.newServerResponse(reply, err) return json.Marshal(res) } func (src *ServerRequestCodec) NewResponseWithString(reply string, err error) ([]byte, error) { res := src.newServerResponse(nil, err) r := strings.TrimSpace(reply) if nil == err && "" != r { var i interface{} mErr := json.Unmarshal([]byte(r), &i) if nil != mErr { return nil, mErr } res.Result = i } return json.Marshal(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 }