123456789_123456789_123456789_123456789_123456789_

Class: ActionCable::Connection::Base

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: actioncable/lib/action_cable/connection/base.rb

Overview

For every WebSocket connection the Action Cable server accepts, a ::ActionCable::Connection object will be instantiated. This instance becomes the parent of all of the channel subscriptions that are created from there on. Incoming messages are then routed to these channel subscriptions based on an identifier sent by the Action Cable consumer. The Connection itself does not deal with any specific application logic beyond authentication and authorization.

Here’s a basic example:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
      logger.add_tags current_user.name
    end

    def disconnect
      # Any cleanup work needed when the cable connection is cut.
    end

    private
      def find_verified_user
        User.find_by_identity(cookies.encrypted[:identity_id]) ||
          reject_unauthorized_connection
      end
  end
end

First, we declare that this connection can be identified by its current_user. This allows us to later be able to find all connections established for that current_user (and potentially disconnect them). You can declare as many identification indexes as you like. Declaring an identification means that an attr_accessor is automatically set for that key.

Second, we rely on the fact that the WebSocket connection is established with the cookies from the domain being sent along. This makes it easy to use signed cookies that were set when logging in via a web interface to authorize the WebSocket connection.

Finally, we add a tag to the connection-specific logger with the name of the current user to easily distinguish their messages in the log.

Pretty simple, eh?

Identification - Attributes & Methods

::ActiveSupport::Rescuable - Attributes & Methods

Class Method Summary

Instance Attribute Summary

Instance Method Summary

::ActiveSupport::Rescuable - Included

#rescue_with_handler

Delegates to the class method, but uses the instance as the subject for rescue_from handlers (method calls, instance_exec blocks).

Authorization - Included

#reject_unauthorized_connection

Closes the WebSocket connection if it is open and returns a 404 “File not Found” response.

Identification - Included

#connection_identifier

Return a single connection identifier that combines the value of all the registered identifiers into a single gid.

Constructor Details

.new(server, env, coder: ActiveSupport::JSON) ⇒ Base

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 55

def initialize(server, env, coder: ActiveSupport::JSON)
  @server, @env, @coder = server, env, coder

  @worker_pool = server.worker_pool
  @logger = new_tagged_logger

  @websocket      = ActionCable::Connection::WebSocket.new(env, self, event_loop)
  @subscriptions  = ActionCable::Connection::Subscriptions.new(self)
  @message_buffer = ActionCable::Connection::MessageBuffer.new(self)

  @_internal_subscriptions = nil
  @started_at = Time.now
end

Class Attribute Details

.identifiers (rw)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/identification.rb', line 11

class_attribute :identifiers, default: Set.new

.identifiers?Boolean (rw)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/identification.rb', line 11

class_attribute :identifiers, default: Set.new

.rescue_handlers (rw)

[ GitHub ]

  
# File 'activesupport/lib/active_support/rescuable.rb', line 13

class_attribute :rescue_handlers, default: []

.rescue_handlers?Boolean (rw)

[ GitHub ]

  
# File 'activesupport/lib/active_support/rescuable.rb', line 13

class_attribute :rescue_handlers, default: []

Instance Attribute Details

#env (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

#event_loop (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 53

delegate :event_loop, :pubsub, to: :server

#identifiers (rw)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/identification.rb', line 11

class_attribute :identifiers, default: Set.new

#identifiers?Boolean (rw)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/identification.rb', line 11

class_attribute :identifiers, default: Set.new

#logger (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

#protocol (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

#pubsub (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 53

delegate :event_loop, :pubsub, to: :server

#rescue_handlers (rw)

[ GitHub ]

  
# File 'activesupport/lib/active_support/rescuable.rb', line 13

class_attribute :rescue_handlers, default: []

#rescue_handlers?Boolean (rw)

[ GitHub ]

  
# File 'activesupport/lib/active_support/rescuable.rb', line 13

class_attribute :rescue_handlers, default: []

#server (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

#subscriptions (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

#worker_pool (readonly)

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 52

attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol

Instance Method Details

#beat

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 125

def beat
  transmit type: ActionCable::INTERNAL[:message_types][:ping], message: Time.now.to_i
end

#close(reason: nil, reconnect: true)

Close the WebSocket connection.

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 100

def close(reason: nil, reconnect: true)
  transmit(
    type: ActionCable::INTERNAL[:message_types][:disconnect],
    reason: reason,
    reconnect: reconnect
  )
  websocket.close
end

#cookies (private)

The cookies of the request that initiated the WebSocket connection. Useful for performing authorization checks.

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 159

def cookies # :doc:
  request.cookie_jar
end

#request (private)

The request that initiated the WebSocket connection is available here. This gives access to the environment, cookies, etc.

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 151

def request # :doc:
  @request ||= begin
    environment = Rails.application.env_config.merge(env) if defined?(Rails.application) && Rails.application
    ActionDispatch::Request.new(environment || env)
  end
end

#send_async(method, *arguments)

Invoke a method on the connection asynchronously through the pool of thread workers.

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 110

def send_async(method, *arguments)
  worker_pool.async_invoke(self, method, *arguments)
end

#statistics

Return a basic hash of statistics for the connection keyed with identifier, started_at, #subscriptions, and request_id. This can be returned by a health check against the connection.

[ GitHub ]

  
# File 'actioncable/lib/action_cable/connection/base.rb', line 116

def statistics
  {
    identifier: connection_identifier,
    started_at: @started_at,
    subscriptions: subscriptions.identifiers,
    request_id: @env["action_dispatch.request_id"]
  }
end