diff options
Diffstat (limited to 'actioncable/lib/action_cable')
40 files changed, 139 insertions, 136 deletions
diff --git a/actioncable/lib/action_cable/channel.rb b/actioncable/lib/action_cable/channel.rb index 7ae262ce5f..d2f6fbbbc7 100644 --- a/actioncable/lib/action_cable/channel.rb +++ b/actioncable/lib/action_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Channel extend ActiveSupport::Autoload diff --git a/actioncable/lib/action_cable/channel/base.rb b/actioncable/lib/action_cable/channel/base.rb index 718f630f58..c5ad749bfe 100644 --- a/actioncable/lib/action_cable/channel/base.rb +++ b/actioncable/lib/action_cable/channel/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" module ActionCable @@ -205,7 +207,9 @@ module ActionCable # Transmit a hash of data to the subscriber. The hash will automatically be wrapped in a JSON envelope with # the proper channel identifier marked as the recipient. def transmit(data, via: nil) # :doc: - logger.debug "#{self.class.name} transmitting #{data.inspect.truncate(300)}".tap { |m| m << " (via #{via})" if via } + status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}" + status += " (via #{via})" if via + logger.debug(status) payload = { channel_class: self.class.name, data: data, via: via } ActiveSupport::Notifications.instrument("transmit.action_cable", payload) do @@ -266,7 +270,7 @@ module ActionCable end def action_signature(action, data) - "#{self.class.name}##{action}".tap do |signature| + "#{self.class.name}##{action}".dup.tap do |signature| if (arguments = data.except("action")).any? signature << "(#{arguments.inspect})" end diff --git a/actioncable/lib/action_cable/channel/broadcasting.rb b/actioncable/lib/action_cable/channel/broadcasting.rb index 23ed4ec943..9a96720f4a 100644 --- a/actioncable/lib/action_cable/channel/broadcasting.rb +++ b/actioncable/lib/action_cable/channel/broadcasting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/object/to_param" module ActionCable @@ -7,7 +9,7 @@ module ActionCable delegate :broadcasting_for, to: :class - class_methods do + module ClassMethods # Broadcast a hash to a unique broadcasting for this <tt>model</tt> in this channel. def broadcast_to(model, message) ActionCable.server.broadcast(broadcasting_for([ channel_name, model ]), message) diff --git a/actioncable/lib/action_cable/channel/callbacks.rb b/actioncable/lib/action_cable/channel/callbacks.rb index c740132c94..e4cb19b26a 100644 --- a/actioncable/lib/action_cable/channel/callbacks.rb +++ b/actioncable/lib/action_cable/channel/callbacks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/callbacks" module ActionCable @@ -11,7 +13,7 @@ module ActionCable define_callbacks :unsubscribe end - class_methods do + module ClassMethods def before_subscribe(*methods, &block) set_callback(:subscribe, :before, *methods, &block) end diff --git a/actioncable/lib/action_cable/channel/naming.rb b/actioncable/lib/action_cable/channel/naming.rb index b565cb3cac..9c324a2a53 100644 --- a/actioncable/lib/action_cable/channel/naming.rb +++ b/actioncable/lib/action_cable/channel/naming.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module ActionCable module Channel module Naming extend ActiveSupport::Concern - class_methods do + module ClassMethods # Returns the name of the channel, underscored, without the <tt>Channel</tt> ending. # If the channel is in a namespace, then the namespaces are represented by single # colon separators in the channel name. diff --git a/actioncable/lib/action_cable/channel/periodic_timers.rb b/actioncable/lib/action_cable/channel/periodic_timers.rb index c9daa0bcd3..830b3efa3c 100644 --- a/actioncable/lib/action_cable/channel/periodic_timers.rb +++ b/actioncable/lib/action_cable/channel/periodic_timers.rb @@ -1,11 +1,12 @@ +# frozen_string_literal: true + module ActionCable module Channel module PeriodicTimers extend ActiveSupport::Concern included do - class_attribute :periodic_timers, instance_reader: false - self.periodic_timers = [] + class_attribute :periodic_timers, instance_reader: false, default: [] after_subscribe :start_periodic_timers after_unsubscribe :stop_periodic_timers diff --git a/actioncable/lib/action_cable/channel/streams.rb b/actioncable/lib/action_cable/channel/streams.rb index dbba333353..81c2c38064 100644 --- a/actioncable/lib/action_cable/channel/streams.rb +++ b/actioncable/lib/action_cable/channel/streams.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Channel # Streams allow channels to route broadcastings to the subscriber. A broadcasting is, as discussed elsewhere, a pubsub queue where any data diff --git a/actioncable/lib/action_cable/connection.rb b/actioncable/lib/action_cable/connection.rb index 902efb07e2..804b89a707 100644 --- a/actioncable/lib/action_cable/connection.rb +++ b/actioncable/lib/action_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Connection extend ActiveSupport::Autoload diff --git a/actioncable/lib/action_cable/connection/authorization.rb b/actioncable/lib/action_cable/connection/authorization.rb index 989a67d6df..a22179d988 100644 --- a/actioncable/lib/action_cable/connection/authorization.rb +++ b/actioncable/lib/action_cable/connection/authorization.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Connection module Authorization diff --git a/actioncable/lib/action_cable/connection/base.rb b/actioncable/lib/action_cable/connection/base.rb index 0a517a532d..11a1f1a5e8 100644 --- a/actioncable/lib/action_cable/connection/base.rb +++ b/actioncable/lib/action_cable/connection/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "action_dispatch" module ActionCable @@ -24,7 +26,7 @@ module ActionCable # # private # def find_verified_user - # User.find_by_identity(cookies.signed[:identity_id]) || + # User.find_by_identity(cookies.encrypted[:identity_id]) || # reject_unauthorized_connection # end # end @@ -126,20 +128,18 @@ module ActionCable end def on_error(message) # :nodoc: - # ignore + # log errors to make diagnosing socket errors easier + logger.error "WebSocket error occurred: #{message}" end def on_close(reason, code) # :nodoc: send_async :handle_close end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected + private attr_reader :websocket attr_reader :message_buffer - private # The request that initiated the WebSocket connection is available here. This gives access to the environment, cookies, etc. def request # :doc: @request ||= begin diff --git a/actioncable/lib/action_cable/connection/client_socket.rb b/actioncable/lib/action_cable/connection/client_socket.rb index c7e30e78c8..4b1964c4ae 100644 --- a/actioncable/lib/action_cable/connection/client_socket.rb +++ b/actioncable/lib/action_cable/connection/client_socket.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "websocket/driver" module ActionCable @@ -19,7 +21,7 @@ module ActionCable return true if env["HTTP_X_FORWARDED_PROTO"] == "https" return true if env["rack.url_scheme"] == "https" - return false + false end CONNECTING = 0 @@ -81,7 +83,7 @@ module ActionCable when Numeric then @driver.text(message.to_s) when String then @driver.text(message) when Array then @driver.binary(message) - else false + else false end end diff --git a/actioncable/lib/action_cable/connection/identification.rb b/actioncable/lib/action_cable/connection/identification.rb index c91a1d1fd7..cc544685dd 100644 --- a/actioncable/lib/action_cable/connection/identification.rb +++ b/actioncable/lib/action_cable/connection/identification.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" module ActionCable @@ -6,11 +8,10 @@ module ActionCable extend ActiveSupport::Concern included do - class_attribute :identifiers - self.identifiers = Set.new + class_attribute :identifiers, default: Set.new end - class_methods do + module ClassMethods # Mark a key as being a connection identifier index that can then be used to find the specific connection again later. # Common identifiers are current_user and current_account, but could be anything, really. # diff --git a/actioncable/lib/action_cable/connection/internal_channel.rb b/actioncable/lib/action_cable/connection/internal_channel.rb index 8f0ec766c3..f03904137b 100644 --- a/actioncable/lib/action_cable/connection/internal_channel.rb +++ b/actioncable/lib/action_cable/connection/internal_channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Connection # Makes it possible for the RemoteConnection to disconnect a specific connection. diff --git a/actioncable/lib/action_cable/connection/message_buffer.rb b/actioncable/lib/action_cable/connection/message_buffer.rb index 4ccd322644..965841b67e 100644 --- a/actioncable/lib/action_cable/connection/message_buffer.rb +++ b/actioncable/lib/action_cable/connection/message_buffer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Connection # Allows us to buffer messages received from the WebSocket before the Connection has been fully initialized, and is ready to receive them. @@ -28,13 +30,10 @@ module ActionCable receive_buffered_messages end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected + private attr_reader :connection attr_reader :buffered_messages - private def valid?(message) message.is_a?(String) end diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb index e620b93845..4873026b71 100644 --- a/actioncable/lib/action_cable/connection/stream.rb +++ b/actioncable/lib/action_cable/connection/stream.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "thread" module ActionCable diff --git a/actioncable/lib/action_cable/connection/stream_event_loop.rb b/actioncable/lib/action_cable/connection/stream_event_loop.rb index 2d1af0ff9f..d95afc50ba 100644 --- a/actioncable/lib/action_cable/connection/stream_event_loop.rb +++ b/actioncable/lib/action_cable/connection/stream_event_loop.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "nio" require "thread" diff --git a/actioncable/lib/action_cable/connection/subscriptions.rb b/actioncable/lib/action_cable/connection/subscriptions.rb index 44bce1e195..1ad8d05107 100644 --- a/actioncable/lib/action_cable/connection/subscriptions.rb +++ b/actioncable/lib/action_cable/connection/subscriptions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/core_ext/hash/indifferent_access" module ActionCable @@ -41,7 +43,7 @@ module ActionCable def remove(data) logger.info "Unsubscribing from channel: #{data['identifier']}" - remove_subscription subscriptions[data["identifier"]] + remove_subscription find(data) end def remove_subscription(subscription) @@ -61,12 +63,8 @@ module ActionCable subscriptions.each { |id, channel| remove_subscription(channel) } end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected - attr_reader :connection, :subscriptions - private + attr_reader :connection, :subscriptions delegate :logger, to: :connection def find(data) diff --git a/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb b/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb index aef549aa86..85831806a9 100644 --- a/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb +++ b/actioncable/lib/action_cable/connection/tagged_logger_proxy.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Connection # Allows the use of per-connection tags against the server logger. This wouldn't work using the traditional diff --git a/actioncable/lib/action_cable/connection/web_socket.rb b/actioncable/lib/action_cable/connection/web_socket.rb index 03eb6e2ea8..31f29fdd2f 100644 --- a/actioncable/lib/action_cable/connection/web_socket.rb +++ b/actioncable/lib/action_cable/connection/web_socket.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "websocket/driver" module ActionCable module Connection # Wrap the real socket to minimize the externally-presented API - class WebSocket + class WebSocket # :nodoc: def initialize(env, event_target, event_loop, protocols: ActionCable::INTERNAL[:protocols]) @websocket = ::WebSocket::Driver.websocket?(env) ? ClientSocket.new(env, event_target, event_loop, protocols) : nil end @@ -32,9 +34,7 @@ module ActionCable websocket.rack_response end - # TODO Change this to private once we've dropped Ruby 2.2 support. - # Workaround for Ruby 2.2 "private attribute?" warning. - protected + private attr_reader :websocket end end diff --git a/actioncable/lib/action_cable/engine.rb b/actioncable/lib/action_cable/engine.rb index 63a26636a0..53cbb597cd 100644 --- a/actioncable/lib/action_cable/engine.rb +++ b/actioncable/lib/action_cable/engine.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rails" require "action_cable" require "action_cable/helpers/action_cable_helper" diff --git a/actioncable/lib/action_cable/gem_version.rb b/actioncable/lib/action_cable/gem_version.rb index 5d6f9af0bb..cd1d9bccef 100644 --- a/actioncable/lib/action_cable/gem_version.rb +++ b/actioncable/lib/action_cable/gem_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable # Returns the version of the currently loaded Action Cable as a <tt>Gem::Version</tt>. def self.gem_version @@ -5,8 +7,8 @@ module ActionCable end module VERSION - MAJOR = 5 - MINOR = 2 + MAJOR = 6 + MINOR = 0 TINY = 0 PRE = "alpha" diff --git a/actioncable/lib/action_cable/helpers/action_cable_helper.rb b/actioncable/lib/action_cable/helpers/action_cable_helper.rb index f53be0bc31..df16c02e83 100644 --- a/actioncable/lib/action_cable/helpers/action_cable_helper.rb +++ b/actioncable/lib/action_cable/helpers/action_cable_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Helpers module ActionCableHelper diff --git a/actioncable/lib/action_cable/remote_connections.rb b/actioncable/lib/action_cable/remote_connections.rb index d2856bc6ae..283400d9e7 100644 --- a/actioncable/lib/action_cable/remote_connections.rb +++ b/actioncable/lib/action_cable/remote_connections.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require "active_support/core_ext/module/redefine_method" + module ActionCable # If you need to disconnect a given connection, you can go through the # RemoteConnections. You can find the connections you're looking for by @@ -45,13 +49,14 @@ module ActionCable end # Returns all the identifiers that were applied to this connection. - def identifiers + redefine_method :identifiers do server.connection_identifiers end - private + protected attr_reader :server + private def set_identifier_instance_vars(ids) raise InvalidIdentifiersError unless valid_identifiers?(ids) ids.each { |k, v| instance_variable_set("@#{k}", v) } diff --git a/actioncable/lib/action_cable/server.rb b/actioncable/lib/action_cable/server.rb index 22f9353825..8d485a44f6 100644 --- a/actioncable/lib/action_cable/server.rb +++ b/actioncable/lib/action_cable/server.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Server extend ActiveSupport::Autoload diff --git a/actioncable/lib/action_cable/server/base.rb b/actioncable/lib/action_cable/server/base.rb index 419eccd73c..1ee03f6dfc 100644 --- a/actioncable/lib/action_cable/server/base.rb +++ b/actioncable/lib/action_cable/server/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "monitor" module ActionCable @@ -10,7 +12,7 @@ module ActionCable include ActionCable::Server::Broadcasting include ActionCable::Server::Connections - cattr_accessor(:config, instance_accessor: true) { ActionCable::Server::Configuration.new } + cattr_accessor :config, instance_accessor: true, default: ActionCable::Server::Configuration.new def self.logger; config.logger; end delegate :logger, to: :config @@ -28,7 +30,7 @@ module ActionCable config.connection_class.call.new(self, env).process end - # Disconnect all the connections identified by `identifiers` on this server or any others via RemoteConnections. + # Disconnect all the connections identified by +identifiers+ on this server or any others via RemoteConnections. def disconnect(identifiers) remote_connections.where(identifiers).disconnect end diff --git a/actioncable/lib/action_cable/server/broadcasting.rb b/actioncable/lib/action_cable/server/broadcasting.rb index 7fcd6c6587..bc54d784b3 100644 --- a/actioncable/lib/action_cable/server/broadcasting.rb +++ b/actioncable/lib/action_cable/server/broadcasting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Server # Broadcasting is how other parts of your application can send messages to a channel's subscribers. As explained in Channel, most of the time, these diff --git a/actioncable/lib/action_cable/server/configuration.rb b/actioncable/lib/action_cable/server/configuration.rb index 17e0dee064..26209537df 100644 --- a/actioncable/lib/action_cable/server/configuration.rb +++ b/actioncable/lib/action_cable/server/configuration.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Server # An instance of this configuration object is available via ActionCable.server.config, which allows you to tweak Action Cable configuration @@ -23,13 +25,26 @@ module ActionCable # Also makes sure proper dependencies are required. def pubsub_adapter adapter = (cable.fetch("adapter") { "redis" }) + + # Require the adapter itself and give useful feedback about + # 1. Missing adapter gems and + # 2. Adapter gems' missing dependencies. path_to_adapter = "action_cable/subscription_adapter/#{adapter}" begin require path_to_adapter - rescue Gem::LoadError => e - raise Gem::LoadError, "Specified '#{adapter}' for Action Cable pubsub adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by Action Cable)." rescue LoadError => e - raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/cable.yml is valid. If you use an adapter other than 'postgresql' or 'redis' add the necessary adapter gem to the Gemfile.", e.backtrace + # We couldn't require the adapter itself. Raise an exception that + # points out config typos and missing gems. + if e.path == path_to_adapter + # We can assume that a non-builtin adapter was specified, so it's + # either misspelled or missing from Gemfile. + raise e.class, "Could not load the '#{adapter}' Action Cable pubsub adapter. Ensure that the adapter is spelled correctly in config/cable.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace + + # Bubbled up from the adapter require. Prefix the exception message + # with some guidance about how to address it and reraise. + else + raise e.class, "Error loading the '#{adapter}' Action Cable pubsub adapter. Missing a gem it depends on? #{e.message}", e.backtrace + end end adapter = adapter.camelize diff --git a/actioncable/lib/action_cable/server/connections.rb b/actioncable/lib/action_cable/server/connections.rb index 5e61b4e335..39557d63a7 100644 --- a/actioncable/lib/action_cable/server/connections.rb +++ b/actioncable/lib/action_cable/server/connections.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Server # Collection class for all the connections that have been established on this specific server. Remember, usually you'll run many Action Cable servers, so diff --git a/actioncable/lib/action_cable/server/worker.rb b/actioncable/lib/action_cable/server/worker.rb index 43639c27af..c69cc4ac31 100644 --- a/actioncable/lib/action_cable/server/worker.rb +++ b/actioncable/lib/action_cable/server/worker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support/callbacks" require "active_support/core_ext/module/attribute_accessors_per_thread" require "concurrent" diff --git a/actioncable/lib/action_cable/server/worker/active_record_connection_management.rb b/actioncable/lib/action_cable/server/worker/active_record_connection_management.rb index c1e4aa8103..2e378d4bf3 100644 --- a/actioncable/lib/action_cable/server/worker/active_record_connection_management.rb +++ b/actioncable/lib/action_cable/server/worker/active_record_connection_management.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module Server class Worker diff --git a/actioncable/lib/action_cable/subscription_adapter.rb b/actioncable/lib/action_cable/subscription_adapter.rb index 596269ab9b..bcece8d33b 100644 --- a/actioncable/lib/action_cable/subscription_adapter.rb +++ b/actioncable/lib/action_cable/subscription_adapter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module SubscriptionAdapter extend ActiveSupport::Autoload diff --git a/actioncable/lib/action_cable/subscription_adapter/async.rb b/actioncable/lib/action_cable/subscription_adapter/async.rb index 46819dbfec..c9930299c7 100644 --- a/actioncable/lib/action_cable/subscription_adapter/async.rb +++ b/actioncable/lib/action_cable/subscription_adapter/async.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "action_cable/subscription_adapter/inline" module ActionCable diff --git a/actioncable/lib/action_cable/subscription_adapter/base.rb b/actioncable/lib/action_cable/subscription_adapter/base.rb index 796db5ffa3..34077707fd 100644 --- a/actioncable/lib/action_cable/subscription_adapter/base.rb +++ b/actioncable/lib/action_cable/subscription_adapter/base.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module SubscriptionAdapter class Base diff --git a/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb index 8b293cc785..df0aa040f5 100644 --- a/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb +++ b/actioncable/lib/action_cable/subscription_adapter/channel_prefix.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module SubscriptionAdapter module ChannelPrefix # :nodoc: diff --git a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb b/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb deleted file mode 100644 index ed8f315791..0000000000 --- a/actioncable/lib/action_cable/subscription_adapter/evented_redis.rb +++ /dev/null @@ -1,87 +0,0 @@ -require "thread" - -gem "em-hiredis", "~> 0.3.0" -gem "redis", "~> 3.0" -require "em-hiredis" -require "redis" - -EventMachine.epoll if EventMachine.epoll? -EventMachine.kqueue if EventMachine.kqueue? - -module ActionCable - module SubscriptionAdapter - class EventedRedis < Base # :nodoc: - prepend ChannelPrefix - - @@mutex = Mutex.new - - # Overwrite this factory method for EventMachine Redis connections if you want to use a different Redis connection library than EM::Hiredis. - # This is needed, for example, when using Makara proxies for distributed Redis. - cattr_accessor(:em_redis_connector) { ->(config) { EM::Hiredis.connect(config[:url]) } } - - # Overwrite this factory method for Redis connections if you want to use a different Redis connection library than Redis. - # This is needed, for example, when using Makara proxies for distributed Redis. - cattr_accessor(:redis_connector) { ->(config) { ::Redis.new(url: config[:url]) } } - - def initialize(*) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - The "evented_redis" subscription adapter is deprecated and - will be removed in Rails 5.2. Please use the "redis" adapter - instead. - MSG - - super - @redis_connection_for_broadcasts = @redis_connection_for_subscriptions = nil - end - - def broadcast(channel, payload) - redis_connection_for_broadcasts.publish(channel, payload) - end - - def subscribe(channel, message_callback, success_callback = nil) - redis_connection_for_subscriptions.pubsub.subscribe(channel, &message_callback).tap do |result| - result.callback { |reply| success_callback.call } if success_callback - end - end - - def unsubscribe(channel, message_callback) - redis_connection_for_subscriptions.pubsub.unsubscribe_proc(channel, message_callback) - end - - def shutdown - redis_connection_for_subscriptions.pubsub.close_connection - @redis_connection_for_subscriptions = nil - end - - private - def redis_connection_for_subscriptions - ensure_reactor_running - @redis_connection_for_subscriptions || @server.mutex.synchronize do - @redis_connection_for_subscriptions ||= self.class.em_redis_connector.call(@server.config.cable).tap do |redis| - redis.on(:reconnect_failed) do - @logger.error "[ActionCable] Redis reconnect failed." - end - - redis.on(:failed) do - @logger.error "[ActionCable] Redis connection has failed." - end - end - end - end - - def redis_connection_for_broadcasts - @redis_connection_for_broadcasts || @server.mutex.synchronize do - @redis_connection_for_broadcasts ||= self.class.redis_connector.call(@server.config.cable) - end - end - - def ensure_reactor_running - return if EventMachine.reactor_running? && EventMachine.reactor_thread - @@mutex.synchronize do - Thread.new { EventMachine.run } unless EventMachine.reactor_running? - Thread.pass until EventMachine.reactor_running? && EventMachine.reactor_thread - end - end - end - end -end diff --git a/actioncable/lib/action_cable/subscription_adapter/inline.rb b/actioncable/lib/action_cable/subscription_adapter/inline.rb index 81357faead..d2c85c1c8d 100644 --- a/actioncable/lib/action_cable/subscription_adapter/inline.rb +++ b/actioncable/lib/action_cable/subscription_adapter/inline.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module SubscriptionAdapter class Inline < Base # :nodoc: diff --git a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb index e7be4c606e..50ec438c3a 100644 --- a/actioncable/lib/action_cable/subscription_adapter/postgresql.rb +++ b/actioncable/lib/action_cable/subscription_adapter/postgresql.rb @@ -1,6 +1,9 @@ -gem "pg", "~> 0.18" +# frozen_string_literal: true + +gem "pg", ">= 0.18", "< 2.0" require "pg" require "thread" +require "digest/sha1" module ActionCable module SubscriptionAdapter @@ -12,16 +15,16 @@ module ActionCable def broadcast(channel, payload) with_broadcast_connection do |pg_conn| - pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel)}, '#{pg_conn.escape_string(payload)}'") + pg_conn.exec("NOTIFY #{pg_conn.escape_identifier(channel_identifier(channel))}, '#{pg_conn.escape_string(payload)}'") end end def subscribe(channel, callback, success_callback = nil) - listener.add_subscriber(channel, callback, success_callback) + listener.add_subscriber(channel_identifier(channel), callback, success_callback) end def unsubscribe(channel, callback) - listener.remove_subscriber(channel, callback) + listener.remove_subscriber(channel_identifier(channel), callback) end def shutdown @@ -51,6 +54,10 @@ module ActionCable end private + def channel_identifier(channel) + channel.size > 63 ? Digest::SHA1.hexdigest(channel) : channel + end + def listener @listener || @server.mutex.synchronize { @listener ||= Listener.new(self, @server.event_loop) } end diff --git a/actioncable/lib/action_cable/subscription_adapter/redis.rb b/actioncable/lib/action_cable/subscription_adapter/redis.rb index 41a6e55822..c28951608f 100644 --- a/actioncable/lib/action_cable/subscription_adapter/redis.rb +++ b/actioncable/lib/action_cable/subscription_adapter/redis.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "thread" -gem "redis", "~> 3.0" +gem "redis", ">= 3", "< 5" require "redis" module ActionCable @@ -8,9 +10,11 @@ module ActionCable class Redis < Base # :nodoc: prepend ChannelPrefix - # Overwrite this factory method for redis connections if you want to use a different Redis library than Redis. + # Overwrite this factory method for Redis connections if you want to use a different Redis library than the redis gem. # This is needed, for example, when using Makara proxies for distributed Redis. - cattr_accessor(:redis_connector) { ->(config) { ::Redis.new(url: config[:url]) } } + cattr_accessor :redis_connector, default: ->(config) do + ::Redis.new(config.slice(:url, :host, :port, :db, :password)) + end def initialize(*) super @@ -72,7 +76,7 @@ module ActionCable def listen(conn) conn.without_reconnect do - original_client = conn.client + original_client = conn.respond_to?(:_client) ? conn._client : conn.client conn.subscribe("_action_cable_internal") do |on| on.subscribe do |chan, count| diff --git a/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb b/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb index 4cce86dcca..01cdc2dfa1 100644 --- a/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb +++ b/actioncable/lib/action_cable/subscription_adapter/subscriber_map.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionCable module SubscriptionAdapter class SubscriberMap diff --git a/actioncable/lib/action_cable/version.rb b/actioncable/lib/action_cable/version.rb index d6081409f0..86115c6065 100644 --- a/actioncable/lib/action_cable/version.rb +++ b/actioncable/lib/action_cable/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "gem_version" module ActionCable |