From cbd15da0274316bae64caae54880fee87853f480 Mon Sep 17 00:00:00 2001 From: Daniel Rhodes Date: Thu, 17 Mar 2016 15:05:06 +0100 Subject: Added protocol negotiation This is primarily for backwards compatibility for when or if the protocol is changed in future versions. If the server fails to respond with an acceptable protocol, the client disconnects and disables the monitor. --- .../javascripts/action_cable/connection.coffee | 41 +++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'actioncable/app/assets/javascripts/action_cable/connection.coffee') diff --git a/actioncable/app/assets/javascripts/action_cable/connection.coffee b/actioncable/app/assets/javascripts/action_cable/connection.coffee index 92272cc5b8..af771f2d82 100644 --- a/actioncable/app/assets/javascripts/action_cable/connection.coffee +++ b/actioncable/app/assets/javascripts/action_cable/connection.coffee @@ -2,7 +2,8 @@ # Encapsulate the cable connection held by the consumer. This is an internal class not intended for direct user manipulation. -{message_types} = ActionCable.INTERNAL +{message_types, protocols} = ActionCable.INTERNAL +[supportedProtocols..., unsupportedProtocol] = protocols class ActionCable.Connection @reopenDelay: 500 @@ -10,6 +11,7 @@ class ActionCable.Connection constructor: (@consumer) -> {@subscriptions} = @consumer @monitor = new ActionCable.ConnectionMonitor this + @disconnected = true send: (data) -> if @isOpen() @@ -23,15 +25,16 @@ class ActionCable.Connection ActionCable.log("Attemped to open WebSocket, but existing socket is #{@getState()}") throw new Error("Existing connection must be closed before opening") else - ActionCable.log("Opening WebSocket, current state is #{@getState()}") + ActionCable.log("Opening WebSocket, current state is #{@getState()}, subprotocols: #{protocols}") @uninstallEventHandlers() if @webSocket? - @webSocket = new WebSocket(@consumer.url) + @webSocket = new WebSocket(@consumer.url, protocols) @installEventHandlers() @monitor.start() true - close: -> - @webSocket?.close() + close: ({allowReconnect} = {allowReconnect: true}) -> + @monitor.stop() unless allowReconnect + @webSocket?.close() if @isActive() reopen: -> ActionCable.log("Reopening WebSocket, current state is #{@getState()}") @@ -46,6 +49,9 @@ class ActionCable.Connection else @open() + getProtocol: -> + @webSocket?.protocol + isOpen: -> @isState("open") @@ -54,6 +60,9 @@ class ActionCable.Connection # Private + isProtocolSupported: -> + @getProtocol() in supportedProtocols + isState: (states...) -> @getState() in states @@ -74,10 +83,12 @@ class ActionCable.Connection events: message: (event) -> + return unless @isSupportedProtocol() {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 @@ -88,20 +99,18 @@ class ActionCable.Connection @subscriptions.notify(identifier, "received", message) open: -> - ActionCable.log("WebSocket onopen event") + ActionCable.log("WebSocket onopen event, using '#{@getProtocol()}' subprotocol") @disconnected = false - @subscriptions.reload() + if not @isProtocolSupported() + ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting.") + @close(allowReconnect: false) - close: -> + close: (event) -> ActionCable.log("WebSocket onclose event") - @disconnect() + return if @disconnected + @disconnected = true + @monitor.recordDisconnect() + @subscriptions.notifyAll("disconnected", {willAttemptReconnect: @monitor.isRunning()}) error: -> ActionCable.log("WebSocket onerror event") - @disconnect() - - disconnect: -> - return if @disconnected - @disconnected = true - @subscriptions.notifyAll("disconnected") - @monitor.recordDisconnect() -- cgit v1.2.3