aboutsummaryrefslogtreecommitdiffstats
path: root/actioncable/app/javascript/action_cable/connection_monitor.js
diff options
context:
space:
mode:
authorRichard Macklin <richard.github@nrm.com>2017-12-11 14:44:52 +0800
committerRichard Macklin <richard.github@nrm.com>2018-11-02 08:40:35 -0700
commit403c001c56e3980e624da2cb1e1e98d667499d40 (patch)
treefcdcb33626125f00dff1fc11a9447995f8b7abf4 /actioncable/app/javascript/action_cable/connection_monitor.js
parent7b0b37240a20c74197408ac3b53519e7e18347e9 (diff)
downloadrails-403c001c56e3980e624da2cb1e1e98d667499d40.tar.gz
rails-403c001c56e3980e624da2cb1e1e98d667499d40.tar.bz2
rails-403c001c56e3980e624da2cb1e1e98d667499d40.zip
Run decaffeinate on action_cable/*.js
Using [decaffeinate], we have converted these files from coffeescript syntax to ES2015 syntax. Decaffeinate is very conservative in the conversion process to ensure exact coffeescript semantics are preserved. Most of the time, it's safe to clean up the code, and decaffeinate has left suggestions regarding potential cleanups we can take. I'll tackle those cleanups separately. After running decaffeinate, I ran: ``` eslint --fix app/javascript ``` using the eslint configuration from ActiveStorage to automatically correct lint violations in the decaffeinated output. This removed 189 extra semicolons and changed one instance of single quotes to double quotes. Note: decaffeinate and eslint can't parse ERB syntax. So I worked around that by temporarily quoting the ERB: ```diff @ActionCable = - INTERNAL: <%= ActionCable::INTERNAL.to_json %> + INTERNAL: "<%= ActionCable::INTERNAL.to_json %>" WebSocket: window.WebSocket logger: window.console ``` and then removing those quotes after running decaffeinate and eslint. [decaffeinate]: https://github.com/decaffeinate/decaffeinate
Diffstat (limited to 'actioncable/app/javascript/action_cable/connection_monitor.js')
-rw-r--r--actioncable/app/javascript/action_cable/connection_monitor.js231
1 files changed, 136 insertions, 95 deletions
diff --git a/actioncable/app/javascript/action_cable/connection_monitor.js b/actioncable/app/javascript/action_cable/connection_monitor.js
index 0cc675fa94..c8d2c62cc8 100644
--- a/actioncable/app/javascript/action_cable/connection_monitor.js
+++ b/actioncable/app/javascript/action_cable/connection_monitor.js
@@ -1,95 +1,136 @@
-# 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 ActionCable.ConnectionMonitor
- @pollInterval:
- min: 3
- max: 30
-
- @staleThreshold: 6 # Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
-
- constructor: (@connection) ->
- @reconnectAttempts = 0
-
- start: ->
- unless @isRunning()
- @startedAt = now()
- delete @stoppedAt
- @startPolling()
- document.addEventListener("visibilitychange", @visibilityDidChange)
- ActionCable.log("ConnectionMonitor started. pollInterval = #{@getPollInterval()} ms")
-
- stop: ->
- if @isRunning()
- @stoppedAt = now()
- @stopPolling()
- document.removeEventListener("visibilitychange", @visibilityDidChange)
- ActionCable.log("ConnectionMonitor stopped")
-
- isRunning: ->
- @startedAt? and not @stoppedAt?
-
- recordPing: ->
- @pingedAt = now()
-
- recordConnect: ->
- @reconnectAttempts = 0
- @recordPing()
- delete @disconnectedAt
- ActionCable.log("ConnectionMonitor recorded connect")
-
- recordDisconnect: ->
- @disconnectedAt = now()
- ActionCable.log("ConnectionMonitor recorded disconnect")
-
- # Private
-
- startPolling: ->
- @stopPolling()
- @poll()
-
- stopPolling: ->
- clearTimeout(@pollTimeout)
-
- poll: ->
- @pollTimeout = setTimeout =>
- @reconnectIfStale()
- @poll()
- , @getPollInterval()
-
- getPollInterval: ->
- {min, max} = @constructor.pollInterval
- interval = 5 * Math.log(@reconnectAttempts + 1)
- Math.round(clamp(interval, min, max) * 1000)
-
- reconnectIfStale: ->
- if @connectionIsStale()
- ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = #{@reconnectAttempts}, pollInterval = #{@getPollInterval()} ms, time disconnected = #{secondsSince(@disconnectedAt)} s, stale threshold = #{@constructor.staleThreshold} s")
- @reconnectAttempts++
- if @disconnectedRecently()
- ActionCable.log("ConnectionMonitor skipping reopening recent disconnect")
- else
- ActionCable.log("ConnectionMonitor reopening")
- @connection.reopen()
-
- connectionIsStale: ->
- secondsSince(@pingedAt ? @startedAt) > @constructor.staleThreshold
-
- disconnectedRecently: ->
- @disconnectedAt and secondsSince(@disconnectedAt) < @constructor.staleThreshold
-
- visibilityDidChange: =>
- if document.visibilityState is "visible"
- setTimeout =>
- if @connectionIsStale() or not @connection.isOpen()
- ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = #{document.visibilityState}")
- @connection.reopen()
- , 200
-
- now = ->
- new Date().getTime()
-
- secondsSince = (time) ->
- (now() - time) / 1000
-
- clamp = (number, min, max) ->
- Math.max(min, Math.min(max, number))
+/*
+ * decaffeinate suggestions:
+ * DS102: Remove unnecessary code created because of implicit returns
+ * DS206: Consider reworking classes to avoid initClass
+ * DS207: Consider shorter variations of null checks
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
+ */
+// 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.
+(function() {
+ let now = undefined
+ let secondsSince = undefined
+ let clamp = undefined
+ const Cls = (ActionCable.ConnectionMonitor = class ConnectionMonitor {
+ static initClass() {
+ this.pollInterval = {
+ min: 3,
+ max: 30
+ }
+
+ this.staleThreshold = 6
+
+ now = () => new Date().getTime()
+
+ secondsSince = time => (now() - time) / 1000
+
+ clamp = (number, min, max) => Math.max(min, Math.min(max, number))
+ // Server::Connections::BEAT_INTERVAL * 2 (missed two pings)
+ }
+
+ constructor(connection) {
+ this.visibilityDidChange = this.visibilityDidChange.bind(this)
+ this.connection = connection
+ this.reconnectAttempts = 0
+ }
+
+ start() {
+ if (!this.isRunning()) {
+ this.startedAt = now()
+ delete this.stoppedAt
+ this.startPolling()
+ document.addEventListener("visibilitychange", this.visibilityDidChange)
+ return ActionCable.log(`ConnectionMonitor started. pollInterval = ${this.getPollInterval()} ms`)
+ }
+ }
+
+ stop() {
+ if (this.isRunning()) {
+ this.stoppedAt = now()
+ this.stopPolling()
+ document.removeEventListener("visibilitychange", this.visibilityDidChange)
+ return ActionCable.log("ConnectionMonitor stopped")
+ }
+ }
+
+ isRunning() {
+ return (this.startedAt != null) && (this.stoppedAt == null)
+ }
+
+ recordPing() {
+ return this.pingedAt = now()
+ }
+
+ recordConnect() {
+ this.reconnectAttempts = 0
+ this.recordPing()
+ delete this.disconnectedAt
+ return ActionCable.log("ConnectionMonitor recorded connect")
+ }
+
+ recordDisconnect() {
+ this.disconnectedAt = now()
+ return ActionCable.log("ConnectionMonitor recorded disconnect")
+ }
+
+ // Private
+
+ startPolling() {
+ this.stopPolling()
+ return this.poll()
+ }
+
+ stopPolling() {
+ return clearTimeout(this.pollTimeout)
+ }
+
+ poll() {
+ return this.pollTimeout = setTimeout(() => {
+ this.reconnectIfStale()
+ return this.poll()
+ }
+ , this.getPollInterval())
+ }
+
+ getPollInterval() {
+ const {min, max} = this.constructor.pollInterval
+ const interval = 5 * Math.log(this.reconnectAttempts + 1)
+ return Math.round(clamp(interval, min, max) * 1000)
+ }
+
+ reconnectIfStale() {
+ if (this.connectionIsStale()) {
+ ActionCable.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, pollInterval = ${this.getPollInterval()} ms, time disconnected = ${secondsSince(this.disconnectedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`)
+ this.reconnectAttempts++
+ if (this.disconnectedRecently()) {
+ return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect")
+ } else {
+ ActionCable.log("ConnectionMonitor reopening")
+ return this.connection.reopen()
+ }
+ }
+ }
+
+ connectionIsStale() {
+ return secondsSince(this.pingedAt != null ? this.pingedAt : this.startedAt) > this.constructor.staleThreshold
+ }
+
+ disconnectedRecently() {
+ return this.disconnectedAt && (secondsSince(this.disconnectedAt) < this.constructor.staleThreshold)
+ }
+
+ visibilityDidChange() {
+ if (document.visibilityState === "visible") {
+ return setTimeout(() => {
+ if (this.connectionIsStale() || !this.connection.isOpen()) {
+ ActionCable.log(`ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = ${document.visibilityState}`)
+ return this.connection.reopen()
+ }
+ }
+ , 200)
+ }
+ }
+ })
+ Cls.initClass()
+ return Cls
+})()