aboutsummaryrefslogtreecommitdiffstats
path: root/actioncable/app/javascript/action_cable/connection.js
diff options
context:
space:
mode:
authorRichard Macklin <richard.github@nrm.com>2018-01-12 16:49:09 -0800
committerRichard Macklin <richard.github@nrm.com>2018-11-02 08:40:59 -0700
commit0eb6b86e9606cace49afba0b35ec18916c73646e (patch)
tree2d038d66bccb439d683b89a93388e31f967ebd6e /actioncable/app/javascript/action_cable/connection.js
parent403c001c56e3980e624da2cb1e1e98d667499d40 (diff)
downloadrails-0eb6b86e9606cace49afba0b35ec18916c73646e.tar.gz
rails-0eb6b86e9606cace49afba0b35ec18916c73646e.tar.bz2
rails-0eb6b86e9606cace49afba0b35ec18916c73646e.zip
Refactor decaffeinate output to more natural/idiomatic javascript
- Remove unnecessary Array.from usages from subscriptions.js These were all Arrays before, so Array.from is a no-op - Remove unnecessary IIFEs from subscriptions.js - Manually decaffeinate sample ActionCable code in comments Here the coffeescript -> ES2015 conversion was done by hand rather than using decaffeinate, because these code samples were simple enough. - Refactor ActionCable.Subscription to avoid initClass - Refactor ActionCable.Subscription to use ES2015 default parameters - Refactor ActionCable.ConnectionMonitor to avoid initClass - Refactor ActionCable.ConnectionMonitor to use shorter variations of null checks - Remove unnecessary code created because of implicit returns in ConnectionMonitor This removes the `return` statements that were returning the value of console.log and those from private methods whose return value was not being used. - Refactor ActionCable.Connection to avoid initClass - Refactor Connection#isProtocolSupported and #isState This addresses these three decaffeinate cleanup suggestions: - DS101: Remove unnecessary use of Array.from - DS104: Avoid inline assignments - DS204: Change includes calls to have a more natural evaluation order It also removes the use of Array.prototype.includes, which means we don't have to worry about providing a polyfill or requiring that end users provide one. - Refactor ActionCable.Connection to use ES2015 default parameters - Refactor ActionCable.Connection to use shorter variations of null checks - Remove return statements that return the value of console.log() in ActionCable.Connection - Simplify complex destructure assignment in connection.js decaffeinate had inserted ``` adjustedLength = Math.max(protocols.length, 1) ``` to be safe, but we know that there has to always be at least one protocol, so we don't have to worry about protocols.length being 0 here. - Refactor Connection#getState The decaffeinate translation of this method was not very clear, so we've rewritten it to be more natural. - Simplify destructure assignment in connection.js - Remove unnecessary use of Array.from from action_cable.js.erb - Refactor ActionCable#createConsumer and #getConfig This addresses these two decaffeinate cleanup suggestions: - DS104: Avoid inline assignments - DS207: Consider shorter variations of null checks - Remove unnecessary code created because of implicit returns in action_cable.js.erb This removes the `return` statements that were returning the value of console.log and those from methods that just set and unset the `debugging` flag. - Remove decaffeinate suggestion about avoiding top-level this In this case, the top-level `this` is intentional, so it's okay to ignore this suggestion. - Remove decaffeinate suggestions about removing unnecessary returns I did remove some of the return statements in previous commits, where it seemed appropriate. However, the rest of these should probably remain because the return values have been exposed through the public API. If we want to break that contract, we can do so, but I think it should be done deliberately as part of a breaking-API change (separate from this coffeescript -> ES2015 conversion) - Remove unused `unsupportedProtocol` variable from connection.js Leaving this would cause eslint to fail - Refactor Subscriptions methods to avoid `for` ... `of` syntax Babel transpiles `for` ... `of` syntax to use `Symbol.iterator`, which would require a polyfill in applications that support older browsers. The `for` ... `of` syntax was produced by running `decaffeinate`, but in these instances a simpler `map` should be sufficient and avoid any `Symbol` issues.
Diffstat (limited to 'actioncable/app/javascript/action_cable/connection.js')
-rw-r--r--actioncable/app/javascript/action_cable/connection.js268
1 files changed, 131 insertions, 137 deletions
diff --git a/actioncable/app/javascript/action_cable/connection.js b/actioncable/app/javascript/action_cable/connection.js
index 462db965d1..540f597303 100644
--- a/actioncable/app/javascript/action_cable/connection.js
+++ b/actioncable/app/javascript/action_cable/connection.js
@@ -1,164 +1,158 @@
-/*
- * 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")
- }
+const supportedProtocols = protocols.slice(0, protocols.length - 1)
+
+ActionCable.Connection = (function() {
+ const indexOf = [].indexOf
+
+ class Connection {
+ constructor(consumer) {
+ this.open = this.open.bind(this)
+ this.consumer = consumer
+ this.subscriptions = this.consumer.subscriptions
+ this.monitor = new ActionCable.ConnectionMonitor(this)
+ this.disconnected = true
}
- }
-
- 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
+ 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
+ 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) { 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) }
- }
+ close({allowReconnect} = {allowReconnect: true}) {
+ if (!allowReconnect) { this.monitor.stop() }
+ if (this.isActive()) { return (this.webSocket ? 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)
+ reopen() {
+ ActionCable.log(`Reopening WebSocket, current state is ${this.getState()}`)
+ if (this.isActive()) {
+ try {
+ return this.close()
+ } catch (error) {
+ 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()
}
- } else {
- return this.open()
}
- }
- getProtocol() {
- return (this.webSocket != null ? this.webSocket.protocol : undefined)
- }
+ getProtocol() {
+ return (this.webSocket ? this.webSocket.protocol : undefined)
+ }
- isOpen() {
- return this.isState("open")
- }
+ isOpen() {
+ return this.isState("open")
+ }
- isActive() {
- return this.isState("open", "connecting")
- }
+ isActive() {
+ return this.isState("open", "connecting")
+ }
- // Private
+ // Private
- isProtocolSupported() {
- let needle
- return (needle = this.getProtocol(), Array.from(supportedProtocols).includes(needle))
- }
+ isProtocolSupported() {
+ return indexOf.call(supportedProtocols, this.getProtocol()) >= 0
+ }
- isState(...states) {
- let needle
- return (needle = this.getState(), Array.from(states).includes(needle))
- }
+ isState(...states) {
+ return indexOf.call(states, this.getState()) >= 0
+ }
- getState() {
- for (let state in WebSocket) { const value = WebSocket[state]; if (value === (this.webSocket != null ? this.webSocket.readyState : undefined)) { return state.toLowerCase() } }
- return null
- }
+ getState() {
+ if (this.webSocket) {
+ for (let state in WebSocket) {
+ if (WebSocket[state] === this.webSocket.readyState) {
+ return state.toLowerCase()
+ }
+ }
+ }
+ return null
+ }
- installEventHandlers() {
- for (let eventName in this.events) {
- const handler = this.events[eventName].bind(this)
- this.webSocket[`on${eventName}`] = handler
+ 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() {}
+ }
+ }
+
}
- uninstallEventHandlers() {
- for (let eventName in this.events) {
- this.webSocket[`on${eventName}`] = function() {}
+ Connection.reopenDelay = 500
+
+ Connection.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() {
+ ActionCable.log("WebSocket onerror event")
}
}
-})
-Cls.initClass()
+
+ return Connection
+
+})()