ing
This commit is contained in:
parent
2aebcbab5e
commit
96b71dc5d5
|
@ -1,42 +1,43 @@
|
||||||
package socket
|
package socket
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"net"
|
||||||
|
|
||||||
|
"git.loafle.net/commons_go/rpc"
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServletHandlers struct {
|
type ServletHandlers struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) GetRequest(codec protocol.ServerCodec, reader interface{}) (protocol.ServerRequestCodec, error) {
|
func (sh *ServletHandlers) GetRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
r := reader.(io.Reader)
|
nConn := conn.(net.Conn)
|
||||||
requestCodec, err := codec.NewRequest(r)
|
requestCodec, err := codec.NewRequest(nConn)
|
||||||
|
|
||||||
return requestCodec, err
|
return requestCodec, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendResponse(requestCodec protocol.ServerRequestCodec, writer interface{}, result interface{}, err error) error {
|
func (sh *ServletHandlers) SendResponse(servletCTX rpc.ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) error {
|
||||||
w := writer.(io.Writer)
|
nConn := conn.(net.Conn)
|
||||||
|
|
||||||
if nil != err {
|
if nil != err {
|
||||||
if lerr := requestCodec.WriteError(w, 500, err); nil != lerr {
|
if wErr := requestCodec.WriteError(nConn, 500, err); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := requestCodec.WriteResponse(w, result); nil != err {
|
if wErr := requestCodec.WriteResponse(nConn, result); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendNotification(codec protocol.ServerCodec, writer interface{}, method string, args ...interface{}) error {
|
func (sh *ServletHandlers) SendNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, args ...interface{}) error {
|
||||||
w := writer.(io.Writer)
|
nConn := conn.(net.Conn)
|
||||||
|
|
||||||
if err := codec.WriteNotification(w, method, args); nil != err {
|
|
||||||
|
|
||||||
|
if wErr := codec.WriteNotification(nConn, method, args); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
package fasthttp
|
package fasthttp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/gorilla/websocket"
|
||||||
|
|
||||||
"git.loafle.net/commons_go/rpc"
|
"git.loafle.net/commons_go/rpc"
|
||||||
"git.loafle.net/commons_go/rpc/protocol"
|
"git.loafle.net/commons_go/rpc/protocol"
|
||||||
"git.loafle.net/commons_go/websocket_fasthttp/websocket"
|
cwf "git.loafle.net/commons_go/websocket_fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ServletHandlers struct {
|
type ServletHandlers struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) GetRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, reader interface{}) (protocol.ServerRequestCodec, error) {
|
func (sh *ServletHandlers) GetRequest(servletCTX rpc.ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
conn := reader.(*websocket.Conn)
|
soc := conn.(cwf.Socket)
|
||||||
_, r, err := conn.NextReader()
|
_, r, err := soc.NextReader()
|
||||||
|
|
||||||
requestCodec, err := codec.NewRequest(r)
|
requestCodec, err := codec.NewRequest(r)
|
||||||
|
|
||||||
return requestCodec, err
|
return requestCodec, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendResponse(servletCTX rpc.ServletContext, requestCodec protocol.ServerRequestCodec, writer interface{}, result interface{}, err error) error {
|
func (sh *ServletHandlers) SendResponse(servletCTX rpc.ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) error {
|
||||||
conn := writer.(*websocket.Conn)
|
soc := conn.(cwf.Socket)
|
||||||
|
|
||||||
wc, lerr := conn.NextWriter(websocket.TextMessage)
|
|
||||||
if nil != lerr {
|
|
||||||
|
|
||||||
|
wc, wErr := soc.NextWriter(websocket.TextMessage)
|
||||||
|
if nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if nil != err {
|
if nil != err {
|
||||||
if lerr := requestCodec.WriteError(wc, 500, err); nil != lerr {
|
if wErr := requestCodec.WriteError(wc, 500, err); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := requestCodec.WriteResponse(wc, result); nil != err {
|
if wErr := requestCodec.WriteResponse(wc, result); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Servlet Handler: SendResponse is not implemented")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendNotification(servletCTX rpc.ServletContext, codec protocol.ServerCodec, writer interface{}, method string, args ...interface{}) error {
|
func (sh *ServletHandlers) SendNotification(servletCTX rpc.ServletContext, conn interface{}, codec protocol.ServerCodec, method string, args ...interface{}) error {
|
||||||
conn := writer.(*websocket.Conn)
|
soc := conn.(cwf.Socket)
|
||||||
|
|
||||||
wc, lerr := conn.NextWriter(websocket.TextMessage)
|
|
||||||
if nil != lerr {
|
|
||||||
|
|
||||||
|
wc, wErr := soc.NextWriter(websocket.TextMessage)
|
||||||
|
if nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := codec.WriteNotification(wc, method, args); nil != err {
|
if wErr := codec.WriteNotification(wc, method, args); nil != wErr {
|
||||||
|
return wErr
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("Servlet Handler: SendNotification is not implemented")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
143
servlet.go
143
servlet.go
|
@ -2,6 +2,8 @@ package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.loafle.net/commons_go/logging"
|
"git.loafle.net/commons_go/logging"
|
||||||
|
@ -16,7 +18,7 @@ func NewServlet(sh ServletHandler) Servlet {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Servlet interface {
|
type Servlet interface {
|
||||||
Start(parentCTX cuc.Context, reader interface{}, writer interface{}) error
|
Start(parentCTX cuc.Context, conn interface{}) error
|
||||||
Stop()
|
Stop()
|
||||||
|
|
||||||
Send(method string, args ...interface{}) (err error)
|
Send(method string, args ...interface{}) (err error)
|
||||||
|
@ -29,15 +31,14 @@ type servlet struct {
|
||||||
sh ServletHandler
|
sh ServletHandler
|
||||||
messageQueueChan chan *messageState
|
messageQueueChan chan *messageState
|
||||||
|
|
||||||
reader interface{}
|
conn interface{}
|
||||||
writer interface{}
|
|
||||||
serverCodec protocol.ServerCodec
|
serverCodec protocol.ServerCodec
|
||||||
|
|
||||||
stopChan chan struct{}
|
stopChan chan struct{}
|
||||||
stopWg sync.WaitGroup
|
stopWg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *servlet) Start(parentCTX cuc.Context, reader interface{}, writer interface{}, doneChan chan<- struct{}) error {
|
func (s *servlet) Start(parentCTX cuc.Context, conn interface{}) error {
|
||||||
if nil == s.sh {
|
if nil == s.sh {
|
||||||
panic("Servlet: servlet handler must be specified.")
|
panic("Servlet: servlet handler must be specified.")
|
||||||
}
|
}
|
||||||
|
@ -53,8 +54,7 @@ func (s *servlet) Start(parentCTX cuc.Context, reader interface{}, writer interf
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.reader = reader
|
s.conn = conn
|
||||||
s.writer = writer
|
|
||||||
s.serverCodec = sc
|
s.serverCodec = sc
|
||||||
|
|
||||||
if err := s.sh.Init(s.ctx); nil != err {
|
if err := s.sh.Init(s.ctx); nil != err {
|
||||||
|
@ -65,7 +65,7 @@ func (s *servlet) Start(parentCTX cuc.Context, reader interface{}, writer interf
|
||||||
s.messageQueueChan = make(chan *messageState, s.sh.GetPendingMessages())
|
s.messageQueueChan = make(chan *messageState, s.sh.GetPendingMessages())
|
||||||
|
|
||||||
s.stopWg.Add(1)
|
s.stopWg.Add(1)
|
||||||
go handleServlet(s, doneChan)
|
go handleServlet(s)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -81,8 +81,7 @@ func (s *servlet) Stop() {
|
||||||
|
|
||||||
s.messageQueueChan = nil
|
s.messageQueueChan = nil
|
||||||
|
|
||||||
s.reader = nil
|
s.conn = nil
|
||||||
s.writer = nil
|
|
||||||
s.serverCodec = nil
|
s.serverCodec = nil
|
||||||
|
|
||||||
logging.Logger().Info(fmt.Sprintf("Servlet is stopped"))
|
logging.Logger().Info(fmt.Sprintf("Servlet is stopped"))
|
||||||
|
@ -102,17 +101,56 @@ func (s *servlet) Context() ServletContext {
|
||||||
return s.ctx
|
return s.ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleServlet(s *servlet, doneChan chan<- struct{}) {
|
func handleServlet(s *servlet) {
|
||||||
defer s.stopWg.Done()
|
defer s.stopWg.Done()
|
||||||
|
|
||||||
messageStopChan := make(chan struct{})
|
subStopChan := make(chan struct{})
|
||||||
messageDoneChan := make(chan struct{})
|
|
||||||
|
|
||||||
go handleMessage(s, messageStopChan, messageDoneChan)
|
readerDone := make(chan error, 1)
|
||||||
|
go handleReader(s, subStopChan, readerDone)
|
||||||
|
|
||||||
|
writerDone := make(chan error, 1)
|
||||||
|
go handleWriter(s, subStopChan, writerDone)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err = <-readerDone:
|
||||||
|
close(subStopChan)
|
||||||
|
<-writerDone
|
||||||
|
case err = <-writerDone:
|
||||||
|
close(subStopChan)
|
||||||
|
<-readerDone
|
||||||
|
case <-s.stopChan:
|
||||||
|
close(subStopChan)
|
||||||
|
<-readerDone
|
||||||
|
<-writerDone
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logging.Logger().Error(fmt.Sprintf("RPC Server: servlet error %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleReader(s *servlet, stopChan chan struct{}, doneChan chan error) {
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("RPC Server: Panic when reading request from client: %v", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doneChan <- err
|
||||||
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
requestCodec, err := s.sh.GetRequest(s.ctx, s.serverCodec, s.reader)
|
requestCodec, err := s.sh.GetRequest(s.ctx, s.serverCodec, s.conn)
|
||||||
if nil != err {
|
if nil != err {
|
||||||
|
if err == io.ErrUnexpectedEOF || err == io.EOF {
|
||||||
|
err = fmt.Errorf("RPC Server: disconnected from client")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logging.Logger().Error(fmt.Sprintf("RPC Server: Cannot read request: [%s]", err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +158,59 @@ func handleServlet(s *servlet, doneChan chan<- struct{}) {
|
||||||
go handleRequest(s, requestCodec)
|
go handleRequest(s, requestCodec)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-s.stopChan:
|
case <-stopChan:
|
||||||
|
err = fmt.Errorf("RPC Server: reading request stopped because get stop channel")
|
||||||
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleWriter(s *servlet, stopChan chan struct{}, doneChan chan error) {
|
||||||
|
var err error
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("RPC Server: Panic when writing message to client: %v", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doneChan <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
var ms *messageState
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ms = <-s.messageQueueChan:
|
||||||
|
default:
|
||||||
|
// Give the last chance for ready goroutines filling s.messageQueueChan :)
|
||||||
|
runtime.Gosched()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-stopChan:
|
||||||
|
err = fmt.Errorf("RPC Server: writing message stopped because get stop channel")
|
||||||
|
return
|
||||||
|
case ms = <-s.messageQueueChan:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ms.messageType {
|
||||||
|
case protocol.MessageTypeResponse:
|
||||||
|
if err := s.sh.SendResponse(s.ctx, s.conn, ms.res.requestCodec, ms.res.result, ms.res.err); nil != err {
|
||||||
|
logging.Logger().Error(fmt.Sprintf("RPC Server: response message error %v", err))
|
||||||
|
}
|
||||||
|
ms.res.requestCodec.Close()
|
||||||
|
case protocol.MessageTypeNotification:
|
||||||
|
if err := s.sh.SendNotification(s.ctx, s.conn, s.serverCodec, ms.noti.method, ms.noti.args...); nil != err {
|
||||||
|
logging.Logger().Error(fmt.Sprintf("RPC Server: response message error %v", err))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func handleRequest(s *servlet, requestCodec protocol.ServerRequestCodec) {
|
func handleRequest(s *servlet, requestCodec protocol.ServerRequestCodec) {
|
||||||
defer func() {
|
defer func() {
|
||||||
s.stopWg.Done()
|
s.stopWg.Done()
|
||||||
|
@ -141,34 +226,6 @@ func handleRequest(s *servlet, requestCodec protocol.ServerRequestCodec) {
|
||||||
s.messageQueueChan <- ms
|
s.messageQueueChan <- ms
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleMessage(s *servlet) {
|
|
||||||
defer func() {
|
|
||||||
s.stopWg.Done()
|
|
||||||
}()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case ms := <-s.messageQueueChan:
|
|
||||||
switch ms.messageType {
|
|
||||||
case protocol.MessageTypeResponse:
|
|
||||||
if err := s.sh.SendResponse(s.ctx, ms.res.requestCodec, s.writer, ms.res.result, ms.res.err); nil != err {
|
|
||||||
logging.Logger().Error(fmt.Sprintf("RPC Server: response message error %v", err))
|
|
||||||
}
|
|
||||||
ms.res.requestCodec.Close()
|
|
||||||
case protocol.MessageTypeNotification:
|
|
||||||
if err := s.sh.SendNotification(s.ctx, s.serverCodec, s.writer, ms.noti.method, ms.noti.args...); nil != err {
|
|
||||||
logging.Logger().Error(fmt.Sprintf("RPC Server: response message error %v", err))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
releaseMessageState(ms)
|
|
||||||
case <-s.stopChan:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type messageState struct {
|
type messageState struct {
|
||||||
messageType protocol.MessageType
|
messageType protocol.MessageType
|
||||||
res messageResponse
|
res messageResponse
|
||||||
|
|
|
@ -10,10 +10,10 @@ type ServletHandler interface {
|
||||||
|
|
||||||
Init(servletCTX ServletContext) error
|
Init(servletCTX ServletContext) error
|
||||||
|
|
||||||
GetRequest(servletCTX ServletContext, codec protocol.ServerCodec, reader interface{}) (protocol.ServerRequestCodec, error)
|
GetRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error)
|
||||||
Invoke(servletCTX ServletContext, requestCodec protocol.RegistryCodec) (result interface{}, err error)
|
Invoke(servletCTX ServletContext, requestCodec protocol.RegistryCodec) (result interface{}, err error)
|
||||||
SendResponse(servletCTX ServletContext, requestCodec protocol.ServerRequestCodec, writer interface{}, result interface{}, err error) error
|
SendResponse(servletCTX ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) error
|
||||||
SendNotification(servletCTX ServletContext, codec protocol.ServerCodec, writer interface{}, method string, args ...interface{}) error
|
SendNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, args ...interface{}) error
|
||||||
|
|
||||||
Destroy(servletCTX ServletContext)
|
Destroy(servletCTX ServletContext)
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (sh *ServletHandlers) Init(servletCTX ServletContext) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) GetRequest(servletCTX ServletContext, codec protocol.ServerCodec, reader interface{}) (protocol.ServerRequestCodec, error) {
|
func (sh *ServletHandlers) GetRequest(servletCTX ServletContext, codec protocol.ServerCodec, conn interface{}) (protocol.ServerRequestCodec, error) {
|
||||||
return nil, fmt.Errorf("Servlet Handler: GetRequest is not implemented")
|
return nil, fmt.Errorf("Servlet Handler: GetRequest is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ func (sh *ServletHandlers) Invoke(servletCTX ServletContext, requestCodec protoc
|
||||||
return nil, fmt.Errorf("Servlet Handler: Invoke is not implemented")
|
return nil, fmt.Errorf("Servlet Handler: Invoke is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendResponse(servletCTX ServletContext, requestCodec protocol.ServerRequestCodec, writer interface{}, result interface{}, err error) error {
|
func (sh *ServletHandlers) SendResponse(servletCTX ServletContext, conn interface{}, requestCodec protocol.ServerRequestCodec, result interface{}, err error) error {
|
||||||
return fmt.Errorf("Servlet Handler: SendResponse is not implemented")
|
return fmt.Errorf("Servlet Handler: SendResponse is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sh *ServletHandlers) SendNotification(servletCTX ServletContext, codec protocol.ServerCodec, writer interface{}, method string, args ...interface{}) error {
|
func (sh *ServletHandlers) SendNotification(servletCTX ServletContext, conn interface{}, codec protocol.ServerCodec, method string, args ...interface{}) error {
|
||||||
return fmt.Errorf("Servlet Handler: SendNotification is not implemented")
|
return fmt.Errorf("Servlet Handler: SendNotification is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user