aboutsummaryrefslogtreecommitdiffstats
path: root/actioncable/app/javascript/action_cable/connection.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.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.js')
-rw-r--r--actioncable/app/javascript/action_cable/connection.js280
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()