ing
This commit is contained in:
parent
a3d9c8941a
commit
08688dfb2f
|
@ -36,7 +36,8 @@ type client struct {
|
||||||
ch ClientHandler
|
ch ClientHandler
|
||||||
rwcHandler ClientReadWriteCloseHandler
|
rwcHandler ClientReadWriteCloseHandler
|
||||||
|
|
||||||
conn interface{}
|
conn interface{}
|
||||||
|
decoder interface{}
|
||||||
|
|
||||||
pendingRequestsCount uint32
|
pendingRequestsCount uint32
|
||||||
pendingRequests map[uint64]*RequestState
|
pendingRequests map[uint64]*RequestState
|
||||||
|
@ -46,18 +47,21 @@ type client struct {
|
||||||
|
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
stopWg sync.WaitGroup
|
stopWg sync.WaitGroup
|
||||||
|
|
||||||
|
requestMtx sync.Mutex
|
||||||
|
responseMtx sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) Connect() error {
|
func (c *client) Connect() error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if nil == c.ch {
|
if nil == c.ch {
|
||||||
panic("RPC Client: Client handler must be specified.")
|
return fmt.Errorf("RPC Client: Client handler must be specified")
|
||||||
}
|
}
|
||||||
c.ch.Validate()
|
c.ch.Validate()
|
||||||
|
|
||||||
if nil == c.rwcHandler {
|
if nil == c.rwcHandler {
|
||||||
panic("RPC Client: Client RWC handler must be specified.")
|
return fmt.Errorf("RPC Client: Client RWC handler must be specified")
|
||||||
}
|
}
|
||||||
c.rwcHandler.Validate()
|
c.rwcHandler.Validate()
|
||||||
|
|
||||||
|
@ -67,12 +71,18 @@ func (c *client) Connect() error {
|
||||||
c.ctx = c.ch.ClientContext(nil)
|
c.ctx = c.ch.ClientContext(nil)
|
||||||
|
|
||||||
if err := c.ch.Init(c.ctx); nil != err {
|
if err := c.ch.Init(c.ctx); nil != err {
|
||||||
logging.Logger().Panicf("RPC Client: Initialization of client has been failed %v", err)
|
return fmt.Errorf("RPC Client: Initialization of client has been failed %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.conn, err = c.rwcHandler.Connect(c.ctx); nil != err {
|
if c.conn, err = c.rwcHandler.Connect(c.ctx); nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.decoder, err = c.rwcHandler.NewDecoder(c.ctx, c.ch.GetCodec(), c.conn)
|
||||||
|
if nil != err {
|
||||||
|
return fmt.Errorf("RPC Client: Cannot build rpc decoder")
|
||||||
|
}
|
||||||
|
|
||||||
c.stopChan = make(chan struct{})
|
c.stopChan = make(chan struct{})
|
||||||
c.requestQueueChan = make(chan *RequestState, c.ch.GetPendingRequests())
|
c.requestQueueChan = make(chan *RequestState, c.ch.GetPendingRequests())
|
||||||
c.pendingRequests = make(map[uint64]*RequestState)
|
c.pendingRequests = make(map[uint64]*RequestState)
|
||||||
|
@ -303,7 +313,9 @@ func (c *client) rpcWriter(stopChan <-chan struct{}, writerDone chan<- error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.requestMtx.Lock()
|
||||||
err = c.rwcHandler.WriteRequest(c.ctx, c.ch.GetCodec(), c.conn, rs.Method, rs.Args, requestID)
|
err = c.rwcHandler.WriteRequest(c.ctx, c.ch.GetCodec(), c.conn, rs.Method, rs.Args, requestID)
|
||||||
|
c.requestMtx.Unlock()
|
||||||
if !rs.hasResponse {
|
if !rs.hasResponse {
|
||||||
rs.Error = err
|
rs.Error = err
|
||||||
rs.Done()
|
rs.Done()
|
||||||
|
@ -337,7 +349,9 @@ func (c *client) rpcReader(readerDone chan<- error) {
|
||||||
err = io.EOF
|
err = io.EOF
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resCodec, err := c.rwcHandler.ReadResponse(c.ctx, c.ch.GetCodec(), c.conn)
|
c.responseMtx.Lock()
|
||||||
|
resCodec, err := c.rwcHandler.ReadResponse(c.ctx, c.ch.GetCodec(), c.decoder)
|
||||||
|
c.responseMtx.Unlock()
|
||||||
if nil != err {
|
if nil != err {
|
||||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||||
logging.Logger().Infof("Client: disconnected from server")
|
logging.Logger().Infof("Client: disconnected from server")
|
||||||
|
|
|
@ -4,7 +4,8 @@ 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)
|
NewDecoder(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}) (interface{}, error)
|
||||||
|
ReadResponse(clientCTX ClientContext, codec protocol.ClientCodec, decoder 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{})
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,22 @@ package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClientReadWriteCloseHandlers struct {
|
type ClientReadWriteCloseHandlers struct {
|
||||||
ReadMtx sync.Mutex
|
|
||||||
WriteMtx sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crwch *ClientReadWriteCloseHandlers) Connect(clientCTX ClientContext) (interface{}, error) {
|
func (crwch *ClientReadWriteCloseHandlers) Connect(clientCTX ClientContext) (interface{}, error) {
|
||||||
return nil, fmt.Errorf("RPC Client RWC Handler: ClientHandlers method[Connect] is not implement")
|
return nil, fmt.Errorf("RPC Client RWC Handler: ClientHandlers method[Connect] is not implement")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}) (protocol.ClientResponseCodec, error) {
|
func (crwch *ClientReadWriteCloseHandlers) NewDecoder(clientCTX ClientContext, codec protocol.ClientCodec, conn interface{}) (interface{}, error) {
|
||||||
|
return nil, fmt.Errorf("RPC Client RWC Handler: NewDecoder is not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX ClientContext, codec protocol.ClientCodec, decoder interface{}) (protocol.ClientResponseCodec, error) {
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,14 @@ func (crwch *ClientReadWriteCloseHandlers) Connect(clientCTX client.ClientContex
|
||||||
return csc.NewSocket(crwch.SocketBuilder, clientCTX)
|
return csc.NewSocket(crwch.SocketBuilder, clientCTX)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}) (protocol.ClientResponseCodec, error) {
|
func (crwch *ClientReadWriteCloseHandlers) NewDecoder(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}) (interface{}, error) {
|
||||||
soc := conn.(csc.Socket)
|
soc := conn.(csc.Socket)
|
||||||
|
|
||||||
crwch.ReadMtx.Lock()
|
return codec.NewDecoder(soc), nil
|
||||||
resCodec, err := codec.NewResponse(soc)
|
}
|
||||||
crwch.ReadMtx.Unlock()
|
|
||||||
|
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientContext, codec protocol.ClientCodec, decoder interface{}) (protocol.ClientResponseCodec, error) {
|
||||||
|
resCodec, err := codec.NewResponse(decoder)
|
||||||
|
|
||||||
return resCodec, err
|
return resCodec, err
|
||||||
}
|
}
|
||||||
|
@ -40,9 +42,7 @@ func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientC
|
||||||
)
|
)
|
||||||
soc := conn.(csc.Socket)
|
soc := conn.(csc.Socket)
|
||||||
|
|
||||||
crwch.WriteMtx.Lock()
|
|
||||||
wErr = codec.WriteRequest(soc, method, params, id)
|
wErr = codec.WriteRequest(soc, method, params, id)
|
||||||
crwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,18 @@ func (crwch *ClientReadWriteCloseHandlers) Connect(clientCTX client.ClientContex
|
||||||
return cwfc.NewSocket(crwch.SocketBuilder, clientCTX)
|
return cwfc.NewSocket(crwch.SocketBuilder, clientCTX)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}) (protocol.ClientResponseCodec, error) {
|
func (crwch *ClientReadWriteCloseHandlers) NewDecoder(clientCTX client.ClientContext, codec protocol.ClientCodec, conn interface{}) (interface{}, error) {
|
||||||
soc := conn.(cwfc.Socket)
|
soc := conn.(cwfc.Socket)
|
||||||
|
|
||||||
crwch.ReadMtx.Lock()
|
|
||||||
_, r, err := soc.NextReader()
|
_, r, err := soc.NextReader()
|
||||||
resCodec, err := codec.NewResponse(r)
|
if nil != err {
|
||||||
crwch.ReadMtx.Unlock()
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return codec.NewDecoder(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (crwch *ClientReadWriteCloseHandlers) ReadResponse(clientCTX client.ClientContext, codec protocol.ClientCodec, decoder interface{}) (protocol.ClientResponseCodec, error) {
|
||||||
|
resCodec, err := codec.NewResponse(decoder)
|
||||||
|
|
||||||
return resCodec, err
|
return resCodec, err
|
||||||
}
|
}
|
||||||
|
@ -45,10 +50,8 @@ func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientC
|
||||||
)
|
)
|
||||||
soc := conn.(cwfc.Socket)
|
soc := conn.(cwfc.Socket)
|
||||||
|
|
||||||
crwch.WriteMtx.Lock()
|
|
||||||
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
||||||
if nil != wErr {
|
if nil != wErr {
|
||||||
crwch.WriteMtx.Unlock()
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -57,8 +60,6 @@ func (crwch *ClientReadWriteCloseHandlers) WriteRequest(clientCTX client.ClientC
|
||||||
|
|
||||||
wErr = codec.WriteRequest(wc, method, params, id)
|
wErr = codec.WriteRequest(wc, method, params, id)
|
||||||
|
|
||||||
crwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
package codec
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// Codec interface contains the encoder for response or decoder for request.
|
|
||||||
// Eg. gzip, flate compressions.
|
|
||||||
type Codec interface {
|
|
||||||
Encode(w io.Writer) io.Writer
|
|
||||||
Decode(r io.Reader) io.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
type codec struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *codec) Encode(w io.Writer) io.Writer {
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *codec) Decode(r io.Reader) io.Reader {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultCodec = &codec{}
|
|
|
@ -1,25 +0,0 @@
|
||||||
package codec
|
|
||||||
|
|
||||||
import "io"
|
|
||||||
|
|
||||||
// CodecSelector interface provides a way to select encoder using the http
|
|
||||||
// request. Typically people can use this to check HEADER of the request and
|
|
||||||
// figure out client capabilities.
|
|
||||||
// Eg. "Accept-Encoding" tells about supported compressions.
|
|
||||||
type CodecSelector interface {
|
|
||||||
SelectByReader(r io.Reader) Codec
|
|
||||||
SelectByWriter(w io.Writer) Codec
|
|
||||||
}
|
|
||||||
|
|
||||||
type codecSelector struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *codecSelector) SelectByReader(_ io.Reader) Codec {
|
|
||||||
return DefaultCodec
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_ *codecSelector) SelectByWriter(_ io.Writer) Codec {
|
|
||||||
return DefaultCodec
|
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultCodecSelector = &codecSelector{}
|
|
|
@ -6,8 +6,10 @@ import (
|
||||||
|
|
||||||
// ClientCodec creates a ClientCodecRequest to process each request.
|
// ClientCodec creates a ClientCodecRequest to process each request.
|
||||||
type ClientCodec interface {
|
type ClientCodec interface {
|
||||||
|
NewDecoder(r io.Reader) 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(decoder interface{}) (ClientResponseCodec, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClientResponseCodec interface {
|
type ClientResponseCodec interface {
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.loafle.net/commons_go/rpc/codec"
|
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,19 +11,17 @@ import (
|
||||||
// Codec
|
// Codec
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// NewCustomClientCodec returns a new JSON Codec based on passed encoder selector.
|
|
||||||
func NewCustomClientCodec(codecSel codec.CodecSelector) protocol.ClientCodec {
|
|
||||||
return &ClientCodec{codecSel: codecSel}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientCodec returns a new JSON Codec.
|
// NewClientCodec returns a new JSON Codec.
|
||||||
func NewClientCodec() protocol.ClientCodec {
|
func NewClientCodec() protocol.ClientCodec {
|
||||||
return NewCustomClientCodec(codec.DefaultCodecSelector)
|
return &ClientCodec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientCodec creates a ClientCodecRequest to process each request.
|
// ClientCodec creates a ClientCodecRequest to process each request.
|
||||||
type ClientCodec struct {
|
type ClientCodec struct {
|
||||||
codecSel codec.CodecSelector
|
}
|
||||||
|
|
||||||
|
func (cc *ClientCodec) NewDecoder(r io.Reader) interface{} {
|
||||||
|
return json.NewDecoder(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -40,7 +37,7 @@ func (cc *ClientCodec) WriteRequest(w io.Writer, method string, args []interface
|
||||||
ID: id,
|
ID: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder := json.NewEncoder(cc.codecSel.SelectByWriter(w).Encode(w))
|
encoder := json.NewEncoder(w)
|
||||||
if err := encoder.Encode(req); nil != err {
|
if err := encoder.Encode(req); nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -49,6 +46,6 @@ func (cc *ClientCodec) WriteRequest(w io.Writer, method string, args []interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMessage returns a ClientMessageCodec.
|
// NewMessage returns a ClientMessageCodec.
|
||||||
func (cc *ClientCodec) NewResponse(r io.Reader) (protocol.ClientResponseCodec, error) {
|
func (cc *ClientCodec) NewResponse(decoder interface{}) (protocol.ClientResponseCodec, error) {
|
||||||
return newClientResponseCodec(r, cc.codecSel.SelectByReader(r))
|
return newClientResponseCodec(decoder.(*json.Decoder))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package json
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"git.loafle.net/commons_go/rpc/codec"
|
|
||||||
crp "git.loafle.net/commons_go/rpc/protocol"
|
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"
|
||||||
)
|
)
|
||||||
|
@ -21,9 +20,8 @@ type clientNotification struct {
|
||||||
|
|
||||||
// ClientNotificationCodec decodes and encodes a single notification.
|
// ClientNotificationCodec decodes and encodes a single notification.
|
||||||
type ClientNotificationCodec struct {
|
type ClientNotificationCodec struct {
|
||||||
noti *clientNotification
|
noti *clientNotification
|
||||||
err error
|
err error
|
||||||
codec codec.Codec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cnc *ClientNotificationCodec) HasResponse() bool {
|
func (cnc *ClientNotificationCodec) HasResponse() bool {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"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"
|
crp "git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
@ -23,9 +22,8 @@ type clientResponse struct {
|
||||||
|
|
||||||
// ClientResponseCodec decodes and encodes a single request.
|
// ClientResponseCodec decodes and encodes a single request.
|
||||||
type ClientResponseCodec struct {
|
type ClientResponseCodec struct {
|
||||||
res *clientResponse
|
res *clientResponse
|
||||||
err error
|
err error
|
||||||
codec codec.Codec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crc *ClientResponseCodec) ID() interface{} {
|
func (crc *ClientResponseCodec) ID() interface{} {
|
||||||
|
@ -61,15 +59,11 @@ func (crc *ClientResponseCodec) Notification() (protocol.ClientNotificationCodec
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ClientNotificationCodec{noti: noti, err: err, codec: crc.codec}, nil
|
return &ClientNotificationCodec{noti: noti, err: err}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newClientMessageCodec returns a new ClientMessageCodec.
|
// newClientMessageCodec returns a new ClientMessageCodec.
|
||||||
func newClientResponseCodec(r io.Reader, codec codec.Codec) (protocol.ClientResponseCodec, error) {
|
func newClientResponseCodec(decoder *json.Decoder) (protocol.ClientResponseCodec, error) {
|
||||||
decoder := json.NewDecoder(r)
|
|
||||||
if nil == r {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
decoder.UseNumber()
|
decoder.UseNumber()
|
||||||
|
|
||||||
res := &clientResponse{}
|
res := &clientResponse{}
|
||||||
|
@ -92,5 +86,5 @@ func newClientResponseCodec(r io.Reader, codec codec.Codec) (protocol.ClientResp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ClientResponseCodec{res: res, err: err, codec: codec}, nil
|
return &ClientResponseCodec{res: res, err: err}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.loafle.net/commons_go/rpc/codec"
|
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,24 +13,22 @@ var null = json.RawMessage([]byte("null"))
|
||||||
// Codec
|
// Codec
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// NewCustomServerCodec returns a new JSON Codec based on passed encoder selector.
|
|
||||||
func NewCustomServerCodec(codecSel codec.CodecSelector) protocol.ServerCodec {
|
|
||||||
return &ServerCodec{codecSel: codecSel}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewServerCodec returns a new JSON Codec.
|
// NewServerCodec returns a new JSON Codec.
|
||||||
func NewServerCodec() protocol.ServerCodec {
|
func NewServerCodec() protocol.ServerCodec {
|
||||||
return NewCustomServerCodec(codec.DefaultCodecSelector)
|
return &ServerCodec{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerCodec creates a ServerRequestCodec to process each request.
|
// ServerCodec creates a ServerRequestCodec to process each request.
|
||||||
type ServerCodec struct {
|
type ServerCodec struct {
|
||||||
codecSel codec.CodecSelector
|
}
|
||||||
|
|
||||||
|
func (sc *ServerCodec) NewDecoder(r io.Reader) interface{} {
|
||||||
|
return json.NewDecoder(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRequest returns a ServerRequestCodec.
|
// NewRequest returns a ServerRequestCodec.
|
||||||
func (sc *ServerCodec) NewRequest(r io.Reader) (protocol.ServerRequestCodec, error) {
|
func (sc *ServerCodec) NewRequest(decoder interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
return newServerRequestCodec(r, sc.codecSel.SelectByReader(r))
|
return newServerRequestCodec(decoder.(*json.Decoder))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteNotification send a notification from server to client.
|
// WriteNotification send a notification from server to client.
|
||||||
|
@ -44,7 +41,7 @@ func (sc *ServerCodec) WriteNotification(w io.Writer, method string, args []inte
|
||||||
noti := &serverNotification{Method: method, Params: params}
|
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(w)
|
||||||
// Not sure in which case will this happen. But seems harmless.
|
// Not sure in which case will this happen. But seems harmless.
|
||||||
if err := encoder.Encode(res); nil != err {
|
if err := encoder.Encode(res); nil != err {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"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"
|
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"
|
||||||
|
@ -36,14 +35,8 @@ type serverRequest struct {
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// newRequestCodec returns a new ServerRequestCodec.
|
// newRequestCodec returns a new ServerRequestCodec.
|
||||||
func newServerRequestCodec(r io.Reader, codec codec.Codec) (protocol.ServerRequestCodec, error) {
|
func newServerRequestCodec(decoder *json.Decoder) (protocol.ServerRequestCodec, error) {
|
||||||
// Decode the request body and check if RPC method is valid.
|
// Decode the request body and check if RPC method is valid.
|
||||||
decoder := json.NewDecoder(r)
|
|
||||||
if nil == r {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
decoder.UseNumber()
|
|
||||||
|
|
||||||
req := &serverRequest{}
|
req := &serverRequest{}
|
||||||
err := decoder.Decode(req)
|
err := decoder.Decode(req)
|
||||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||||
|
@ -64,14 +57,13 @@ func newServerRequestCodec(r io.Reader, codec codec.Codec) (protocol.ServerReque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &ServerRequestCodec{req: req, err: err, codec: codec}, nil
|
return &ServerRequestCodec{req: req, err: err}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerRequestCodec decodes and encodes a single request.
|
// ServerRequestCodec decodes and encodes a single request.
|
||||||
type ServerRequestCodec struct {
|
type ServerRequestCodec struct {
|
||||||
req *serverRequest
|
req *serverRequest
|
||||||
err error
|
err error
|
||||||
codec codec.Codec
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (src *ServerRequestCodec) HasResponse() bool {
|
func (src *ServerRequestCodec) HasResponse() bool {
|
||||||
|
@ -155,7 +147,7 @@ func (src *ServerRequestCodec) WriteError(w io.Writer, status int, err error) er
|
||||||
func (src *ServerRequestCodec) writeServerResponse(w io.Writer, res *serverResponse) error {
|
func (src *ServerRequestCodec) writeServerResponse(w io.Writer, res *serverResponse) error {
|
||||||
// ID is null for notifications and they don't have a response.
|
// ID is null for notifications and they don't have a response.
|
||||||
if src.req.ID != nil {
|
if src.req.ID != nil {
|
||||||
encoder := json.NewEncoder(src.codec.Encode(w))
|
encoder := json.NewEncoder(w)
|
||||||
// Not sure in which case will this happen. But seems harmless.
|
// Not sure in which case will this happen. But seems harmless.
|
||||||
if err := encoder.Encode(res); nil != err {
|
if err := encoder.Encode(res); nil != err {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,7 +6,9 @@ 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)
|
NewDecoder(r io.Reader) interface{}
|
||||||
|
|
||||||
|
NewRequest(decoder interface{}) (ServerRequestCodec, error)
|
||||||
WriteNotification(w io.Writer, method string, args []interface{}) error
|
WriteNotification(w io.Writer, method string, args []interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,14 @@ type ServletReadWriteCloseHandlers struct {
|
||||||
rpc.ServletReadWriteCloseHandlers
|
rpc.ServletReadWriteCloseHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
func (srwch *ServletReadWriteCloseHandlers) NewDecoder(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (interface{}, error) {
|
||||||
soc := conn.(server.Socket)
|
soc := conn.(server.Socket)
|
||||||
|
|
||||||
srwch.ReadMtx.Lock()
|
return codec.NewDecoder(soc), nil
|
||||||
reqCodec, err := codec.NewRequest(soc)
|
}
|
||||||
srwch.ReadMtx.Unlock()
|
|
||||||
|
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, decoder interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
|
reqCodec, err := codec.NewRequest(decoder)
|
||||||
|
|
||||||
return reqCodec, err
|
return reqCodec, err
|
||||||
}
|
}
|
||||||
|
@ -30,13 +32,11 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
|
||||||
)
|
)
|
||||||
soc := conn.(server.Socket)
|
soc := conn.(server.Socket)
|
||||||
|
|
||||||
srwch.WriteMtx.Lock()
|
|
||||||
if nil != err {
|
if nil != err {
|
||||||
wErr = reqCodec.WriteError(soc, 500, err)
|
wErr = reqCodec.WriteError(soc, 500, err)
|
||||||
} else {
|
} else {
|
||||||
wErr = reqCodec.WriteResponse(soc, result)
|
wErr = reqCodec.WriteResponse(soc, result)
|
||||||
}
|
}
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,7 @@ func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.Ser
|
||||||
)
|
)
|
||||||
soc := conn.(server.Socket)
|
soc := conn.(server.Socket)
|
||||||
|
|
||||||
srwch.WriteMtx.Lock()
|
|
||||||
wErr = codec.WriteNotification(soc, method, params)
|
wErr = codec.WriteNotification(soc, method, params)
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,18 @@ type ServletReadWriteCloseHandlers struct {
|
||||||
rpc.ServletReadWriteCloseHandlers
|
rpc.ServletReadWriteCloseHandlers
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
func (srwch *ServletReadWriteCloseHandlers) NewDecoder(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (interface{}, error) {
|
||||||
soc := conn.(cwf.Socket)
|
soc := conn.(cwf.Socket)
|
||||||
|
|
||||||
srwch.ReadMtx.Lock()
|
|
||||||
_, r, err := soc.NextReader()
|
_, r, err := soc.NextReader()
|
||||||
requestCodec, err := codec.NewRequest(r)
|
if nil != err {
|
||||||
srwch.ReadMtx.Unlock()
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return codec.NewDecoder(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, decoder interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
|
requestCodec, err := codec.NewRequest(decoder)
|
||||||
|
|
||||||
return requestCodec, err
|
return requestCodec, err
|
||||||
}
|
}
|
||||||
|
@ -35,10 +40,8 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
|
||||||
)
|
)
|
||||||
soc := conn.(cwf.Socket)
|
soc := conn.(cwf.Socket)
|
||||||
|
|
||||||
srwch.WriteMtx.Lock()
|
|
||||||
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
||||||
if nil != wErr {
|
if nil != wErr {
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +54,6 @@ func (srwch *ServletReadWriteCloseHandlers) WriteResponse(servletCTX rpc.Servlet
|
||||||
} else {
|
} else {
|
||||||
wErr = requestCodec.WriteResponse(wc, result)
|
wErr = requestCodec.WriteResponse(wc, result)
|
||||||
}
|
}
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
@ -63,10 +65,8 @@ func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.Ser
|
||||||
)
|
)
|
||||||
soc := conn.(cwf.Socket)
|
soc := conn.(cwf.Socket)
|
||||||
|
|
||||||
srwch.WriteMtx.Lock()
|
|
||||||
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
wc, wErr = soc.NextWriter(websocket.TextMessage)
|
||||||
if nil != wErr {
|
if nil != wErr {
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +75,6 @@ func (srwch *ServletReadWriteCloseHandlers) WriteNotification(servletCTX rpc.Ser
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wErr = codec.WriteNotification(wc, method, params)
|
wErr = codec.WriteNotification(wc, method, params)
|
||||||
srwch.WriteMtx.Unlock()
|
|
||||||
|
|
||||||
return wErr
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
15
servlet.go
15
servlet.go
|
@ -36,11 +36,13 @@ type rpcServlet struct {
|
||||||
|
|
||||||
conn interface{}
|
conn interface{}
|
||||||
serverCodec protocol.ServerCodec
|
serverCodec protocol.ServerCodec
|
||||||
|
decoder interface{}
|
||||||
|
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
stopWg sync.WaitGroup
|
stopWg sync.WaitGroup
|
||||||
|
|
||||||
sendMtx sync.RWMutex
|
requestMtx sync.Mutex
|
||||||
|
responseMTX sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *rpcServlet) Context() ServletContext {
|
func (s *rpcServlet) Context() ServletContext {
|
||||||
|
@ -70,6 +72,10 @@ func (s *rpcServlet) Start(parentCTX cuc.Context, conn interface{}, doneChan cha
|
||||||
|
|
||||||
s.conn = conn
|
s.conn = conn
|
||||||
s.serverCodec = sc
|
s.serverCodec = sc
|
||||||
|
s.decoder, err = s.rwcSH.NewDecoder(s.ctx, sc, conn)
|
||||||
|
if nil != err {
|
||||||
|
return fmt.Errorf("RPC Servlet: Cannot build rpc decoder")
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.sh.Init(s.ctx); nil != err {
|
if err := s.sh.Init(s.ctx); nil != err {
|
||||||
return fmt.Errorf("RPC Servlet: Initialization of servlet has been failed %v", err)
|
return fmt.Errorf("RPC Servlet: Initialization of servlet has been failed %v", err)
|
||||||
|
@ -168,7 +174,9 @@ func handleReader(s *rpcServlet, stopChan chan struct{}, doneChan chan error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
requestCodec, err := s.rwcSH.ReadRequest(s.ctx, s.serverCodec, s.conn)
|
s.requestMtx.Lock()
|
||||||
|
requestCodec, err := s.rwcSH.ReadRequest(s.ctx, s.serverCodec, s.decoder)
|
||||||
|
s.requestMtx.Unlock()
|
||||||
if nil != err {
|
if nil != err {
|
||||||
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||||
err = fmt.Errorf("RPC Server: Disconnected from client")
|
err = fmt.Errorf("RPC Server: Disconnected from client")
|
||||||
|
@ -221,6 +229,7 @@ func handleWriter(s *rpcServlet, stopChan chan struct{}, doneChan chan error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.responseMTX.Lock()
|
||||||
if nil != rs.requestCodec {
|
if nil != rs.requestCodec {
|
||||||
if err := s.rwcSH.WriteResponse(s.ctx, s.conn, rs.requestCodec, rs.result, rs.err); nil != err {
|
if err := s.rwcSH.WriteResponse(s.ctx, s.conn, rs.requestCodec, rs.result, rs.err); nil != err {
|
||||||
logging.Logger().Errorf("RPC Servlet: response error %v", err)
|
logging.Logger().Errorf("RPC Servlet: response error %v", err)
|
||||||
|
@ -230,9 +239,9 @@ func handleWriter(s *rpcServlet, stopChan chan struct{}, doneChan chan error) {
|
||||||
logging.Logger().Errorf("RPC Servlet: notification error %v", err)
|
logging.Logger().Errorf("RPC Servlet: notification error %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
s.responseMTX.Unlock()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRequest(s *rpcServlet, requestCodec protocol.ServerRequestCodec) {
|
func handleRequest(s *rpcServlet, requestCodec protocol.ServerRequestCodec) {
|
||||||
|
|
|
@ -3,7 +3,9 @@ package rpc
|
||||||
import "git.loafle.net/commons_go/rpc/protocol"
|
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)
|
NewDecoder(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (interface{}, error)
|
||||||
|
|
||||||
|
ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, decoder 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
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,20 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
|
||||||
|
|
||||||
|
"git.loafle.net/commons_go/logging"
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServletReadWriteCloseHandlers struct {
|
type ServletReadWriteCloseHandlers struct {
|
||||||
ReadMtx sync.Mutex
|
|
||||||
WriteMtx sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
func (srwch *ServletReadWriteCloseHandlers) NewDecoder(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) interface{} {
|
||||||
|
logging.Logger().Errorf("Servlet RWC Handler: NewDecoder is not implemented")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (srwch *ServletReadWriteCloseHandlers) ReadRequest(servletCTX ServletContext, codec protocol.ServerCodec, decoder interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
return nil, fmt.Errorf("Servlet RWC Handler: ReadRequest is not implemented")
|
return nil, fmt.Errorf("Servlet RWC Handler: ReadRequest is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user