From b8b50e6b043a5b1900922629edf250ccb6006085 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 5 Jul 2015 22:34:23 +0200 Subject: Extract Server configuration into a Configuration object --- lib/action_cable/server/base.rb | 47 +++++++++++++---------------- lib/action_cable/server/broadcasting.rb | 2 +- lib/action_cable/server/configuration.rb | 51 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 lib/action_cable/server/configuration.rb (limited to 'lib/action_cable/server') diff --git a/lib/action_cable/server/base.rb b/lib/action_cable/server/base.rb index fd3e5e4020..3d1d9e71ff 100644 --- a/lib/action_cable/server/base.rb +++ b/lib/action_cable/server/base.rb @@ -4,28 +4,31 @@ module ActionCable include ActionCable::Server::Broadcasting include ActionCable::Server::Connections - cattr_accessor(:logger, instance_reader: true) { Rails.logger } + cattr_accessor(:config, instance_accessor: true) { ActionCable::Server::Configuration.new } + + def self.logger; config.logger; end + delegate :logger, to: :config - attr_accessor :registered_channels, :redis_config, :log_tags - - def initialize(redis_config:, channels:, worker_pool_size: 100, connection: Connection, log_tags: [ 'ActionCable' ]) - @redis_config = redis_config.with_indifferent_access - @registered_channels = Set.new(channels) - @worker_pool_size = worker_pool_size - @connection_class = connection - @log_tags = log_tags - - @connections = [] - - logger.info "[ActionCable] Initialized server (redis_config: #{@redis_config.inspect}, worker_pool_size: #{@worker_pool_size})" + def initialize end def call(env) - @connection_class.new(self, env).process + config.connection_class.new(self, env).process end def worker_pool - @worker_pool ||= ActionCable::Server::Worker.pool(size: @worker_pool_size) + @worker_pool ||= ActionCable::Server::Worker.pool(size: config.worker_pool_size) + end + + def channel_classes + @channel_classes ||= begin + config.channel_paths.each { |channel_path| require channel_path } + config.channel_class_names.collect { |name| name.constantize } + end + end + + def remote_connections + @remote_connections ||= RemoteConnections.new(self) end def pubsub @@ -33,25 +36,17 @@ module ActionCable end def redis - @redis ||= begin - redis = EM::Hiredis.connect(@redis_config[:url]) + @redis ||= EM::Hiredis.connect(config.redis[:url]).tap do |redis| redis.on(:reconnect_failed) do logger.info "[ActionCable] Redis reconnect failed." # logger.info "[ActionCable] Redis reconnected. Closing all the open connections." # @connections.map &:close - end - redis + end end end - def remote_connections - @remote_connections ||= RemoteConnections.new(self) - end - def connection_identifiers - @connection_class.identifiers - end - + config.connection_class.identifiers end end end diff --git a/lib/action_cable/server/broadcasting.rb b/lib/action_cable/server/broadcasting.rb index 6376e88de0..105ccb2b5c 100644 --- a/lib/action_cable/server/broadcasting.rb +++ b/lib/action_cable/server/broadcasting.rb @@ -10,7 +10,7 @@ module ActionCable end def broadcasting_redis - @broadcasting_redis ||= Redis.new(redis_config) + @broadcasting_redis ||= Redis.new(config.redis) end private diff --git a/lib/action_cable/server/configuration.rb b/lib/action_cable/server/configuration.rb new file mode 100644 index 0000000000..c5783f30e0 --- /dev/null +++ b/lib/action_cable/server/configuration.rb @@ -0,0 +1,51 @@ +module ActionCable + module Server + class Configuration + attr_accessor :logger, :log_tags + attr_accessor :connection_class, :worker_pool_size + attr_accessor :redis_path, :channels_path + + def initialize + @logger = Rails.logger + @log_tags = [] + + @connection_class = ApplicationCable::Connection + @worker_pool_size = 100 + + @redis_path = Rails.root.join('config/redis/cable.yml') + @channels_path = Rails.root.join('app/channels') + end + + def channel_paths + @channels ||= Dir["#{channels_path}/**/*_channel.rb"] + end + + def channel_class_names + @channel_class_names ||= channel_paths.collect do |channel_path| + Pathname.new(channel_path).basename.to_s.split('.').first.camelize + end + end + + def redis + @redis ||= config_for(redis_path).with_indifferent_access + end + + private + # FIXME: Extract this from Rails::Application in a way it can be used here. + def config_for(path) + if path.exist? + require "yaml" + require "erb" + (YAML.load(ERB.new(path.read).result) || {})[Rails.env] || {} + else + raise "Could not load configuration. No such file - #{path}" + end + rescue Psych::SyntaxError => e + raise "YAML syntax error occurred while parsing #{path}. " \ + "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \ + "Error: #{e.message}" + end + end + end +end + -- cgit v1.2.3