This commit is contained in:
crusader 2017-08-09 17:20:44 +09:00
parent 6a5cb736ed
commit 35ba58c220
8 changed files with 88 additions and 212 deletions

View File

@ -1,6 +1,6 @@
{
"server": {
"addr": ":80",
"addr": ":18081",
"tls": false
},
"websocket": {

BIN
debug

Binary file not shown.

View File

@ -7,7 +7,6 @@ import (
"path/filepath"
"git.loafle.net/overflow/overflow_service_websocket/config"
"git.loafle.net/overflow/overflow_service_websocket/protocol/jsonrpc"
"git.loafle.net/overflow/overflow_service_websocket/server"
)
@ -46,7 +45,7 @@ func main() {
// Config TLS
ws := server.New(sConfig)
ws.RegistProtocol("jsonrpc", jsonrpc.NewHandler())
ws.OnConnection(func(c server.Client) {
log.Println("Client have been connected")
c.OnDisconnect(func(c server.Client) {

View File

@ -1,35 +0,0 @@
package protocol
import "errors"
type ErrorCode int
const (
E_PARSE ErrorCode = -32700
E_INVALID_REQ ErrorCode = -32600
E_NOT_FOUND_METHOD ErrorCode = -32601
E_INVALID_PARAMS ErrorCode = -32602
E_INTERNAL ErrorCode = -32603
E_SERVER ErrorCode = -32000
)
var ErrNullResult = errors.New("result is null")
type Error struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
type Handler interface {
Handle([]byte) ([]byte, *Error)
}
func NewError(code ErrorCode, err error, data interface{}) *Error {
e := &Error{
Code: code,
Message: err.Error(),
Data: data,
}
return e
}

View File

@ -1,94 +0,0 @@
package jsonrpc
import (
"encoding/json"
"log"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
serverGrpc "git.loafle.net/overflow/overflow_api_server/golang"
"git.loafle.net/overflow/overflow_service_websocket/config"
"git.loafle.net/overflow/overflow_service_websocket/pool"
grpcPool "git.loafle.net/overflow/overflow_service_websocket/pool/grpc"
"git.loafle.net/overflow/overflow_service_websocket/protocol"
)
type Request struct {
Method string `json:"method"`
Params []string `json:"params,omitempty"`
}
type Response struct {
Result string `json:"result,omitempty"`
}
// NewHandler returns a new JSON RPC handler.
func NewHandler() protocol.Handler {
c := config.GetConfig().GRpc
addr := c.Addr
servicePool, err := grpcPool.New(1, 5,
func(conn *grpc.ClientConn) (interface{}, error) {
return serverGrpc.NewOverflowApiServerClient(conn), nil
},
func() (*grpc.ClientConn, error) {
return grpc.Dial(addr, grpc.WithInsecure())
},
)
if nil != err {
log.Fatal(err)
return nil
}
h := &handler{
pool: servicePool,
}
return h
}
// Codec creates a CodecRequest to process each request.
type handler struct {
pool pool.Pool
}
// NewRequest returns a CodecRequest.
func (h *handler) Handle(data []byte) ([]byte, *protocol.Error) {
req := Request{}
err := json.Unmarshal(data, &req)
if nil != err {
return nil, protocol.NewError(protocol.E_PARSE, err, nil)
}
parts := strings.Split(req.Method, ".")
si := &serverGrpc.ServerInput{
Target: parts[0],
Method: parts[1],
Params: req.Params,
}
c, err := h.pool.Get()
if nil != err {
return nil, protocol.NewError(protocol.E_INTERNAL, err, nil)
}
defer h.pool.Put(c)
client := c.(serverGrpc.OverflowApiServerClient)
out, err := client.Exec(context.Background(), si)
if err != nil {
return nil, protocol.NewError(protocol.E_SERVER, err, err)
}
res := &Response{
Result: out.Result,
}
r, err := json.Marshal(res)
if err != nil {
return nil, protocol.NewError(protocol.E_INTERNAL, err, nil)
}
return r, nil
}

View File

@ -1,15 +1,17 @@
package server
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"strings"
"sync"
"time"
"git.loafle.net/overflow/overflow_service_websocket/protocol"
serverGrpc "git.loafle.net/overflow/overflow_api_server/golang"
"github.com/gorilla/websocket"
)
@ -168,17 +170,26 @@ func (c *client) onMessageReceived(messageType int, r io.Reader) {
log.Println(err)
}
h := c.server.ProtocolHandler(req.Protocol)
if nil == h {
parts := strings.Split(req.Method, ".")
si := &serverGrpc.ServerInput{
Target: parts[0],
Method: parts[1],
Params: req.Params,
}
hr, perr := h.Handle(*req.Body)
if perr != nil {
c.writeError(req, perr)
grpcPool, err := c.server.GetGRPCPool().Get()
if nil != err {
c.writeError(req, NewError(E_INTERNAL, err, nil))
}
defer c.server.GetGRPCPool().Put(grpcPool)
grpcClient := grpcPool.(serverGrpc.OverflowApiServerClient)
out, err := grpcClient.Exec(context.Background(), si)
if err != nil {
c.writeError(req, NewError(E_SERVER, err, err))
}
c.writeResult(req, hr)
c.writeResult(req, out.Result)
}
func (c *client) fireError(err error) {
@ -187,7 +198,7 @@ func (c *client) fireError(err error) {
}
}
func (c *client) writeResult(r *Request, data []byte) {
func (c *client) writeResult(r *Request, result string) {
c.writeMTX.Lock()
if writeTimeout := c.server.GetOptions().WriteTimeout; writeTimeout > 0 {
// set the write deadline based on the configuration
@ -195,28 +206,27 @@ func (c *client) writeResult(r *Request, data []byte) {
log.Println(fmt.Errorf("%v", err))
}
raw := json.RawMessage(data)
res := &Response{
Protocol: r.Protocol,
ID: r.ID,
Body: &raw,
Result: &result,
Error: nil,
}
jRes, err := json.Marshal(res)
if nil != err {
log.Println(fmt.Errorf("%v", err))
}
err = c.conn.WriteMessage(c.messageType, jRes)
c.writeMTX.Unlock()
if nil != err {
c.Disconnect()
_ = c.Disconnect()
}
}
func (c *client) writeError(r *Request, perr *protocol.Error) {
func (c *client) writeError(r *Request, perr *Error) {
c.writeMTX.Lock()
if writeTimeout := c.server.GetOptions().WriteTimeout; writeTimeout > 0 {
// set the write deadline based on the configuration
@ -227,18 +237,19 @@ func (c *client) writeError(r *Request, perr *protocol.Error) {
res := &Response{
Protocol: r.Protocol,
ID: r.ID,
Body: nil,
Result: nil,
Error: perr,
}
jRes, err := json.Marshal(res)
if nil != err {
log.Println(fmt.Errorf("%v", err))
}
err = c.conn.WriteMessage(c.messageType, jRes)
c.writeMTX.Unlock()
if nil != err {
c.Disconnect()
_ = c.Disconnect()
}
}

View File

@ -2,21 +2,49 @@ package server
import (
"encoding/json"
"git.loafle.net/overflow/overflow_service_websocket/protocol"
"errors"
)
type ErrorCode int
const (
E_PARSE ErrorCode = -32700
E_INVALID_REQ ErrorCode = -32600
E_NOT_FOUND_METHOD ErrorCode = -32601
E_INVALID_PARAMS ErrorCode = -32602
E_INTERNAL ErrorCode = -32603
E_SERVER ErrorCode = -32000
)
var ErrNullResult = errors.New("result is null")
type Error struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// Request is protocol which Websocket Request
type Request struct {
Protocol string `json:"protocol"`
ID *json.RawMessage `json:"id"`
Body *json.RawMessage `json:"body"`
Method string `json:"method"`
Params []string `json:"params,omitempty"`
ID *json.RawMessage `json:"id,omitempty"`
}
// Response is protocol which Websocket Response
type Response struct {
Protocol string `json:"protocol"`
ID *json.RawMessage `json:"id"`
Error *protocol.Error `json:"error,omitempty"`
Body *json.RawMessage `json:"body"`
Result *string `json:"result,omitempty"`
Error *Error `json:"error,omitempty"`
ID *json.RawMessage `json:"id,omitempty"`
}
func NewError(code ErrorCode, err error, data interface{}) *Error {
e := &Error{
Code: code,
Message: err.Error(),
Data: data,
}
return e
}

View File

@ -4,11 +4,14 @@ import (
"fmt"
"log"
"net/http"
"strings"
"sync"
"git.loafle.net/overflow/overflow_service_websocket/protocol"
serverGrpc "git.loafle.net/overflow/overflow_api_server/golang"
"git.loafle.net/overflow/overflow_service_websocket/config"
"git.loafle.net/overflow/overflow_service_websocket/pool"
grpcPool "git.loafle.net/overflow/overflow_service_websocket/pool/grpc"
"github.com/gorilla/websocket"
"google.golang.org/grpc"
)
type (
@ -20,8 +23,7 @@ type (
// listens on the config's port, the critical part is the event OnConnection
type Server interface {
GetOptions() *Options
RegistProtocol(protocol string, h protocol.Handler)
ProtocolHandler(protocol string) protocol.Handler
GetGRPCPool() pool.Pool
HTTPHandler() http.Handler
HandleConnection(*http.Request, Connection)
OnConnection(cb OnConnectionFunc)
@ -35,13 +37,9 @@ type server struct {
clients map[string]Client
clientMTX sync.Mutex
onConnectionListeners []OnConnectionFunc
protocols map[string]protocol.Handler
grpcPool pool.Pool
}
var _ Server = &server{}
var defaultServer = newServer(nil)
// server implementation
// New creates a websocket server and returns it
@ -55,7 +53,6 @@ func newServer(o *Options) Server {
s := &server{
clients: make(map[string]Client, 100),
onConnectionListeners: make([]OnConnectionFunc, 0),
protocols: make(map[string]protocol.Handler, 0),
}
if nil == o {
@ -65,37 +62,31 @@ func newServer(o *Options) Server {
o.Validate()
s.options = o
pool, err := grpcPool.New(1, 5,
func(conn *grpc.ClientConn) (interface{}, error) {
return serverGrpc.NewOverflowApiServerClient(conn), nil
},
func() (*grpc.ClientConn, error) {
return grpc.Dial(config.GetConfig().GRpc.Addr, grpc.WithInsecure())
},
)
if nil != err {
log.Fatal(err)
return nil
}
s.grpcPool = pool
return s
}
func RegistProtocol(protocol string, h protocol.Handler) {
defaultServer.RegistProtocol(protocol, h)
}
func (s *server) RegistProtocol(protocol string, h protocol.Handler) {
s.protocols[strings.ToLower(protocol)] = h
}
func ProtocolHandler(protocol string) protocol.Handler {
return defaultServer.ProtocolHandler(protocol)
}
func (s *server) ProtocolHandler(protocol string) protocol.Handler {
return s.protocols[protocol]
}
// GetOptions is function that get option values
func GetOptions() *Options {
return defaultServer.GetOptions()
}
func (s *server) GetOptions() *Options {
return s.options
}
// Handler is the function that used on http request
func HTTPHandler() http.Handler {
return defaultServer.HTTPHandler()
func (s *server) GetGRPCPool() pool.Pool {
return s.grpcPool
}
func (s *server) HTTPHandler() http.Handler {
@ -118,10 +109,6 @@ func (s *server) HTTPHandler() http.Handler {
})
}
func HandleConnection(r *http.Request, conn Connection) {
defaultServer.HandleConnection(r, conn)
}
func (s *server) HandleConnection(r *http.Request, conn Connection) {
clientID := s.options.IDGenerator(r)
c := newClient(s, r, conn, clientID)
@ -138,39 +125,19 @@ func (s *server) HandleConnection(r *http.Request, conn Connection) {
c.initialize()
}
// OnConnection is function that add the callback when client is connected to default Server
func OnConnection(cb OnConnectionFunc) {
defaultServer.OnConnection(cb)
}
func (s *server) OnConnection(cb OnConnectionFunc) {
s.onConnectionListeners = append(s.onConnectionListeners, cb)
}
// IsConnected is function that check client is connect
func IsConnected(clientID string) bool {
return defaultServer.IsConnected(clientID)
}
func (s *server) IsConnected(clientID string) bool {
soc := s.clients[clientID]
return soc != nil
}
// GetClient is function that return client instance
func GetClient(clientID string) Client {
return defaultServer.GetClient(clientID)
}
func (s *server) GetClient(clientID string) Client {
return s.clients[clientID]
}
// Disconnect is function that disconnect a client
func Disconnect(clientID string) error {
return defaultServer.Disconnect(clientID)
}
func (s *server) Disconnect(clientID string) error {
c := s.clients[clientID]