-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwebsocket-gorilla.go
117 lines (95 loc) · 2.92 KB
/
websocket-gorilla.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
package carrier
import (
"log"
"math/rand"
"net/url"
"sync"
"time"
"github.com/gorilla/websocket"
"github.com/jpillora/backoff"
)
// GorillaClient manage all websocket client actions
type GorillaClient struct {
connection *websocket.Conn
config *GorillaConfigModel
}
var (
// gorrilaClientSessionMapping singleton pattern
gorrilaClientSessionMapping = make(map[string]*GorillaClient)
// gorrilaClientMutex mutex for this service only
gorrilaClientMutex sync.Mutex
)
// NewGorillaClient init new instance
func NewGorillaClient(config *GorillaConfigModel) IWebsocket {
configHashed := hashObject(config)
currentGorrilaClientSession := gorrilaClientSessionMapping[configHashed]
if currentGorrilaClientSession == nil {
currentGorrilaClientSession = &GorillaClient{nil, nil}
url := url.URL{Scheme: config.Scheme, Host: config.URL, Path: config.Channel}
connection, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
if err != nil {
currentGorrilaClientSession.closeAndReConect()
} else {
currentGorrilaClientSession.connection = connection
currentGorrilaClientSession.config = config
gorrilaClientSessionMapping[configHashed] = currentGorrilaClientSession
log.Println("Websocket client: connected")
}
}
return currentGorrilaClientSession
}
// CloseAndRecconect will try to reconnect
func (gc *GorillaClient) closeAndReConect() {
gc.connection.Close()
go func() {
gc.reConnect()
}()
}
func (gc *GorillaClient) reConnect() {
bo := &backoff.Backoff{
Min: gc.config.RecIntervalMin,
Max: gc.config.RecIntervalMax,
Factor: gc.config.RecIntervalFactor,
Jitter: true,
}
rand.Seed(time.Now().UTC().UnixNano())
for {
nextInterval := bo.Duration()
url := url.URL{Scheme: gc.config.Scheme, Host: gc.config.URL, Path: gc.config.Channel}
newConnection, _, err := websocket.DefaultDialer.Dial(url.String(), nil)
if err != nil {
log.Printf("Websocket client: will try again in %v seconds. Because of %v\n", nextInterval, err)
} else {
configHashed := hashObject(gc.config)
gorrilaClientMutex.Lock()
currentWebsocketClientSession := gorrilaClientSessionMapping[configHashed]
currentWebsocketClientSession.connection = newConnection
gorrilaClientSessionMapping[configHashed] = currentWebsocketClientSession
gorrilaClientMutex.Unlock()
log.Println("Websocket client: reconnected")
break
}
time.Sleep(nextInterval)
}
}
// Write message to channel
func (gc *GorillaClient) Write(message string) error {
if err := gc.connection.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
gc.closeAndReConect()
return err
}
return nil
}
// Read message from channel
func (gc *GorillaClient) Read() (interface{}, error) {
_, message, err := gc.connection.ReadMessage()
if err != nil {
gc.closeAndReConect()
return nil, err
}
return bytesToString(message), nil
}
// End this communication
func (gc *GorillaClient) End() error {
return gc.connection.Close()
}