From 7b0b37240a20c74197408ac3b53519e7e18347e9 Mon Sep 17 00:00:00 2001 From: Richard Macklin Date: Mon, 11 Dec 2017 14:29:45 +0800 Subject: Move actioncable javascript to app/javascript and change .coffee -> .js - Rename action_cable/*.coffee -> *.js - Move app/assets/javascripts/* -> app/javascript/* - Rename action_cable.js.erb -> action_cable/index.js.erb Renaming the extension to .js is in preparation for converting these files from coffeescript to ES2015. Moving the files to app/javascript and putting the entry point in index.js.erb changes the structure of ActionCable's javascript to match the structure of ActiveStorage's javascript. (We are doing the file moving and renaming in a separate commit to ensure that the git history of the files will be preserved - i.e. git will track these as file renames rather than unrelated file additions/deletions. In particular, git blame will still trace back to the original authorship.) --- .../javascript/action_cable/connection_monitor.js | 95 ++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 actioncable/app/javascript/action_cable/connection_monitor.js (limited to 'actioncable/app/javascript/action_cable/connection_monitor.js') diff --git a/actioncable/app/javascript/action_cable/connection_monitor.js b/actioncable/app/javascript/action_cable/connection_monitor.js new file mode 100644 index 0000000000..0cc675fa94 --- /dev/null +++ b/actioncable/app/javascript/action_cable/connection_monitor.js @@ -0,0 +1,95 @@ +# 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)) -- cgit v1.2.3