lib/anycable/rails/actioncable/connection.rb in anycable-rails-0.5.5 vs lib/anycable/rails/actioncable/connection.rb in anycable-rails-0.6.0.rc1

- old
+ new

@@ -4,14 +4,18 @@ require "anycable/rails/refinements/subscriptions" require "anycable/rails/actioncable/channel" module ActionCable module Connection - # rubocop:disable Metrics/ClassLength + # rubocop: disable Metrics/ClassLength class Base # :nodoc: - using Anycable::Refinements::Subscriptions + # We store logger tags in identifiers to be able + # to re-use them in the subsequent calls + LOG_TAGS_IDENTIFIER = "__ltags__" + using AnyCable::Refinements::Subscriptions + attr_reader :socket class << self def call(socket, **options) new(socket, options) @@ -25,13 +29,15 @@ end end end end - def initialize(socket, identifiers: '{}', subscriptions: []) + def initialize(socket, identifiers: "{}", subscriptions: []) @ids = ActiveSupport::JSON.decode(identifiers) + @ltags = ids.delete(LOG_TAGS_IDENTIFIER) + @cached_ids = {} @env = socket.env @coder = ActiveSupport::JSON @socket = socket @subscriptions = ActionCable::Connection::Subscriptions.new(self) @@ -41,15 +47,16 @@ end def handle_open logger.info started_request_message if access_logs? + verify_origin! + connect if respond_to?(:connect) send_welcome_message rescue ActionCable::Connection::Authorization::UnauthorizedError - logger.info finished_request_message('Rejected') if access_logs? - close + reject_request end def handle_close logger.info finished_request_message if access_logs? @@ -86,58 +93,85 @@ end # Generate identifiers info. # Converts GlobalID compatible vars to corresponding global IDs params. def identifiers_hash - identifiers.each_with_object({}) do |id, acc| + obj = { LOG_TAGS_IDENTIFIER => fetch_ltags } + + identifiers.each_with_object(obj) do |id, acc| obj = instance_variable_get("@#{id}") next unless obj acc[id] = obj.try(:to_gid_param) || obj - end + end.compact end def identifiers_json identifiers_hash.to_json end # Fetch identifier and deserialize if neccessary def fetch_identifier(name) @cached_ids[name] ||= @cached_ids.fetch(name) do - val = @ids[name.to_s] + val = ids[name.to_s] next val unless val.is_a?(String) GlobalID::Locator.locate(val) || val end end def logger - Anycable.logger + @logger ||= TaggedLoggerProxy.new(AnyCable.logger, tags: ltags || []) end private + attr_reader :ids, :ltags + def started_request_message - 'Started "%s"%s for %s at %s' % [ - request.filtered_path, - " [Anycable]", - request.ip, - Time.now.to_s - ] + format( + 'Started "%s"%s for %s at %s', + request.filtered_path, " [AnyCable]", request.ip, Time.now.to_s + ) end def finished_request_message(reason = "Closed") - 'Finished "%s"%s for %s at %s (%s)' % [ - request.filtered_path, - " [Anycable]", - request.ip, - Time.now.to_s, - reason - ] + format( + 'Finished "%s"%s for %s at %s (%s)', + request.filtered_path, " [AnyCable]", request.ip, Time.now.to_s, reason + ) end def access_logs? - Anycable.config.access_logs_disabled == false + AnyCable.config.access_logs_disabled == false + end + + def fetch_ltags + if instance_variable_defined?(:@logger) + logger.tags + else + ltags + end + end + + def server + ActionCable.server + end + + def verify_origin! + return unless socket.env.key?("HTTP_ORIGIN") + + return if allow_request_origin? + + raise( + ActionCable::Connection::Authorization::UnauthorizedError, + "Origin is not allowed" + ) + end + + def reject_request + logger.info finished_request_message("Rejected") if access_logs? + close end end # rubocop:enable Metrics/ClassLength end end