Class: ActionCable::Connection::Base

Inherits:
Object
  • Object
show all
Includes:
Authorization, Identification, InternalChannel
Defined in:
actioncable/lib/action_cable/connection/base.rb

Overview

Для каждого соединения WebSocket, принимаемого сервером Action Cable, будет создан экземпляр объекта Connection. Этот экземпляр становится родительским для всех подписок канала, которые создаются оттуда. Входящие сообщения затем направляются на эти подписки канала на основе идентификатора, отправленного потребителем Action Cable. Само соединение не имеет отношения к какой-либо конкретной логике приложения, кроме аутентификации и авторизации.

Вот простой пример:

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
      # Любые работы по очистке, необходимые при разъединении кабеля.
    end

    protected
      def find_verified_user
        if current_user = User.find_by_identity cookies.signed[:identity_id]
          current_user
        else
          reject_unauthorized_connection
        end
      end
  end
end

Во-первых, мы объявляем, что это соединение может быть идентифицировано его current_user. Это позволяет нам позже найти все соединения, установленные для этого current_user (и потенциально отключить их). Вы можете объявить столько индексов идентификации, сколько захотите. Объявление идентификатора означает, что attr_accessor автоматически устанавливается для этого ключа.

Во-вторых, мы полагаемся на то, что соединение WebSocket устанавливается с куки-файлами из домена, отправляемого вместе. Это упрощает использование подписанных куки-файлов, которые были установлены при входе через веб-интерфейс для авторизации соединения WebSocket.

Наконец, мы добавляем тег в специфичный для соединения логгер, с именем текущего пользователя, чтобы легко отличать их сообщения в логе.

Довольно просто, да?

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ActiveSupport::Concern

#append_features, #class_methods, extended, #included

Methods included from Identification

#connection_identifier

Constructor Details

#initialize(server, env, coder: ActiveSupport::JSON) ⇒ Base

Returns a new instance of Base.


54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'actioncable/lib/action_cable/connection/base.rb', line 54

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, server.config.client_socket_class)
  @subscriptions  = ActionCable::Connection::Subscriptions.new(self)
  @message_buffer = ActionCable::Connection::MessageBuffer.new(self)

  @_internal_subscriptions = nil
  @started_at = Time.now
end

Instance Attribute Details

#envObject (readonly)

Returns the value of attribute env


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

def env
  @env
end

#loggerObject (readonly)

Returns the value of attribute logger


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

def logger
  @logger
end

#protocolObject (readonly)

Returns the value of attribute protocol


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

def protocol
  @protocol
end

#serverObject (readonly)

Returns the value of attribute server


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

def server
  @server
end

#subscriptionsObject (readonly)

Returns the value of attribute subscriptions


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

def subscriptions
  @subscriptions
end

#worker_poolObject (readonly)

Returns the value of attribute worker_pool


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

def worker_pool
  @worker_pool
end

Instance Method Details

#beatObject


119
120
121
# File 'actioncable/lib/action_cable/connection/base.rb', line 119

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

#closeObject

Закройте соединение WebSocket.


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

def close
  websocket.close
end

#dispatch_websocket_message(websocket_message) ⇒ Object

:nodoc:


86
87
88
89
90
91
92
# File 'actioncable/lib/action_cable/connection/base.rb', line 86

def dispatch_websocket_message(websocket_message) #:nodoc:
  if websocket.alive?
    subscriptions.execute_command decode(websocket_message)
  else
    logger.error "Ignoring message processed after the WebSocket was closed: #{websocket_message.inspect})"
  end
end

#on_close(reason, code) ⇒ Object

:nodoc:


135
136
137
# File 'actioncable/lib/action_cable/connection/base.rb', line 135

def on_close(reason, code) # :nodoc:
  send_async :handle_close
end

#on_error(message) ⇒ Object

:nodoc:


131
132
133
# File 'actioncable/lib/action_cable/connection/base.rb', line 131

def on_error(message) # :nodoc:
  # игнорировать
end

#on_message(message) ⇒ Object

:nodoc:


127
128
129
# File 'actioncable/lib/action_cable/connection/base.rb', line 127

def on_message(message) # :nodoc:
  message_buffer.append message
end

#on_openObject

:nodoc:


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

def on_open # :nodoc:
  send_async :handle_open
end

#processObject

Вызывается сервером, когда установлено новое соединение WebSocket. Здесь настраиваются колбэки, предназначенные для перезаписи пользователем. Этот метод не следует вызывать напрямую – вместо этого используйте колбэки #connect (и #disconnect).


70
71
72
73
74
75
76
77
78
# File 'actioncable/lib/action_cable/connection/base.rb', line 70

def process #:nodoc:
  logger.info started_request_message

  if websocket.possible? && allow_request_origin?
    respond_to_successful_request
  else
    respond_to_invalid_request
  end
end

#receive(websocket_message) ⇒ Object

Декодирует сообщения WebSocket и отправляет их по подписанным каналам. WebSocket сообщение передает всегда кодированный JSON.


82
83
84
# File 'actioncable/lib/action_cable/connection/base.rb', line 82

def receive(websocket_message) #:nodoc:
  send_async :dispatch_websocket_message, websocket_message
end

#send_async(method, *arguments) ⇒ Object

Вызов метода в соединении асинхронно через пул воркеров.


104
105
106
# File 'actioncable/lib/action_cable/connection/base.rb', line 104

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

#statisticsObject

Возвращает базовый хеш статистики для соединения с ключом `identifier`, `started_at`, and `subscriptions`. Это может быть возвращено путем проверки работоспособности соединения.


110
111
112
113
114
115
116
117
# File 'actioncable/lib/action_cable/connection/base.rb', line 110

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

#transmit(cable_message) ⇒ Object

:nodoc:


94
95
96
# File 'actioncable/lib/action_cable/connection/base.rb', line 94

def transmit(cable_message) # :nodoc:
  websocket.transmit encode(cable_message)
end