Class: ActionCable::Server::Socket

Inherits:
Object
  • Object
show all
Defined in:
lib/action_cable/server/socket.rb,
lib/action_cable/server/socket/stream.rb,
lib/action_cable/server/socket/web_socket.rb,
lib/action_cable/server/socket/client_socket.rb,
lib/action_cable/server/socket/message_buffer.rb

Overview

This class encapsulates all the low-level logic of working with the underlying WebSocket conenctions and delegate all the business-logic to the user-level connection object (e.g., ApplicationCable::Connection). This connection object is also responsible for handling encoding and decoding of messages, so the user-level connection object shouldn’t know about such details.

Defined Under Namespace

Classes: ClientSocket, MessageBuffer, Stream, WebSocket

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Socket.



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/action_cable/server/socket.rb', line 17

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

  @worker_pool = server.worker_pool
  @logger = server.new_tagged_logger { request }

  @websocket      = WebSocket.new(env, self, event_loop)
  @message_buffer = MessageBuffer.new(self)

  @protocol = nil
  @connection = config.connection_class.call.new(server, self)
end

Instance Attribute Details

#connectionObject (readonly)

Returns the value of attribute connection.



12
13
14
# File 'lib/action_cable/server/socket.rb', line 12

def connection
  @connection
end

#envObject (readonly)

Returns the value of attribute env.



12
13
14
# File 'lib/action_cable/server/socket.rb', line 12

def env
  @env
end

#loggerObject (readonly)

Returns the value of attribute logger.



12
13
14
# File 'lib/action_cable/server/socket.rb', line 12

def logger
  @logger
end

#protocolObject (readonly)

Returns the value of attribute protocol.



12
13
14
# File 'lib/action_cable/server/socket.rb', line 12

def protocol
  @protocol
end

#serverObject (readonly)

Returns the value of attribute server.



12
13
14
# File 'lib/action_cable/server/socket.rb', line 12

def server
  @server
end

#worker_poolObject (readonly)

Returns the value of attribute worker_pool.



13
14
15
# File 'lib/action_cable/server/socket.rb', line 13

def worker_pool
  @worker_pool
end

Instance Method Details

#closeObject

Close the WebSocket connection.



51
52
53
# File 'lib/action_cable/server/socket.rb', line 51

def close(...)
  websocket.close(...) if websocket.alive?
end

#dispatch_websocket_message(websocket_message) ⇒ Object

:nodoc:



78
79
80
81
82
83
84
85
86
# File 'lib/action_cable/server/socket.rb', line 78

def dispatch_websocket_message(websocket_message) # :nodoc:
  if websocket.alive?
    @connection.handle_incoming decode(websocket_message)
  else
    logger.error "Ignoring message processed after the WebSocket was closed: #{websocket_message.inspect})"
  end
rescue Exception => e
  logger.error "Could not handle incoming message: #{websocket_message.inspect} [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(" | ")}"
end

#inspectObject

:nodoc:



105
106
107
# File 'lib/action_cable/server/socket.rb', line 105

def inspect # :nodoc:
  "#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
end

#on_close(reason, code) ⇒ Object

:nodoc:



101
102
103
# File 'lib/action_cable/server/socket.rb', line 101

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

#on_error(message) ⇒ Object

:nodoc:



96
97
98
99
# File 'lib/action_cable/server/socket.rb', line 96

def on_error(message) # :nodoc:
  # log errors to make diagnosing socket errors easier
  logger.error "WebSocket error occurred: #{message}"
end

#on_message(message) ⇒ Object

:nodoc:



92
93
94
# File 'lib/action_cable/server/socket.rb', line 92

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

#on_openObject

:nodoc:



88
89
90
# File 'lib/action_cable/server/socket.rb', line 88

def on_open # :nodoc:
  send_async :handle_open
end

#perform_work(receiver, method, *args) ⇒ Object

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



56
57
58
# File 'lib/action_cable/server/socket.rb', line 56

def perform_work(receiver, method, *args)
  worker_pool.async_invoke(receiver, method, *args, connection: self)
end

#processObject

Called by the server when a new WebSocket connection is established.



31
32
33
34
35
36
37
38
39
# File 'lib/action_cable/server/socket.rb', line 31

def process # :nodoc:
  logger.info started_request_message

  if websocket.possible? && server.allow_request_origin?(env)
    respond_to_successful_request
  else
    respond_to_invalid_request
  end
end

#receive(websocket_message) ⇒ Object

Decodes WebSocket messages and dispatches them to subscribed channels. WebSocket message transfer encoding is always JSON.



74
75
76
# File 'lib/action_cable/server/socket.rb', line 74

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

#requestObject

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



65
66
67
68
69
70
# File 'lib/action_cable/server/socket.rb', line 65

def request
  @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) ⇒ Object



60
61
62
# File 'lib/action_cable/server/socket.rb', line 60

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

#transmit(cable_message) ⇒ Object

Send a non-serialized message over the WebSocket connection.



44
45
46
47
48
# File 'lib/action_cable/server/socket.rb', line 44

def transmit(cable_message)
  return unless websocket.alive?

  websocket.transmit encode(cable_message)
end