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.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.js')
-rw-r--r-- | actioncable/app/javascript/action_cable/connection.js | 280 |
1 files changed, 164 insertions, 116 deletions
diff --git a/actioncable/app/javascript/action_cable/connection.js b/actioncable/app/javascript/action_cable/connection.js index 7fd68cad2f..462db965d1 100644 --- a/actioncable/app/javascript/action_cable/connection.js +++ b/actioncable/app/javascript/action_cable/connection.js @@ -1,116 +1,164 @@ -#= require ./connection_monitor - -# Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation. - -{message_types, protocols} = ActionCable.INTERNAL -[supportedProtocols..., unsupportedProtocol] = protocols - -class ActionCable.Connection - @reopenDelay: 500 - - constructor: (@consumer) -> - {@subscriptions} = @consumer - @monitor = new ActionCable.ConnectionMonitor this - @disconnected = true - - send: (data) -> - if @isOpen() - @webSocket.send(JSON.stringify(data)) - true - else - false - - open: => - if @isActive() - ActionCable.log("Attempted to open WebSocket, but existing socket is #{@getState()}") - false - else - ActionCable.log("Opening WebSocket, current state is #{@getState()}, subprotocols: #{protocols}") - @uninstallEventHandlers() if @webSocket? - @webSocket = new ActionCable.WebSocket(@consumer.url, protocols) - @installEventHandlers() - @monitor.start() - true - - close: ({allowReconnect} = {allowReconnect: true}) -> - @monitor.stop() unless allowReconnect - @webSocket?.close() if @isActive() - - reopen: -> - ActionCable.log("Reopening WebSocket, current state is #{@getState()}") - if @isActive() - try - @close() - catch error - ActionCable.log("Failed to reopen WebSocket", error) - finally - ActionCable.log("Reopening WebSocket in #{@constructor.reopenDelay}ms") - setTimeout(@open, @constructor.reopenDelay) - else - @open() - - getProtocol: -> - @webSocket?.protocol - - isOpen: -> - @isState("open") - - isActive: -> - @isState("open", "connecting") - - # Private - - isProtocolSupported: -> - @getProtocol() in supportedProtocols - - isState: (states...) -> - @getState() in states - - getState: -> - return state.toLowerCase() for state, value of WebSocket when value is @webSocket?.readyState - null - - installEventHandlers: -> - for eventName of @events - handler = @events[eventName].bind(this) - @webSocket["on#{eventName}"] = handler - return - - uninstallEventHandlers: -> - for eventName of @events - @webSocket["on#{eventName}"] = -> - return - - events: - message: (event) -> - return unless @isProtocolSupported() - {identifier, message, type} = JSON.parse(event.data) - switch type - when message_types.welcome - @monitor.recordConnect() - @subscriptions.reload() - when message_types.ping - @monitor.recordPing() - when message_types.confirmation - @subscriptions.notify(identifier, "connected") - when message_types.rejection - @subscriptions.reject(identifier) - else - @subscriptions.notify(identifier, "received", message) - - open: -> - ActionCable.log("WebSocket onopen event, using '#{@getProtocol()}' subprotocol") - @disconnected = false - if not @isProtocolSupported() - ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.") - @close(allowReconnect: false) - - close: (event) -> - ActionCable.log("WebSocket onclose event") - return if @disconnected - @disconnected = true - @monitor.recordDisconnect() - @subscriptions.notifyAll("disconnected", {willAttemptReconnect: @monitor.isRunning()}) - - error: -> - ActionCable.log("WebSocket onerror event") +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS104: Avoid inline assignments + * DS201: Simplify complex destructure assignments + * DS204: Change includes calls to have a more natural evaluation order + * 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 + */ +//= require ./connection_monitor + +// Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation. + +const {message_types, protocols} = ActionCable.INTERNAL +const adjustedLength = Math.max(protocols.length, 1), + supportedProtocols = protocols.slice(0, adjustedLength - 1), + unsupportedProtocol = protocols[adjustedLength - 1] + +const Cls = (ActionCable.Connection = class Connection { + static initClass() { + this.reopenDelay = 500 + + this.prototype.events = { + message(event) { + if (!this.isProtocolSupported()) { return } + const {identifier, message, type} = JSON.parse(event.data) + switch (type) { + case message_types.welcome: + this.monitor.recordConnect() + return this.subscriptions.reload() + case message_types.ping: + return this.monitor.recordPing() + case message_types.confirmation: + return this.subscriptions.notify(identifier, "connected") + case message_types.rejection: + return this.subscriptions.reject(identifier) + default: + return this.subscriptions.notify(identifier, "received", message) + } + }, + + open() { + ActionCable.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`) + this.disconnected = false + if (!this.isProtocolSupported()) { + ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.") + return this.close({allowReconnect: false}) + } + }, + + close(event) { + ActionCable.log("WebSocket onclose event") + if (this.disconnected) { return } + this.disconnected = true + this.monitor.recordDisconnect() + return this.subscriptions.notifyAll("disconnected", {willAttemptReconnect: this.monitor.isRunning()}) + }, + + error() { + return ActionCable.log("WebSocket onerror event") + } + } + } + + constructor(consumer) { + this.open = this.open.bind(this) + this.consumer = consumer; + ({subscriptions: this.subscriptions} = this.consumer) + this.monitor = new ActionCable.ConnectionMonitor(this) + this.disconnected = true + } + + send(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)) + return true + } else { + return false + } + } + + open() { + if (this.isActive()) { + ActionCable.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`) + return false + } else { + ActionCable.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`) + if (this.webSocket != null) { this.uninstallEventHandlers() } + this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols) + this.installEventHandlers() + this.monitor.start() + return true + } + } + + close(param) { + if (param == null) { param = {allowReconnect: true} } + const {allowReconnect} = param + if (!allowReconnect) { this.monitor.stop() } + if (this.isActive()) { return (this.webSocket != null ? this.webSocket.close() : undefined) } + } + + reopen() { + ActionCable.log(`Reopening WebSocket, current state is ${this.getState()}`) + if (this.isActive()) { + try { + return this.close() + } catch (error) { + return ActionCable.log("Failed to reopen WebSocket", error) + } + finally { + ActionCable.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`) + setTimeout(this.open, this.constructor.reopenDelay) + } + } else { + return this.open() + } + } + + getProtocol() { + return (this.webSocket != null ? this.webSocket.protocol : undefined) + } + + isOpen() { + return this.isState("open") + } + + isActive() { + return this.isState("open", "connecting") + } + + // Private + + isProtocolSupported() { + let needle + return (needle = this.getProtocol(), Array.from(supportedProtocols).includes(needle)) + } + + isState(...states) { + let needle + return (needle = this.getState(), Array.from(states).includes(needle)) + } + + getState() { + for (let state in WebSocket) { const value = WebSocket[state]; if (value === (this.webSocket != null ? this.webSocket.readyState : undefined)) { return state.toLowerCase() } } + return null + } + + installEventHandlers() { + for (let eventName in this.events) { + const handler = this.events[eventName].bind(this) + this.webSocket[`on${eventName}`] = handler + } + } + + uninstallEventHandlers() { + for (let eventName in this.events) { + this.webSocket[`on${eventName}`] = function() {} + } + } +}) +Cls.initClass() |