This commit is contained in:
crusader 2018-03-20 15:31:54 +09:00
parent efea9e8ca6
commit 96d9105d30
19 changed files with 107 additions and 74 deletions

View File

@ -5,7 +5,7 @@ import "git.loafle.net/commons_go/rpc/protocol"
type ClientReadWriteCloseHandler interface {
Connect(clientCTX ClientContext) (interface{}, error)
ReadResponse(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}) (protocol.ClientResponseCodec, error)
WriteRequest(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params interface{}, id interface{}) error
WriteRequest(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params []interface{}, id interface{}) error
Disconnect(clientCTX ClientContext, conn interface{})
Validate()

View File

@ -17,7 +17,7 @@ func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX ClientContext,
return nil, fmt.Errorf("RPC Client RWC Handler: ClientHandlers method[ReadResponse] is not implement")
}
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params interface{}, id interface{}) error {
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params []interface{}, id interface{}) error {
return fmt.Errorf("RPC Client RWC Handler: ClientHandlers method[WriteRequest] is not implement")
}

View File

@ -31,7 +31,7 @@ func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientC
return resCodec, err
}
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params interface{}, id interface{}) error {
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params []interface{}, id interface{}) error {
soc := conn.(csc.Socket)
if wErr := codec.WriteRequest(soc, method, params, id); nil != wErr {

View File

@ -34,7 +34,7 @@ func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientC
return resCodec, err
}
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params interface{}, id interface{}) error {
func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}, method string, params []interface{}, id interface{}) error {
soc := conn.(cwfc.Socket)
wc, wErr := soc.NextWriter(websocket.TextMessage)

View File

@ -6,7 +6,7 @@ import (
// ClientCodec creates a ClientCodecRequest to process each request.
type ClientCodec interface {
WriteRequest(w io.Writer, method string, args interface{}, id interface{}) error
WriteRequest(w io.Writer, method string, args []interface{}, id interface{}) error
NewResponse(rc io.Reader) (ClientResponseCodec, error)
}

12
protocol/error.go Normal file
View File

@ -0,0 +1,12 @@
package protocol
type ErrorCode int
const (
E_PARSE ErrorCode = -32700
E_INVALID_REQ ErrorCode = -32600
E_NO_METHOD ErrorCode = -32601
E_BAD_PARAMS ErrorCode = -32602
E_INTERNAL ErrorCode = -32603
E_SERVER ErrorCode = -32000
)

View File

@ -27,11 +27,16 @@ type ClientCodec struct {
codecSel codec.CodecSelector
}
func (cc *ClientCodec) WriteRequest(w io.Writer, method string, args interface{}, id interface{}) error {
func (cc *ClientCodec) WriteRequest(w io.Writer, method string, args []interface{}, id interface{}) error {
params, err := convertParamsToStringArray(args)
if nil != err {
return err
}
req := &clientRequest{
Version: Version,
Method: method,
Params: args,
Params: params,
ID: id,
}

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"git.loafle.net/commons_go/rpc/codec"
crp "git.loafle.net/commons_go/rpc/protocol"
cuej "git.loafle.net/commons_go/util/encoding/json"
)
@ -35,7 +36,7 @@ func (cnc *ClientNotificationCodec) ReadParams(args []interface{}) error {
// JSON params structured object. Unmarshal to the args object.
if err := cuej.SetValueWithJSONStringArray(*cnc.noti.Params, args); nil != err {
cnc.err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: err.Error(),
Data: cnc.noti.Params,
}
@ -48,18 +49,18 @@ func (cnc *ClientNotificationCodec) ReadParams(args []interface{}) error {
func (cnc *ClientNotificationCodec) Params() ([]string, error) {
if cnc.err == nil && cnc.noti.Params != nil {
var results []string
var values []string
if err := json.Unmarshal(*cnc.noti.Params, &results); err != nil {
if err := json.Unmarshal(*cnc.noti.Params, &values); err != nil {
cnc.err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: err.Error(),
Data: cnc.noti.Params,
}
return nil, cnc.err
}
return results, nil
return values, nil
}
return nil, cnc.err
}

View File

@ -7,6 +7,7 @@ import (
"git.loafle.net/commons_go/rpc/codec"
"git.loafle.net/commons_go/rpc/protocol"
crp "git.loafle.net/commons_go/rpc/protocol"
)
// ----------------------------------------------------------------------------
@ -35,7 +36,7 @@ func (crc *ClientResponseCodec) Result(result interface{}) error {
if nil == crc.err && nil != crc.res.Result {
if err := json.Unmarshal(*crc.res.Result, result); nil != err {
crc.err = &Error{
Code: E_PARSE,
Code: crp.E_PARSE,
Message: err.Error(),
Data: crc.res.Result,
}
@ -77,14 +78,14 @@ func newClientResponseCodec(r io.Reader, codec codec.Codec) (protocol.ClientResp
return nil, err
}
err = &Error{
Code: E_PARSE,
Code: crp.E_PARSE,
Message: err.Error(),
Data: res,
}
}
if res.Version != Version {
err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: "jsonrpc must be " + Version,
Data: res,
}

View File

@ -2,24 +2,15 @@ package json
import (
"errors"
)
type ErrorCode int
const (
E_PARSE ErrorCode = -32700
E_INVALID_REQ ErrorCode = -32600
E_NO_METHOD ErrorCode = -32601
E_BAD_PARAMS ErrorCode = -32602
E_INTERNAL ErrorCode = -32603
E_SERVER ErrorCode = -32000
crp "git.loafle.net/commons_go/rpc/protocol"
)
var ErrNullResult = errors.New("result is null")
type Error struct {
// A Number that indicates the error type that occurred.
Code ErrorCode `json:"code"` /* required */
Code crp.ErrorCode `json:"code"` /* required */
// A String providing a short description of the error.
// The message SHOULD be limited to a concise single sentence.

View File

@ -35,8 +35,13 @@ func (sc *ServerCodec) NewRequest(r io.Reader) (protocol.ServerRequestCodec, err
}
// WriteNotification send a notification from server to client.
func (sc *ServerCodec) WriteNotification(w io.Writer, method string, args interface{}) error {
noti := &serverNotification{Method: method, Params: args}
func (sc *ServerCodec) WriteNotification(w io.Writer, method string, args []interface{}) error {
params, err := convertParamsToStringArray(args)
if nil != err {
return err
}
noti := &serverNotification{Method: method, Params: params}
res := &serverResponse{Version: Version, Result: noti}
encoder := json.NewEncoder(sc.codecSel.SelectByWriter(w).Encode(w))

View File

@ -6,6 +6,8 @@ import (
"git.loafle.net/commons_go/rpc/codec"
"git.loafle.net/commons_go/rpc/protocol"
crp "git.loafle.net/commons_go/rpc/protocol"
cuej "git.loafle.net/commons_go/util/encoding/json"
)
// ----------------------------------------------------------------------------
@ -48,14 +50,14 @@ func newServerRequestCodec(r io.Reader, codec codec.Codec) (protocol.ServerReque
}
if err != nil {
err = &Error{
Code: E_PARSE,
Code: crp.E_PARSE,
Message: err.Error(),
Data: req,
}
}
if req.Version != Version {
err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: "jsonrpc must be " + Version,
Data: req,
}
@ -93,65 +95,35 @@ func (src *ServerRequestCodec) Method() string {
// case, to the method's expected parameters.
func (src *ServerRequestCodec) ReadParams(args []interface{}) error {
if src.err == nil && src.req.Params != nil {
// Note: if src.req.Params is nil it's not an error, it's an optional member.
// 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.
var values []json.RawMessage
if err := json.Unmarshal(*src.req.Params, &values); err != nil {
if err := cuej.SetValueWithJSONStringArray(*src.req.Params, args); nil != err {
src.err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: err.Error(),
Data: src.req.Params,
}
return src.err
}
for indexI := 0; indexI < len(args); indexI++ {
if err := json.Unmarshal(values[indexI], &args[indexI]); err != nil {
src.err = &Error{
Code: E_INVALID_REQ,
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 []interface{}
var values []string
if err := json.Unmarshal(*src.req.Params, &values); err != nil {
src.err = &Error{
Code: E_INVALID_REQ,
Code: crp.E_INVALID_REQ,
Message: err.Error(),
Data: src.req.Params,
}
return nil, src.err
}
var results []string
for _, v := range values {
switch v := v.(type) {
case string:
results = append(results, v)
default:
b, err := json.Marshal(v)
if nil != err {
src.err = &Error{
Code: E_INVALID_REQ,
Message: err.Error(),
Data: src.req.Params,
}
return nil, src.err
}
results = append(results, string(b))
}
}
return results, nil
return values, nil
}
return nil, src.err
}
@ -167,7 +139,7 @@ func (src *ServerRequestCodec) WriteError(w io.Writer, status int, err error) er
jsonErr, ok := err.(*Error)
if !ok {
jsonErr = &Error{
Code: E_SERVER,
Code: crp.E_SERVER,
Message: err.Error(),
}
}

46
protocol/json/util.go Normal file
View File

@ -0,0 +1,46 @@
package json
import (
"encoding/json"
"fmt"
"reflect"
cur "git.loafle.net/commons_go/util/reflect"
)
func convertParamsToStringArray(params []interface{}) ([]string, error) {
var values []string
if nil == params || 0 == len(params) {
return values, nil
}
for i, param := range params {
t := reflect.TypeOf(param)
switch t.Kind() {
case reflect.String:
values = append(values, param.(string))
case reflect.Array, reflect.Slice, reflect.Map, reflect.Struct:
b, err := json.Marshal(param)
if nil != err {
return nil, err
}
values = append(values, string(b))
case reflect.Ptr:
if t.Elem().Kind() != reflect.Struct {
return nil, fmt.Errorf("Pointer of param[%d] is permitted only Struct type", i)
}
b, err := json.Marshal(param)
if nil != err {
return nil, err
}
values = append(values, string(b))
default:
s, err := cur.ConvertToString(param)
if nil != err {
return nil, fmt.Errorf("String conversion of param[%d] has been failed [%v]", i, err)
}
values = append(values, s)
}
}
return values, nil
}

View File

@ -7,7 +7,7 @@ import (
// ServerCodec creates a ServerRequestCodec to process each request.
type ServerCodec interface {
NewRequest(r io.Reader) (ServerRequestCodec, error)
WriteNotification(w io.Writer, method string, args interface{}) error
WriteNotification(w io.Writer, method string, args []interface{}) error
}
// ServerRequestCodec decodes a request and encodes a response using a specific

View File

@ -37,7 +37,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
return nil
}
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params interface{}) error {
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params []interface{}) error {
soc := conn.(server.Socket)
if wErr := codec.WriteNotification(soc, method, params); nil != wErr {

View File

@ -49,7 +49,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
return nil
}
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params interface{}) error {
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params []interface{}) error {
soc := conn.(cwf.Socket)
wc, wErr := soc.NextWriter(websocket.TextMessage)

View File

@ -270,5 +270,5 @@ type responseState struct {
type notification struct {
method string
args interface{}
args []interface{}
}

View File

@ -5,7 +5,7 @@ import "git.loafle.net/commons_go/rpc/protocol"
type ServletReadWriteCloseHandler interface {
ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error)
WriteResponse(servletCTX ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) error
WriteNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params interface{}) error
WriteNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params []interface{}) error
Validate()
}

View File

@ -17,7 +17,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX ServletCont
return fmt.Errorf("Servlet RWC Handler: WriteResponse is not implemented")
}
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params interface{}) error {
func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, params []interface{}) error {
return fmt.Errorf("Servlet RWC Handler: WriteNotification is not implemented")
}