This commit is contained in:
crusader 2017-07-14 20:18:07 +09:00
parent 97f3e920f1
commit 0d428d20c0
14 changed files with 141 additions and 183 deletions

16
.vscode/launch.json vendored
View File

@ -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
}
]
}

View File

@ -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,

View File

@ -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

View File

@ -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 {

View File

@ -18,5 +18,5 @@ func TestLoadConfig(t *testing.T) {
}
c := GetConfig()
log.Println(c.Websocket.MaxMessageSize)
log.Println(c.Server.Ip)
}

BIN
debug Executable file

Binary file not shown.

View File

@ -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
View File

@ -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()
}

View File

@ -142,6 +142,8 @@ func (p *grpcPool) create() (interface{}, error) {
return nil, err
}
log.Println("Client of GRPC is created")
return c, nil
}

View File

@ -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")

View File

@ -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,
}

View File

@ -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() {

View File

@ -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"`

View File

@ -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()