-
Notifications
You must be signed in to change notification settings - Fork 5
/
conn.go
144 lines (120 loc) · 2.28 KB
/
conn.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
package websocket
import (
"encoding/json"
"github.com/gobwas/ws"
"net"
"net/url"
"sync"
"time"
)
// Conn websocket connection
type Conn struct {
id string
conn net.Conn
params url.Values
done chan bool
mu sync.Mutex
}
var pingHeader = ws.Header{
Fin: true,
OpCode: ws.OpPing,
Masked: false,
Length: 0,
}
var PingInterval = time.Second * 5
var TextMessage = false
// ID return an connection identifier (could be not unique)
func (c *Conn) ID() string {
return c.id
}
// Emit message to connection.
func (c *Conn) Emit(name string, data interface{}) error {
var msg = struct {
Name string `json:"name"`
Data interface{} `json:"data"`
}{
Name: name,
Data: data,
}
b, _ := json.Marshal(msg)
opCode := ws.OpBinary
if TextMessage {
opCode = ws.OpText
}
h := ws.Header{
Fin: true,
OpCode: opCode,
Masked: false,
Length: int64(len(b)),
}
return c.Write(h, b)
}
// Write byte array to connection.
func (c *Conn) Write(h ws.Header, b []byte) error {
c.mu.Lock()
defer c.mu.Unlock()
_ = c.conn.SetWriteDeadline(time.Now().Add(15000 * time.Millisecond))
err := ws.WriteHeader(c.conn, h)
if err != nil {
return err
}
_, err = c.conn.Write(b)
return err
}
// Send data to connection.
func (c *Conn) Send(data any) error {
var b []byte
switch data.(type) {
case []byte:
b = data.([]byte)
default:
b, _ = json.Marshal(data)
}
opCode := ws.OpBinary
if TextMessage {
opCode = ws.OpText
}
h := ws.Header{
Fin: true,
OpCode: opCode,
Masked: false,
Length: int64(len(b)),
}
err := c.Write(h, b)
return err
}
// Close closing websocket connection.
func (c *Conn) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == nil {
return nil
}
c.done <- true
err := c.conn.Close()
c.conn = nil
return err
}
// Param gets the value from url params.
// If there are no values associated with the key, Get returns
// the empty string. To access multiple values, use the map
// directly.
func (c *Conn) Param(key string) string {
return c.params.Get(key)
}
func (c *Conn) startPing() {
ticker := time.NewTicker(PingInterval)
go func() {
for {
select {
case <-ticker.C:
if err := c.Write(pingHeader, nil); err != nil {
_ = c.Close()
}
case <-c.done:
ticker.Stop()
return
}
}
}()
}