forked from henvic/gosocketio
/
websocket.go
153 lines (116 loc) · 3.62 KB
/
websocket.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package websocket
import (
"context"
"errors"
"io/ioutil"
"net/http"
"time"
ws "github.com/gorilla/websocket"
)
const (
// PingInterval for the connection
PingInterval = 25 * time.Second
// PingTimeout for the connection
PingTimeout = 60 * time.Second
// ReadTimeout for the connection
ReadTimeout = 60 * time.Second
// SendTimeout for the connection
SendTimeout = 60 * time.Second
// BufferSize for the connection
BufferSize = 1024 * 32
)
var (
// ErrUnsupportedBinaryMessage is returned when trying to send an unsupported binary message
ErrUnsupportedBinaryMessage = errors.New("sending binary messages is not supported")
// ErrBadBuffer is used when there is an error while reading the buffer
ErrBadBuffer = errors.New("error while reading buffer")
// ErrPacketType is used when a packet comes with an unexpected format
ErrPacketType = errors.New("wrong packet type")
)
// Connection to websocket
type Connection struct {
socket *ws.Conn
transport *Transport
}
// GetMessage on connection
func (c *Connection) GetMessage() (data []byte, err error) {
c.socket.SetReadDeadline(time.Now().Add(c.transport.ReadTimeout))
msgType, reader, err := c.socket.NextReader()
if err != nil {
return data, err
}
if msgType != ws.TextMessage {
return data, ErrUnsupportedBinaryMessage
}
data, err = ioutil.ReadAll(reader)
if err != nil {
return data, ErrBadBuffer
}
if len(data) == 0 {
return data, ErrPacketType
}
return data, nil
}
// WriteMessage to the socket
func (c *Connection) WriteMessage(message string) error {
c.socket.SetWriteDeadline(time.Now().Add(c.transport.SendTimeout))
writer, err := c.socket.NextWriter(ws.TextMessage)
if err != nil {
return err
}
if _, err := writer.Write([]byte(message)); err != nil {
return err
}
return writer.Close()
}
// Close the connection
func (c *Connection) Close() error {
return c.socket.Close()
}
// PingParams gets the ping and pong interval and timeout
func (c *Connection) PingParams() (interval, timeout time.Duration) {
return c.transport.PingInterval, c.transport.PingTimeout
}
// Transport for the websocket
type Transport struct {
PingInterval time.Duration
PingTimeout time.Duration
ReadTimeout time.Duration
SendTimeout time.Duration
BufferSize int
Dialer ws.Dialer
RequestHeader http.Header
}
// NewTransport creates a new WebSocket connection transport
func NewTransport() *Transport {
t := &Transport{
PingInterval: PingInterval,
PingTimeout: PingTimeout,
ReadTimeout: ReadTimeout,
SendTimeout: SendTimeout,
BufferSize: BufferSize,
RequestHeader: http.Header{},
}
t.RequestHeader.Add("User-Agent", "socketio client; (+https://github.com/wedeploy/gosocket.io)")
return t
}
// Connect to web socket with default gorilla websocket dialer
func (wst *Transport) Connect(url string) (conn *Connection, err error) {
return wst.ConnectContext(context.Background(), url)
}
// ConnectContext to web socket with default gorilla websocket dialer
func (wst *Transport) ConnectContext(ctx context.Context, url string) (conn *Connection, err error) {
return wst.ConnectDialerContext(ctx, *ws.DefaultDialer, url)
}
// ConnectDialer to web socket
func (wst *Transport) ConnectDialer(dialer ws.Dialer, url string) (conn *Connection, err error) {
return wst.ConnectDialerContext(context.Background(), dialer, url)
}
// ConnectDialerContext to web socket
func (wst *Transport) ConnectDialerContext(ctx context.Context, dialer ws.Dialer, url string) (conn *Connection, err error) {
socket, _, err := dialer.DialContext(ctx, url, wst.RequestHeader)
if err != nil {
return nil, err
}
return &Connection{socket, wst}, nil
}