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
|
- google
|
||||||
- package: google.golang.org/grpc
|
- package: google.golang.org/grpc
|
||||||
- package: gopkg.in/yaml.v2
|
- package: gopkg.in/yaml.v2
|
||||||
|
- package: github.com/gorilla/websocket
|
||||||
|
version: v1.2.0
|
||||||
testImport:
|
testImport:
|
||||||
- package: github.com/google/uuid
|
- package: github.com/google/uuid
|
||||||
- package: github.com/stretchr/testify
|
- package: github.com/stretchr/testify
|
||||||
subpackages:
|
subpackages:
|
||||||
- assert
|
- 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