WebSocket client
This commit is contained in:
parent
53f87c2c80
commit
abaf9c217a
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
// Specifies Lint tool name.
|
||||
"go.lintTool": "gometalinter",
|
||||
|
||||
// Flags to pass to Lint tool (e.g. ["-min_confidence=.8"])
|
||||
"go.lintFlags": [
|
||||
"--config=${workspaceRoot}/golint.json"
|
||||
]
|
||||
|
||||
}
|
@ -21,10 +21,10 @@ import:
|
||||
- google
|
||||
- package: google.golang.org/grpc
|
||||
- package: gopkg.in/yaml.v2
|
||||
- package: github.com/gorilla/websocket
|
||||
version: v1.2.0
|
||||
testImport:
|
||||
- package: github.com/google/uuid
|
||||
- package: github.com/stretchr/testify
|
||||
subpackages:
|
||||
- assert
|
||||
|
||||
|
||||
|
39
golint.json
Normal file
39
golint.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"DisableAll": true,
|
||||
"Enable": [
|
||||
"aligncheck",
|
||||
"deadcode",
|
||||
"dupl",
|
||||
"errcheck",
|
||||
"gas",
|
||||
"goconst",
|
||||
"gocyclo",
|
||||
"gofmt",
|
||||
"goimports",
|
||||
"golint",
|
||||
"gotype",
|
||||
"ineffassign",
|
||||
"interfacer",
|
||||
"lll",
|
||||
"megacheck",
|
||||
"misspell",
|
||||
"structcheck",
|
||||
"test",
|
||||
"testify",
|
||||
"unconvert",
|
||||
"varcheck",
|
||||
"vet",
|
||||
"vetshadow"
|
||||
],
|
||||
"Aggregate": true,
|
||||
"Concurrency": 16,
|
||||
"Cyclo": 60,
|
||||
"Deadline": "60s",
|
||||
"DuplThreshold": 50,
|
||||
"EnableGC": true,
|
||||
"LineLength": 120,
|
||||
"MinConfidence": 0.8,
|
||||
"MinOccurrences": 3,
|
||||
"MinConstLength": 3,
|
||||
"Sort": ["severity"]
|
||||
}
|
23
websocket/options.go
Normal file
23
websocket/options.go
Normal file
@ -0,0 +1,23 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Options interface {
|
||||
}
|
||||
|
||||
type options struct {
|
||||
OnError func(res http.ResponseWriter, req *http.Request, status int, reason error)
|
||||
OnCheckOrigin func(req *http.Request) bool
|
||||
WriteTimeout time.Duration
|
||||
ReadTimeout time.Duration
|
||||
PongTimeout time.Duration
|
||||
PingTimeout time.Duration
|
||||
PingPeriod time.Duration
|
||||
MaxMessageSize int64
|
||||
BinaryMessage bool
|
||||
ReadBufferSize int
|
||||
WriteBufferSize int
|
||||
}
|
30
websocket/protocol/error.go
Normal file
30
websocket/protocol/error.go
Normal file
@ -0,0 +1,30 @@
|
||||
package protocol
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrorCode is type when used to communicate with WebSocket RPC
|
||||
type ErrorCode int
|
||||
|
||||
const (
|
||||
// EParse is error code that is invalid json
|
||||
EParse ErrorCode = -32700
|
||||
// EInvalidReq is error code that is invalid request
|
||||
EInvalidReq ErrorCode = -32600
|
||||
// ENotFoundMethod is error code that is not exist method
|
||||
ENotFoundMethod ErrorCode = -32601
|
||||
// EInvalidParams is error code that is invalid parameters
|
||||
EInvalidParams ErrorCode = -32602
|
||||
// EInternal is error code that is internel error
|
||||
EInternal ErrorCode = -32603
|
||||
// EServer is error code that is server error
|
||||
EServer ErrorCode = -32000
|
||||
)
|
||||
|
||||
var ErrNullResult = errors.New("result is null")
|
||||
|
||||
// Error is error struct when used to communicate with WebSocket RPC
|
||||
type Error struct {
|
||||
Code ErrorCode `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
6
websocket/protocol/header.go
Normal file
6
websocket/protocol/header.go
Normal file
@ -0,0 +1,6 @@
|
||||
package protocol
|
||||
|
||||
// Header is struct when used to communicate with WebSocket RPC
|
||||
type Header struct {
|
||||
Protocol string `json:"protocol"`
|
||||
}
|
8
websocket/protocol/notification.go
Normal file
8
websocket/protocol/notification.go
Normal file
@ -0,0 +1,8 @@
|
||||
package protocol
|
||||
|
||||
// Notification is struct when used to communicate with WebSocket RPC
|
||||
type Notification struct {
|
||||
Header
|
||||
Method string `json:"method"`
|
||||
Params []string `json:"params,omitempty"`
|
||||
}
|
7
websocket/protocol/request.go
Normal file
7
websocket/protocol/request.go
Normal file
@ -0,0 +1,7 @@
|
||||
package protocol
|
||||
|
||||
// Request is struct when used to communicate with WebSocket RPC
|
||||
type Request struct {
|
||||
Notification
|
||||
ID int64 `json:"id"`
|
||||
}
|
9
websocket/protocol/response.go
Normal file
9
websocket/protocol/response.go
Normal file
@ -0,0 +1,9 @@
|
||||
package protocol
|
||||
|
||||
// Response is struct when used to communicate with WebSocket RPC
|
||||
type Response struct {
|
||||
Header
|
||||
Result *string `json:"result,omitempty"`
|
||||
Error *Error `json:"error,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
137
websocket/rpc.go
Normal file
137
websocket/rpc.go
Normal file
@ -0,0 +1,137 @@
|
||||
package websocket
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
protocol "git.loafle.net/overflow/overflow_probe/websocket/protocol"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
protocolName string = "1.0"
|
||||
)
|
||||
|
||||
type CallCallback func(interface{}, *protocol.Error)
|
||||
|
||||
type WebSocketRPC interface {
|
||||
Call(cb CallCallback, method string, params []string)
|
||||
Send(method string, params []string)
|
||||
}
|
||||
|
||||
type webSocketRPC struct {
|
||||
conn *websocket.Conn
|
||||
messageType int
|
||||
writeMTX sync.Mutex
|
||||
requestID int64
|
||||
requestQueue map[int64]CallCallback
|
||||
}
|
||||
|
||||
// New creates a websocket rpc client and returns it
|
||||
func New(serverURL string) WebSocketRPC {
|
||||
return newInstance(serverURL)
|
||||
}
|
||||
|
||||
func newInstance(serverURL string) WebSocketRPC {
|
||||
var dialer *websocket.Dialer
|
||||
|
||||
conn, _, err := dialer.Dial(serverURL, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
w := &webSocketRPC{
|
||||
conn: conn,
|
||||
requestID: 0,
|
||||
requestQueue: make(map[int64]CallCallback),
|
||||
}
|
||||
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) readHandler() {
|
||||
for {
|
||||
// messageType, data, err := c.conn.ReadMessage()
|
||||
messageType, r, err := w.conn.NextReader()
|
||||
if err != nil {
|
||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
||||
|
||||
}
|
||||
break
|
||||
} else {
|
||||
w.onMessageReceived(messageType, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) onMessageReceived(messageType int, r io.Reader) {
|
||||
res := new(protocol.Response)
|
||||
err := json.NewDecoder(r).Decode(res)
|
||||
if err != nil {
|
||||
// Check message is Notification
|
||||
noti := new(protocol.Notification)
|
||||
err = json.NewDecoder(r).Decode(noti)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
w.onNotificationReceived(noti)
|
||||
}
|
||||
|
||||
w.onResponseReceived(res)
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) onResponseReceived(r *protocol.Response) {
|
||||
cb := w.requestQueue[r.ID]
|
||||
|
||||
cb(r.Result, r.Error)
|
||||
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) onNotificationReceived(n *protocol.Notification) {
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) Call(cb CallCallback, method string, params []string) {
|
||||
w.writeMTX.Lock()
|
||||
w.requestID++
|
||||
rID := w.requestID
|
||||
|
||||
req := new(protocol.Request)
|
||||
req.Protocol = protocolName
|
||||
req.Method = method
|
||||
req.Params = params
|
||||
req.ID = rID
|
||||
|
||||
jReq, err := json.Marshal(req)
|
||||
if nil != err {
|
||||
log.Println(fmt.Errorf("%v", err))
|
||||
}
|
||||
err = w.conn.WriteMessage(w.messageType, jReq)
|
||||
w.writeMTX.Unlock()
|
||||
|
||||
if nil != err {
|
||||
}
|
||||
w.requestQueue[rID] = cb
|
||||
}
|
||||
|
||||
func (w *webSocketRPC) Send(method string, params []string) {
|
||||
w.writeMTX.Lock()
|
||||
|
||||
req := new(protocol.Request)
|
||||
req.Protocol = protocolName
|
||||
req.Method = method
|
||||
req.Params = params
|
||||
|
||||
jReq, err := json.Marshal(req)
|
||||
if nil != err {
|
||||
log.Println(fmt.Errorf("%v", err))
|
||||
}
|
||||
err = w.conn.WriteMessage(w.messageType, jReq)
|
||||
w.writeMTX.Unlock()
|
||||
|
||||
if nil != err {
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user