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 { type ClientReadWriteCloseHandler interface {
Connect(clientCTX ClientContext) (interface{}, error) Connect(clientCTX ClientContext) (interface{}, error)
ReadResponse(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}) (protocol.ClientResponseCodec, 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{}) Disconnect(clientCTX ClientContext, conn interface{})
Validate() 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") 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") 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 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) soc := conn.(csc.Socket)
if wErr := codec.WriteRequest(soc, method, params, id); nil != wErr { 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 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) soc := conn.(cwfc.Socket)
wc, wErr := soc.NextWriter(websocket.TextMessage) wc, wErr := soc.NextWriter(websocket.TextMessage)

View File

@ -6,7 +6,7 @@ import (
// ClientCodec creates a ClientCodecRequest to process each request. // ClientCodec creates a ClientCodecRequest to process each request.
type ClientCodec interface { 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) 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 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{ req := &clientRequest{
Version: Version, Version: Version,
Method: method, Method: method,
Params: args, Params: params,
ID: id, ID: id,
} }

View File

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

View File

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

View File

@ -2,24 +2,15 @@ package json
import ( import (
"errors" "errors"
)
type ErrorCode int crp "git.loafle.net/commons_go/rpc/protocol"
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
) )
var ErrNullResult = errors.New("result is null") var ErrNullResult = errors.New("result is null")
type Error struct { type Error struct {
// A Number that indicates the error type that occurred. // 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. // A String providing a short description of the error.
// The message SHOULD be limited to a concise single sentence. // 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. // WriteNotification send a notification from server to client.
func (sc *ServerCodec) WriteNotification(w io.Writer, method string, args interface{}) error { func (sc *ServerCodec) WriteNotification(w io.Writer, method string, args []interface{}) error {
noti := &serverNotification{Method: method, Params: args} params, err := convertParamsToStringArray(args)
if nil != err {
return err
}
noti := &serverNotification{Method: method, Params: params}
res := &serverResponse{Version: Version, Result: noti} res := &serverResponse{Version: Version, Result: noti}
encoder := json.NewEncoder(sc.codecSel.SelectByWriter(w).Encode(w)) 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/codec"
"git.loafle.net/commons_go/rpc/protocol" "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 { if err != nil {
err = &Error{ err = &Error{
Code: E_PARSE, Code: crp.E_PARSE,
Message: err.Error(), Message: err.Error(),
Data: req, Data: req,
} }
} }
if req.Version != Version { if req.Version != Version {
err = &Error{ err = &Error{
Code: E_INVALID_REQ, Code: crp.E_INVALID_REQ,
Message: "jsonrpc must be " + Version, Message: "jsonrpc must be " + Version,
Data: req, Data: req,
} }
@ -93,65 +95,35 @@ func (src *ServerRequestCodec) Method() string {
// case, to the method's expected parameters. // case, to the method's expected parameters.
func (src *ServerRequestCodec) ReadParams(args []interface{}) error { func (src *ServerRequestCodec) ReadParams(args []interface{}) error {
if src.err == nil && src.req.Params != nil { 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. // JSON params structured object. Unmarshal to the args object.
var values []json.RawMessage if err := cuej.SetValueWithJSONStringArray(*src.req.Params, args); nil != err {
if err := json.Unmarshal(*src.req.Params, &values); err != nil {
src.err = &Error{ src.err = &Error{
Code: E_INVALID_REQ, Code: crp.E_INVALID_REQ,
Message: err.Error(), Message: err.Error(),
Data: src.req.Params, Data: src.req.Params,
} }
return src.err return src.err
} }
return nil
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 src.err return src.err
} }
func (src *ServerRequestCodec) Params() ([]string, error) { func (src *ServerRequestCodec) Params() ([]string, error) {
if src.err == nil && src.req.Params != nil { if src.err == nil && src.req.Params != nil {
var values []interface{} var values []string
if err := json.Unmarshal(*src.req.Params, &values); err != nil { if err := json.Unmarshal(*src.req.Params, &values); err != nil {
src.err = &Error{ src.err = &Error{
Code: E_INVALID_REQ, Code: crp.E_INVALID_REQ,
Message: err.Error(), Message: err.Error(),
Data: src.req.Params, Data: src.req.Params,
} }
return nil, src.err return nil, src.err
} }
var results []string return values, nil
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 nil, src.err return nil, src.err
} }
@ -167,7 +139,7 @@ func (src *ServerRequestCodec) WriteError(w io.Writer, status int, err error) er
jsonErr, ok := err.(*Error) jsonErr, ok := err.(*Error)
if !ok { if !ok {
jsonErr = &Error{ jsonErr = &Error{
Code: E_SERVER, Code: crp.E_SERVER,
Message: err.Error(), 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. // ServerCodec creates a ServerRequestCodec to process each request.
type ServerCodec interface { type ServerCodec interface {
NewRequest(r io.Reader) (ServerRequestCodec, error) 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 // 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 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) soc := conn.(server.Socket)
if wErr := codec.WriteNotification(soc, method, params); nil != wErr { if wErr := codec.WriteNotification(soc, method, params); nil != wErr {

View File

@ -49,7 +49,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
return nil 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) soc := conn.(cwf.Socket)
wc, wErr := soc.NextWriter(websocket.TextMessage) wc, wErr := soc.NextWriter(websocket.TextMessage)

View File

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

View File

@ -5,7 +5,7 @@ import "git.loafle.net/commons_go/rpc/protocol"
type ServletReadWriteCloseHandler interface { type ServletReadWriteCloseHandler interface {
ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error)
WriteResponse(servletCTX ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) 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() Validate()
} }

View File

@ -17,7 +17,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX ServletCont
return fmt.Errorf("Servlet RWC Handler: WriteResponse is not implemented") 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") return fmt.Errorf("Servlet RWC Handler: WriteNotification is not implemented")
} }