lib/anycable/rails/actioncable/connection.rb in anycable-rails-0.6.5 vs lib/anycable/rails/actioncable/connection.rb in anycable-rails-1.0.0.preview1
- old
+ new
@@ -1,23 +1,26 @@
# frozen_string_literal: true
require "action_cable/connection"
require "anycable/rails/refinements/subscriptions"
require "anycable/rails/actioncable/channel"
+require "anycable/rails/session_proxy"
module ActionCable
module Connection
# rubocop: disable Metrics/ClassLength
class Base # :nodoc:
- # We store logger tags in identifiers to be able
+ # We store logger tags in the connection state to be able
# to re-use them in the subsequent calls
LOG_TAGS_IDENTIFIER = "__ltags__"
using AnyCable::Refinements::Subscriptions
attr_reader :socket
+ delegate :env, :session, to: :request
+
class << self
def call(socket, **options)
new(socket, options)
end
@@ -32,14 +35,16 @@
end
def initialize(socket, identifiers: "{}", subscriptions: [])
@ids = ActiveSupport::JSON.decode(identifiers)
- @ltags = ids.delete(LOG_TAGS_IDENTIFIER)
+ @ltags = socket.cstate.read(LOG_TAGS_IDENTIFIER).yield_self do |raw_tags|
+ next unless raw_tags
+ ActiveSupport::JSON.decode(raw_tags)
+ end
@cached_ids = {}
- @env = socket.env
@coder = ActiveSupport::JSON
@socket = socket
@subscriptions = ActionCable::Connection::Subscriptions.new(self)
# Initialize channels if any
@@ -47,16 +52,21 @@
end
def handle_open
logger.info started_request_message if access_logs?
- verify_origin!
+ verify_origin! || return
connect if respond_to?(:connect)
+
+ socket.cstate.write(LOG_TAGS_IDENTIFIER, fetch_ltags.to_json)
+
send_welcome_message
rescue ActionCable::Connection::Authorization::UnauthorizedError
- reject_request
+ reject_request(
+ ActionCable::INTERNAL[:disconnect_reasons]&.[](:unauthorized) || "unauthorized"
+ )
end
def handle_close
logger.info finished_request_message if access_logs?
@@ -82,24 +92,27 @@
false
end
end
# rubocop:enable Metrics/MethodLength
- def close
+ def close(reason: nil, reconnect: nil)
+ transmit(
+ type: ActionCable::INTERNAL[:message_types].fetch(:disconnect, "disconnect"),
+ reason: reason,
+ reconnect: reconnect
+ )
socket.close
end
def transmit(cable_message)
socket.transmit encode(cable_message)
end
# Generate identifiers info.
# Converts GlobalID compatible vars to corresponding global IDs params.
def identifiers_hash
- obj = { LOG_TAGS_IDENTIFIER => fetch_ltags }
-
- identifiers.each_with_object(obj) do |id, acc|
+ identifiers.each_with_object({}) do |id, acc|
obj = instance_variable_get("@#{id}")
next unless obj
acc[id] = obj.try(:to_gid_param) || obj
end.compact
@@ -121,10 +134,14 @@
def logger
@logger ||= TaggedLoggerProxy.new(AnyCable.logger, tags: ltags || [])
end
+ def request
+ @request ||= build_rack_request
+ end
+
private
attr_reader :ids, :ltags
def started_request_message
@@ -156,22 +173,36 @@
def server
ActionCable.server
end
def verify_origin!
- return unless socket.env.key?("HTTP_ORIGIN")
+ return true unless socket.env.key?("HTTP_ORIGIN")
- return if allow_request_origin?
+ return true if allow_request_origin?
- raise(
- ActionCable::Connection::Authorization::UnauthorizedError,
- "Origin is not allowed"
+ reject_request(
+ ActionCable::INTERNAL[:disconnect_reasons]&.[](:invalid_request) || "invalid_request"
)
+ false
end
- def reject_request
+ def reject_request(reason, reconnect = false)
logger.info finished_request_message("Rejected") if access_logs?
- close
+ close(
+ reason: reason,
+ reconnect: reconnect
+ )
+ end
+
+ def build_rack_request
+ environment = Rails.application.env_config.merge(socket.env)
+ AnyCable::Rails::Rack.app.call(environment)
+
+ ActionDispatch::Request.new(environment)
+ end
+
+ def request_loaded?
+ instance_variable_defined?(:@request)
end
end
# rubocop:enable Metrics/ClassLength
end
end