diff --git a/client/client_rwc_handler.go b/client/client_rwc_handler.go index 52aac9e..9693c51 100644 --- a/client/client_rwc_handler.go +++ b/client/client_rwc_handler.go @@ -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() diff --git a/client/client_rwc_handlers.go b/client/client_rwc_handlers.go index 24b011a..2461cfc 100644 --- a/client/client_rwc_handlers.go +++ b/client/client_rwc_handlers.go @@ -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") } diff --git a/client/rwc/socket/client_rwc_handlers.go b/client/rwc/socket/client_rwc_handlers.go index 7a04ba7..d9595a0 100644 --- a/client/rwc/socket/client_rwc_handlers.go +++ b/client/rwc/socket/client_rwc_handlers.go @@ -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 { diff --git a/client/rwc/websocket/fasthttp/client_rwc_handlers.go b/client/rwc/websocket/fasthttp/client_rwc_handlers.go index 26a820d..9053dd9 100644 --- a/client/rwc/websocket/fasthttp/client_rwc_handlers.go +++ b/client/rwc/websocket/fasthttp/client_rwc_handlers.go @@ -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) diff --git a/protocol/client_codec.go b/protocol/client_codec.go index 1f2a134..b5a58bc 100644 --- a/protocol/client_codec.go +++ b/protocol/client_codec.go @@ -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) } diff --git a/protocol/error.go b/protocol/error.go new file mode 100644 index 0000000..25e8197 --- /dev/null +++ b/protocol/error.go @@ -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 +) diff --git a/protocol/json/client.go b/protocol/json/client.go index 550ed3a..3ead2d6 100644 --- a/protocol/json/client.go +++ b/protocol/json/client.go @@ -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, } diff --git a/protocol/json/client_notification.go b/protocol/json/client_notification.go index 0ed8575..d65a9a1 100644 --- a/protocol/json/client_notification.go +++ b/protocol/json/client_notification.go @@ -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 } diff --git a/protocol/json/client_response.go b/protocol/json/client_response.go index 3fc0562..5c53b1a 100644 --- a/protocol/json/client_response.go +++ b/protocol/json/client_response.go @@ -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, } diff --git a/protocol/json/error.go b/protocol/json/error.go index 9ebbc86..8c2353c 100644 --- a/protocol/json/error.go +++ b/protocol/json/error.go @@ -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. diff --git a/protocol/json/server.go b/protocol/json/server.go index 32e1940..cbc38f9 100644 --- a/protocol/json/server.go +++ b/protocol/json/server.go @@ -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)) diff --git a/protocol/json/server_request.go b/protocol/json/server_request.go index ecf8a5e..636863c 100644 --- a/protocol/json/server_request.go +++ b/protocol/json/server_request.go @@ -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(), } } diff --git a/protocol/json/util.go b/protocol/json/util.go new file mode 100644 index 0000000..43695d1 --- /dev/null +++ b/protocol/json/util.go @@ -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 +} diff --git a/protocol/server_codec.go b/protocol/server_codec.go index 6dbcc89..92f98de 100644 --- a/protocol/server_codec.go +++ b/protocol/server_codec.go @@ -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 diff --git a/server/rwc/socket/servlet_rwc_handlers.go b/server/rwc/socket/servlet_rwc_handlers.go index d37e3f3..ccf374e 100644 --- a/server/rwc/socket/servlet_rwc_handlers.go +++ b/server/rwc/socket/servlet_rwc_handlers.go @@ -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 { diff --git a/server/rwc/websocket/fasthttp/servlet_rwc_handlers.go b/server/rwc/websocket/fasthttp/servlet_rwc_handlers.go index a44cc07..77f8900 100644 --- a/server/rwc/websocket/fasthttp/servlet_rwc_handlers.go +++ b/server/rwc/websocket/fasthttp/servlet_rwc_handlers.go @@ -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) diff --git a/servlet.go b/servlet.go index da1afd1..91f728d 100644 --- a/servlet.go +++ b/servlet.go @@ -270,5 +270,5 @@ type responseState struct { type notification struct { method string - args interface{} + args []interface{} } diff --git a/servlet_rwc_handler.go b/servlet_rwc_handler.go index 87ec010..c0e2ef7 100644 --- a/servlet_rwc_handler.go +++ b/servlet_rwc_handler.go @@ -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() } diff --git a/servlet_rwc_handlers.go b/servlet_rwc_handlers.go index 10738ef..033c638 100644 --- a/servlet_rwc_handlers.go +++ b/servlet_rwc_handlers.go @@ -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") }