ing
This commit is contained in:
parent
97f3e920f1
commit
0d428d20c0
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
@ -2,7 +2,20 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch",
|
||||
"name": "Debug",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"remotePath": "",
|
||||
"port": 2345,
|
||||
"host": "127.0.0.1",
|
||||
"program": "${workspaceRoot}/main.go",
|
||||
"env": {},
|
||||
"args": [],
|
||||
"showLog": true
|
||||
},
|
||||
{
|
||||
"name": "File Debug",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
@ -14,5 +27,6 @@
|
||||
"args": [],
|
||||
"showLog": true
|
||||
}
|
||||
|
||||
]
|
||||
}
|
@ -1,4 +1,9 @@
|
||||
{
|
||||
"server": {
|
||||
"ip": "localhost",
|
||||
"port": 18081,
|
||||
"tls": false
|
||||
},
|
||||
"websocket": {
|
||||
"writeTimeout": 0,
|
||||
"readTimeout": 0,
|
||||
@ -9,8 +14,8 @@
|
||||
"writeBufferSize": 4096
|
||||
},
|
||||
"gRpc": {
|
||||
"host": "localhost",
|
||||
"port": 8000,
|
||||
"ip": "localhost",
|
||||
"port": 50006,
|
||||
"tls": false,
|
||||
"pool": {
|
||||
"initialCapacity": 30,
|
||||
|
13
config.yml
13
config.yml
@ -1,13 +0,0 @@
|
||||
|
||||
websocket:
|
||||
writeTimeout: 0
|
||||
readTimeout: 0
|
||||
pongTimeout: 60
|
||||
pingTimeout: 10
|
||||
maxMessageSize: 1024
|
||||
readBufferSize: 4096
|
||||
writeBufferSize: 4096
|
||||
gRpc:
|
||||
host: localhost
|
||||
port: 8000
|
||||
tls: false
|
@ -7,31 +7,37 @@ import (
|
||||
var _config *Config
|
||||
|
||||
type Config struct {
|
||||
Server ServerConfig `json:"server"`
|
||||
Websocket WebsocketConfig `json:"websocket"`
|
||||
GRpc GRpcConfig `json:"gRpc"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Ip string `required:"true"`
|
||||
Port uint16 `required:"true"`
|
||||
Tls bool `default:"false"`
|
||||
}
|
||||
|
||||
type WebsocketConfig struct {
|
||||
WriteTimeout int8 `default:"0"`
|
||||
ReadTimeout int8 `default:"0"`
|
||||
PongTimeout int8 `default:"60"`
|
||||
PingTimeout int8 `default:"10"`
|
||||
MaxMessageSize int64 `default:"1024"`
|
||||
ReadBufferSize int `default:"4096"`
|
||||
WriteBufferSize int `default:"4096"`
|
||||
WriteTimeout uint8 `default:"0"`
|
||||
ReadTimeout uint8 `default:"0"`
|
||||
PongTimeout uint8 `default:"60"`
|
||||
PingTimeout uint8 `default:"10"`
|
||||
MaxMessageSize int64 `default:"1024"`
|
||||
ReadBufferSize int `default:"4096"`
|
||||
WriteBufferSize int `default:"4096"`
|
||||
UseBinaryMessage bool `required:"false" default:"false"`
|
||||
}
|
||||
|
||||
type GRpcConfig struct {
|
||||
Host string `required:"true"`
|
||||
Port int16 `required:"true"`
|
||||
Tls bool `default:"false"`
|
||||
ServerConfig
|
||||
Pool PoolConfig `json:"pool"`
|
||||
}
|
||||
|
||||
type PoolConfig struct {
|
||||
InitialCapacity int `defalut:"1"`
|
||||
MaxCapacity int `defalut:"1"`
|
||||
IncreaseCapacity int `defalut:"1"`
|
||||
InitialCapacity uint8 `defalut:"1"`
|
||||
MaxCapacity uint8 `defalut:"1"`
|
||||
IncreaseCapacity uint8 `defalut:"1"`
|
||||
}
|
||||
|
||||
func InitConfig(path string) error {
|
||||
|
@ -18,5 +18,5 @@ func TestLoadConfig(t *testing.T) {
|
||||
}
|
||||
c := GetConfig()
|
||||
|
||||
log.Println(c.Websocket.MaxMessageSize)
|
||||
log.Println(c.Server.Ip)
|
||||
}
|
||||
|
@ -19,3 +19,5 @@ import:
|
||||
- package: gopkg.in/yaml.v2
|
||||
- package: github.com/BurntSushi/toml
|
||||
version: ^0.3.0
|
||||
- package: github.com/valyala/fasthttp
|
||||
version: ^20160617.0.0
|
||||
|
57
main.go
57
main.go
@ -1,28 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
host = "localhost:8080"
|
||||
const (
|
||||
version = "1.0.0"
|
||||
website = "https://www.overflow.cloud"
|
||||
banner = `
|
||||
|
||||
██████╗ ██╗ ██╗███████╗██████╗ ███████╗██╗ ██████╗ ██╗ ██╗
|
||||
██╔═══██╗██║ ██║██╔════╝██╔══██╗██╔════╝██║ ██╔═══██╗██║ ██║
|
||||
██║ ██║██║ ██║█████╗ ██████╔╝█████╗ ██║ ██║ ██║██║ █╗ ██║
|
||||
██║ ██║╚██╗ ██╔╝██╔══╝ ██╔══██╗██╔══╝ ██║ ██║ ██║██║███╗██║
|
||||
╚██████╔╝ ╚████╔╝ ███████╗██║ ██║██║ ███████╗╚██████╔╝╚███╔███╔╝
|
||||
╚═════╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝ ╚═════╝ ╚══╝╚══╝
|
||||
|
||||
`
|
||||
)
|
||||
|
||||
func main() {
|
||||
ws := server.New(server.Options{})
|
||||
|
||||
// Initialize config
|
||||
config := loadConfig()
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", config.Server.Ip, config.Server.Port)
|
||||
useTLS := config.Server.Tls
|
||||
sConfig := server.NewOptions(&config.Websocket)
|
||||
// Print banner
|
||||
log.Println(banner)
|
||||
|
||||
// Config TLS
|
||||
|
||||
ws := server.New(sConfig)
|
||||
ws.RegistProtocol("jsonrpc", jsonrpc.NewHandler())
|
||||
ws.OnConnection(func(c server.Client) {
|
||||
c.OnDisconnect(func(Client) {
|
||||
|
||||
log.Println("Client have been connected")
|
||||
c.OnDisconnect(func(c server.Client) {
|
||||
log.Println("Client have been disconnected")
|
||||
})
|
||||
})
|
||||
|
||||
http.HandleFunc("/ws", ws.HTTPHandler())
|
||||
http.Handle("/ws", ws.HTTPHandler())
|
||||
log.Printf("Address: %s, UseTLS: %t", addr, useTLS)
|
||||
|
||||
// ws.OnConnection(handleWebsocketConnection)
|
||||
http.ListenAndServe(addr, nil)
|
||||
|
||||
http.ListenAndServe(host, nil)
|
||||
}
|
||||
|
||||
func loadConfig() *config.Config {
|
||||
os.Chdir("./")
|
||||
wd, _ := os.Getwd()
|
||||
path := filepath.Join(wd, "config.json")
|
||||
|
||||
err := config.InitConfig(path)
|
||||
if nil != err {
|
||||
log.Fatalln("Config error")
|
||||
}
|
||||
return config.GetConfig()
|
||||
}
|
||||
|
@ -142,6 +142,8 @@ func (p *grpcPool) create() (interface{}, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Client of GRPC is created")
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,12 @@ 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
|
||||
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")
|
||||
|
@ -2,6 +2,7 @@ package jsonrpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
@ -9,15 +10,12 @@ import (
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
host = "localhost:8080"
|
||||
)
|
||||
|
||||
type Request struct {
|
||||
Method string `json:"method"`
|
||||
Params []string `json:"params,omitempty"`
|
||||
@ -29,12 +27,16 @@ type Response struct {
|
||||
|
||||
// NewHandler returns a new JSON RPC handler.
|
||||
func NewHandler() protocol.Handler {
|
||||
servicePool, err := grpcPool.New(10, 30,
|
||||
c := config.GetConfig().GRpc
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", c.Ip, c.Port)
|
||||
|
||||
servicePool, err := grpcPool.New(1, 5,
|
||||
func(conn *grpc.ClientConn) (interface{}, error) {
|
||||
return serverGrpc.NewOverflowApiServerClient(conn), nil
|
||||
},
|
||||
func() (*grpc.ClientConn, error) {
|
||||
return grpc.Dial(host, grpc.WithInsecure())
|
||||
return grpc.Dial(addr, grpc.WithInsecure())
|
||||
},
|
||||
)
|
||||
if nil != err {
|
||||
@ -81,7 +83,6 @@ func (h *handler) Handle(data []byte) ([]byte, *protocol.Error) {
|
||||
}
|
||||
|
||||
res := &Response{
|
||||
ID: req.ID,
|
||||
Result: out.Result,
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.loafle.net/overflow/overflow_service_websocket/config"
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
@ -31,22 +32,6 @@ var (
|
||||
DefaultIDGenerator = func(*http.Request) string { return uuid.NewV4().String() }
|
||||
)
|
||||
|
||||
type (
|
||||
// OptionSetter sets a configuration field to the websocket config
|
||||
// used to help developers to write less and configure only what they really want and nothing else
|
||||
OptionSetter interface {
|
||||
Set(o *Options)
|
||||
}
|
||||
|
||||
// OptionSet implements the OptionSetter
|
||||
OptionSet func(o *Options)
|
||||
)
|
||||
|
||||
// Set is the func which makes the OptionSet an OptionSetter, this is used mostly
|
||||
func (os OptionSet) Set(o *Options) {
|
||||
os(o)
|
||||
}
|
||||
|
||||
// Options is configuration of the websocket server
|
||||
type Options struct {
|
||||
OnError func(res http.ResponseWriter, req *http.Request, status int, reason error)
|
||||
@ -63,6 +48,24 @@ type Options struct {
|
||||
IDGenerator func(*http.Request) string
|
||||
}
|
||||
|
||||
func NewOptions(c *config.WebsocketConfig) *Options {
|
||||
o := &Options{
|
||||
WriteTimeout: time.Duration(c.WriteTimeout) * time.Second,
|
||||
ReadTimeout: time.Duration(c.ReadTimeout) * time.Second,
|
||||
PongTimeout: time.Duration(c.PongTimeout) * time.Second,
|
||||
PingTimeout: time.Duration(c.PingTimeout) * time.Second,
|
||||
MaxMessageSize: c.MaxMessageSize,
|
||||
BinaryMessage: c.UseBinaryMessage,
|
||||
ReadBufferSize: c.ReadBufferSize,
|
||||
WriteBufferSize: c.WriteBufferSize,
|
||||
}
|
||||
o.Validate()
|
||||
o.PongTimeout = o.PongTimeout * time.Second
|
||||
o.PingTimeout = o.PingTimeout * time.Second
|
||||
o.PingPeriod = (o.PingTimeout * 9) / 10
|
||||
return o
|
||||
}
|
||||
|
||||
// Set is the func which makes the OptionSet an OptionSetter, this is used mostly
|
||||
func (o *Options) Set(main *Options) {
|
||||
main.OnError = o.OnError
|
||||
@ -79,103 +82,6 @@ func (o *Options) Set(main *Options) {
|
||||
main.IDGenerator = o.IDGenerator
|
||||
}
|
||||
|
||||
// OnError sets the error handler
|
||||
func OnError(val func(res http.ResponseWriter, req *http.Request, status int, reason error)) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.OnError = val
|
||||
}
|
||||
}
|
||||
|
||||
// OnCheckOrigin sets a handler which will check if different origin(domains) are allowed to contact with
|
||||
// the websocket server
|
||||
func OnCheckOrigin(val func(req *http.Request) bool) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.OnCheckOrigin = val
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTimeout time allowed to write a message to the connection.
|
||||
// Default value is 15 * time.Second
|
||||
func WriteTimeout(val time.Duration) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.WriteTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// ReadTimeout time allowed to read a message from the connection.
|
||||
// Default value is 15 * time.Second
|
||||
func ReadTimeout(val time.Duration) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.ReadTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// PongTimeout allowed to read the next pong message from the connection
|
||||
// Default value is 60 * time.Second
|
||||
func PongTimeout(val time.Duration) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.PongTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// PingTimeout allowed to send the ping message to the connection
|
||||
// Default value is 10 * time.Second
|
||||
func PingTimeout(val time.Duration) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.PingTimeout = val
|
||||
}
|
||||
}
|
||||
|
||||
// PingPeriod send ping messages to the connection with this period. Must be less than PongTimeout
|
||||
// Default value is (PongTimeout * 9) / 10
|
||||
func PingPeriod(val time.Duration) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.PingPeriod = val
|
||||
}
|
||||
}
|
||||
|
||||
// MaxMessageSize max message size allowed from connection
|
||||
// Default value is 1024
|
||||
func MaxMessageSize(val int64) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.MaxMessageSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// BinaryMessage set it to true in order to denotes binary data messages instead of utf-8 text
|
||||
// compatible if you wanna use the Connection's EmitMessage to send a custom binary data to the client,
|
||||
// like a native server-client communication.
|
||||
// defaults to false
|
||||
func BinaryMessage(val bool) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.BinaryMessage = val
|
||||
}
|
||||
}
|
||||
|
||||
// ReadBufferSize is the buffer size for the underline reader
|
||||
func ReadBufferSize(val int) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.ReadBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// WriteBufferSize is the buffer size for the underline writer
|
||||
func WriteBufferSize(val int) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.WriteBufferSize = val
|
||||
}
|
||||
}
|
||||
|
||||
// IDGenerator used to create (and later on, set)
|
||||
// an ID for each incoming websocket connections (clients).
|
||||
// The request is an argument which you can use to generate the ID (from headers for example).
|
||||
// If empty then the ID is generated by func: uuid.NewV4().String()
|
||||
func IDGenerator(val func(*http.Request) string) OptionSet {
|
||||
return func(o *Options) {
|
||||
o.IDGenerator = val
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates the configuration
|
||||
func (o *Options) Validate() {
|
||||
|
||||
|
@ -6,12 +6,14 @@ import (
|
||||
"git.loafle.net/overflow/overflow_service_websocket/protocol"
|
||||
)
|
||||
|
||||
// Request is protocol which Websocket Request
|
||||
type Request struct {
|
||||
Protocol string `json:"protocol"`
|
||||
ID *json.RawMessage `json:"id"`
|
||||
Body *json.RawMessage `json:"body"`
|
||||
}
|
||||
|
||||
// Response is protocol which Websocket Response
|
||||
type Response struct {
|
||||
Protocol string `json:"protocol"`
|
||||
ID *json.RawMessage `json:"id"`
|
||||
|
@ -19,7 +19,6 @@ type (
|
||||
// Server is the websocket server,
|
||||
// listens on the config's port, the critical part is the event OnConnection
|
||||
type Server interface {
|
||||
SetOptions(...OptionSetter)
|
||||
GetOptions() *Options
|
||||
RegistProtocol(protocol string, h protocol.Handler)
|
||||
ProtocolHandler(protocol string) protocol.Handler
|
||||
@ -41,17 +40,17 @@ type server struct {
|
||||
|
||||
var _ Server = &server{}
|
||||
|
||||
var defaultServer = newServer()
|
||||
var defaultServer = newServer(nil)
|
||||
|
||||
// server implementation
|
||||
|
||||
// New creates a websocket server and returns it
|
||||
func New(setters ...OptionSetter) Server {
|
||||
return newServer(setters...)
|
||||
func New(o *Options) Server {
|
||||
return newServer(o)
|
||||
}
|
||||
|
||||
// newServer creates a websocket server and returns it
|
||||
func newServer(setters ...OptionSetter) Server {
|
||||
func newServer(o *Options) Server {
|
||||
|
||||
s := &server{
|
||||
clients: make(map[string]Client, 100),
|
||||
@ -59,7 +58,13 @@ func newServer(setters ...OptionSetter) Server {
|
||||
protocols: make(map[string]protocol.Handler, 0),
|
||||
}
|
||||
|
||||
s.SetOptions(setters...)
|
||||
if nil == o {
|
||||
o = &Options{}
|
||||
}
|
||||
|
||||
o.Validate()
|
||||
|
||||
s.options = o
|
||||
return s
|
||||
}
|
||||
|
||||
@ -79,19 +84,6 @@ func (s *server) ProtocolHandler(protocol string) protocol.Handler {
|
||||
return s.protocols[protocol]
|
||||
}
|
||||
|
||||
// SetOptions is function that set option values
|
||||
func SetOptions(setters ...OptionSetter) {
|
||||
defaultServer.SetOptions(setters...)
|
||||
}
|
||||
|
||||
func (s *server) SetOptions(setters ...OptionSetter) {
|
||||
for _, setter := range setters {
|
||||
setter.Set(s.options)
|
||||
}
|
||||
|
||||
s.options.Validate()
|
||||
}
|
||||
|
||||
// GetOptions is function that get option values
|
||||
func GetOptions() *Options {
|
||||
return defaultServer.GetOptions()
|
||||
|
Loading…
x
Reference in New Issue
Block a user