diff options
author | Richard Macklin <richard.github@nrm.com> | 2017-12-11 14:44:52 +0800 |
---|---|---|
committer | Richard Macklin <richard.github@nrm.com> | 2018-11-02 08:40:35 -0700 |
commit | 403c001c56e3980e624da2cb1e1e98d667499d40 (patch) | |
tree | fcdcb33626125f00dff1fc11a9447995f8b7abf4 /actioncable/app/javascript/action_cable/connection_monitor.js | |
parent | 7b0b37240a20c74197408ac3b53519e7e18347e9 (diff) | |
download | rails-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.js | 231 |
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 +})() |