aboutsummaryrefslogtreecommitdiffstats
path: root/lib/assets/javascripts/cable/connection_monitor.coffee
diff options
context:
space:
mode:
authorRafael Mendonça França <rafaelmfranca@gmail.com>2015-09-02 02:57:38 -0300
committerRafael Mendonça França <rafaelmfranca@gmail.com>2015-09-02 02:57:38 -0300
commiteb8c713c987480e7a0362ae3de617ba0c0f27d7f (patch)
tree7f5b9afd7a6326161c75270701f1e880e4f20263 /lib/assets/javascripts/cable/connection_monitor.coffee
parent0cf1db6be29fb2269d722bedd690641e0f949b36 (diff)
downloadrails-eb8c713c987480e7a0362ae3de617ba0c0f27d7f.tar.gz
rails-eb8c713c987480e7a0362ae3de617ba0c0f27d7f.tar.bz2
rails-eb8c713c987480e7a0362ae3de617ba0c0f27d7f.zip
.js.coffee -> .coffee
It was initially required, but support for the shorthand has been supported since sprockets 2.1. Eventually 4.x will only support the shorthand version. Just want to get new people using the prefer stuff ASAP.
Diffstat (limited to 'lib/assets/javascripts/cable/connection_monitor.coffee')
-rw-r--r--lib/assets/javascripts/cable/connection_monitor.coffee87
1 files changed, 87 insertions, 0 deletions
diff --git a/lib/assets/javascripts/cable/connection_monitor.coffee b/lib/assets/javascripts/cable/connection_monitor.coffee
new file mode 100644
index 0000000000..30ce11957c
--- /dev/null
+++ b/lib/assets/javascripts/cable/connection_monitor.coffee
@@ -0,0 +1,87 @@
+# 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.
+class Cable.ConnectionMonitor
+ identifier: Cable.PING_IDENTIFIER
+
+ pollInterval:
+ min: 2
+ max: 30
+
+ staleThreshold:
+ startedAt: 4
+ pingedAt: 8
+
+ constructor: (@consumer) ->
+ @consumer.subscriptions.add(this)
+ @start()
+
+ connected: ->
+ @reset()
+ @pingedAt = now()
+
+ disconnected: ->
+ if @reconnectAttempts++ is 0
+ setTimeout =>
+ @consumer.connection.open() unless @consumer.connection.isOpen()
+ , 200
+
+ received: ->
+ @pingedAt = now()
+
+ reset: ->
+ @reconnectAttempts = 0
+
+ start: ->
+ @reset()
+ delete @stoppedAt
+ @startedAt = now()
+ @poll()
+ document.addEventListener("visibilitychange", @visibilityDidChange)
+
+ stop: ->
+ @stoppedAt = now()
+ document.removeEventListener("visibilitychange", @visibilityDidChange)
+
+ poll: ->
+ setTimeout =>
+ unless @stoppedAt
+ @reconnectIfStale()
+ @poll()
+ , @getInterval()
+
+ getInterval: ->
+ {min, max} = @pollInterval
+ interval = 4 * Math.log(@reconnectAttempts + 1)
+ clamp(interval, min, max) * 1000
+
+ reconnectIfStale: ->
+ if @connectionIsStale()
+ @reconnectAttempts++
+ @consumer.connection.reopen()
+
+ connectionIsStale: ->
+ if @pingedAt
+ secondsSince(@pingedAt) > @staleThreshold.pingedAt
+ else
+ secondsSince(@startedAt) > @staleThreshold.startedAt
+
+ visibilityDidChange: =>
+ if document.visibilityState is "visible"
+ setTimeout =>
+ if @connectionIsStale() or not @consumer.connection.isOpen()
+ @consumer.connection.reopen()
+ , 200
+
+ toJSON: ->
+ interval = @getInterval()
+ connectionIsStale = @connectionIsStale()
+ {@startedAt, @stoppedAt, @pingedAt, @reconnectAttempts, connectionIsStale, interval}
+
+ now = ->
+ new Date().getTime()
+
+ secondsSince = (time) ->
+ (now() - time) / 1000
+
+ clamp = (number, min, max) ->
+ Math.max(min, Math.min(max, number))