blob: 2a70693bf0d9153e7b738582909cdc11627123b5 (
plain) (
blame)
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
|
#= require_self
#= require_tree .
class @Cable
MAX_CONNECTION_ATTEMPTS: 10
MAX_CONNECTION_INTERVAL: 5 * 1000
MAX_PING_INTERVAL: 6
constructor: (@cableUrl) ->
@subscribers = {}
@resetPingTime()
@resetConnectionAttemptsCount()
@connect()
connect: ->
@connection = @createConnection()
createConnection: ->
connection = new WebSocket(@cableUrl)
connection.onmessage = @receiveData
connection.onopen = @connected
connection.onclose = @reconnect
connection.onerror = @reconnect
connection
isConnected: =>
@connection?.readyState is 1
sendData: (identifier, data) =>
if @isConnected()
@connection.send JSON.stringify { action: 'message', identifier: identifier, data: data }
receiveData: (message) =>
data = JSON.parse message.data
if data.identifier is '_ping'
@pingReceived(data.message)
else
@subscribers[data.identifier]?.onReceiveData(data.message)
connected: =>
@resetConnectionAttemptsCount()
for identifier, callbacks of @subscribers
@subscribeOnServer(identifier)
callbacks['onConnect']?()
reconnect: =>
@resetPingTime()
@disconnected()
setTimeout =>
if @isMaxConnectionAttemptsReached()
@giveUp()
else
@incrementConnectionAttemptsCount()
@connect()
, @generateReconnectInterval()
resetConnectionAttemptsCount: =>
@connectionAttempts = 1
incrementConnectionAttemptsCount: =>
@connectionAttempts += 1
isMaxConnectionAttemptsReached: =>
@connectionAttempts > @MAX_CONNECTION_ATTEMPTS
generateReconnectInterval: () ->
interval = (Math.pow(2, @connectionAttempts) - 1) * 1000
if interval > @MAX_CONNECTION_INTERVAL then @MAX_CONNECTION_INTERVAL else interval
resetPingTime: () =>
@lastPingTime = null
disconnected: =>
callbacks['onDisconnect']?() for identifier, callbacks of @subscribers
giveUp: =>
# Show an error message
subscribe: (identifier, callbacks) =>
@subscribers[identifier] = callbacks
if @isConnected()
@subscribeOnServer(identifier)
@subscribers[identifier]['onConnect']?()
unsubscribe: (identifier) =>
@unsubscribeOnServer(identifier, 'unsubscribe')
delete @subscribers[identifier]
subscribeOnServer: (identifier) =>
if @isConnected()
@connection.send JSON.stringify { action: 'subscribe', identifier: identifier }
unsubscribeOnServer: (identifier) =>
if @isConnected()
@connection.send JSON.stringify { action: 'unsubscribe', identifier: identifier }
pingReceived: (timestamp) =>
if @lastPingTime? and (timestamp - @lastPingTime) > @MAX_PING_INTERVAL
console.log "Websocket connection is stale. Reconnecting.."
@connection.close()
else
@lastPingTime = timestamp
|