2015-07-08 08:42:04 -04:00
|
|
|
# Responsible for ensuring the cable connection is in good health by validating the heartbeat pings sent from the server, and attempting
|
|
|
|
# revival reconnections if things go astray. Internal class, not intended for direct user manipulation.
|
2015-06-25 13:52:47 -04:00
|
|
|
class Cable.ConnectionMonitor
|
|
|
|
identifier: Cable.PING_IDENTIFIER
|
|
|
|
|
2015-06-27 16:17:00 -04:00
|
|
|
pollInterval:
|
|
|
|
min: 2
|
|
|
|
max: 30
|
|
|
|
|
|
|
|
staleThreshold:
|
|
|
|
startedAt: 4
|
|
|
|
pingedAt: 8
|
|
|
|
|
2015-06-25 16:24:58 -04:00
|
|
|
constructor: (@consumer) ->
|
2015-07-08 05:00:24 -04:00
|
|
|
@consumer.subscriptions.add(this)
|
2015-06-27 16:17:00 -04:00
|
|
|
@start()
|
2015-06-25 13:52:47 -04:00
|
|
|
|
|
|
|
connected: ->
|
|
|
|
@reset()
|
|
|
|
@pingedAt = now()
|
|
|
|
|
2015-08-28 18:05:46 -04:00
|
|
|
disconnected: ->
|
2015-08-31 09:14:17 -04:00
|
|
|
if @reconnectAttempts++ is 0
|
2015-08-28 18:05:46 -04:00
|
|
|
setTimeout =>
|
2015-08-31 08:54:54 -04:00
|
|
|
@consumer.connection.open() unless @consumer.connection.isOpen()
|
2015-08-28 18:05:46 -04:00
|
|
|
, 200
|
|
|
|
|
2015-06-25 13:52:47 -04:00
|
|
|
received: ->
|
|
|
|
@pingedAt = now()
|
|
|
|
|
|
|
|
reset: ->
|
2015-06-27 16:17:00 -04:00
|
|
|
@reconnectAttempts = 0
|
|
|
|
|
|
|
|
start: ->
|
|
|
|
@reset()
|
|
|
|
delete @stoppedAt
|
|
|
|
@startedAt = now()
|
|
|
|
@poll()
|
2015-08-23 17:57:09 -04:00
|
|
|
document.addEventListener("visibilitychange", @visibilityDidChange)
|
2015-06-25 13:52:47 -04:00
|
|
|
|
2015-06-27 16:17:00 -04:00
|
|
|
stop: ->
|
|
|
|
@stoppedAt = now()
|
2015-08-23 17:57:09 -04:00
|
|
|
document.removeEventListener("visibilitychange", @visibilityDidChange)
|
2015-06-27 16:17:00 -04:00
|
|
|
|
|
|
|
poll: ->
|
2015-06-25 13:52:47 -04:00
|
|
|
setTimeout =>
|
2015-06-27 16:17:00 -04:00
|
|
|
unless @stoppedAt
|
|
|
|
@reconnectIfStale()
|
|
|
|
@poll()
|
|
|
|
, @getInterval()
|
2015-06-25 13:52:47 -04:00
|
|
|
|
2015-06-27 16:17:00 -04:00
|
|
|
getInterval: ->
|
|
|
|
{min, max} = @pollInterval
|
|
|
|
interval = 4 * Math.log(@reconnectAttempts + 1)
|
|
|
|
clamp(interval, min, max) * 1000
|
2015-06-25 13:52:47 -04:00
|
|
|
|
2015-06-27 16:17:00 -04:00
|
|
|
reconnectIfStale: ->
|
|
|
|
if @connectionIsStale()
|
2015-08-31 09:14:17 -04:00
|
|
|
@reconnectAttempts++
|
2015-06-27 16:17:00 -04:00
|
|
|
@consumer.connection.reopen()
|
2015-06-25 13:52:47 -04:00
|
|
|
|
2015-06-27 16:17:00 -04:00
|
|
|
connectionIsStale: ->
|
|
|
|
if @pingedAt
|
|
|
|
secondsSince(@pingedAt) > @staleThreshold.pingedAt
|
|
|
|
else
|
|
|
|
secondsSince(@startedAt) > @staleThreshold.startedAt
|
2015-06-25 13:52:47 -04:00
|
|
|
|
2015-08-23 17:57:09 -04:00
|
|
|
visibilityDidChange: =>
|
|
|
|
if document.visibilityState is "visible"
|
|
|
|
setTimeout =>
|
|
|
|
if @connectionIsStale() or not @consumer.connection.isOpen()
|
|
|
|
@consumer.connection.reopen()
|
|
|
|
, 200
|
|
|
|
|
2015-07-07 09:43:22 -04:00
|
|
|
toJSON: ->
|
|
|
|
interval = @getInterval()
|
|
|
|
connectionIsStale = @connectionIsStale()
|
|
|
|
{@startedAt, @stoppedAt, @pingedAt, @reconnectAttempts, connectionIsStale, interval}
|
|
|
|
|
2015-06-25 13:52:47 -04:00
|
|
|
now = ->
|
|
|
|
new Date().getTime()
|
2015-06-27 16:17:00 -04:00
|
|
|
|
|
|
|
secondsSince = (time) ->
|
|
|
|
(now() - time) / 1000
|
|
|
|
|
|
|
|
clamp = (number, min, max) ->
|
|
|
|
Math.max(min, Math.min(max, number))
|