diff options
Diffstat (limited to 'lib/assets/javascripts/cable/connection.js.coffee')
-rw-r--r-- | lib/assets/javascripts/cable/connection.js.coffee | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/lib/assets/javascripts/cable/connection.js.coffee b/lib/assets/javascripts/cable/connection.js.coffee new file mode 100644 index 0000000000..a318925b97 --- /dev/null +++ b/lib/assets/javascripts/cable/connection.js.coffee @@ -0,0 +1,102 @@ +class Cable.Connection + MAX_CONNECTION_INTERVAL: 5 * 1000 + PING_STALE_INTERVAL: 8 + + constructor: (@cable) -> + @resetPingTime() + @resetConnectionAttemptsCount() + @connect() + + send: (data) -> + if @isConnected() + @websocket.send(JSON.stringify(data)) + true + else + false + + connect: -> + @websocket = @createWebSocket() + + createWebSocket: -> + ws = new WebSocket(@cable.url) + ws.onmessage = @onMessage + ws.onopen = @onConnect + ws.onclose = @onClose + ws.onerror = @onError + ws + + onMessage: (message) => + data = JSON.parse message.data + + if data.identifier is '_ping' + @pingReceived(data.message) + else + @cable.subscribers.notify(data.identifier, "onMessage", data.message) + + onConnect: => + @startWaitingForPing() + @resetConnectionAttemptsCount() + @cable.subscribers.reload() + + onClose: => + @reconnect() + + onError: => + @reconnect() + + isConnected: -> + @websocket?.readyState is 1 + + disconnect: -> + @removeExistingConnection() + @resetPingTime() + @cable.subscribers.notifyAll("onDisconnect") + + reconnect: -> + @disconnect() + + setTimeout => + @incrementConnectionAttemptsCount() + @connect() + , @generateReconnectInterval() + + removeExistingConnection: -> + if @websocket? + @clearPingWaitTimeout() + + @websocket.onclose = -> # no-op + @websocket.onerror = -> # no-op + @websocket.close() + @websocket = null + + resetConnectionAttemptsCount: -> + @connectionAttempts = 1 + + incrementConnectionAttemptsCount: -> + @connectionAttempts += 1 + + generateReconnectInterval: () -> + interval = (Math.pow(2, @connectionAttempts) - 1) * 1000 + if interval > @MAX_CONNECTION_INTERVAL then @MAX_CONNECTION_INTERVAL else interval + + startWaitingForPing: -> + @clearPingWaitTimeout() + + @waitForPingTimeout = setTimeout => + console.log "Ping took too long to arrive. Reconnecting.." + @reconnect() + , @PING_STALE_INTERVAL * 1000 + + clearPingWaitTimeout: -> + clearTimeout(@waitForPingTimeout) + + resetPingTime: -> + @lastPingTime = null + + pingReceived: (timestamp) -> + if @lastPingTime? and (timestamp - @lastPingTime) > @PING_STALE_INTERVAL + console.log "Websocket connection is stale. Reconnecting.." + @reconnect() + else + @startWaitingForPing() + @lastPingTime = timestamp |