1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Extract Server configuration into a Configuration object

This commit is contained in:
David Heinemeier Hansson 2015-07-05 22:34:23 +02:00
parent 44e7cc324d
commit b8b50e6b04
7 changed files with 82 additions and 35 deletions

View file

@ -117,7 +117,7 @@ module ActionCable
# Tags are declared in the server but computed in the connection. This allows us per-connection tailored tags. # Tags are declared in the server but computed in the connection. This allows us per-connection tailored tags.
def new_tagged_logger def new_tagged_logger
TaggedLoggerProxy.new server.logger, TaggedLoggerProxy.new server.logger,
tags: server.log_tags.map { |tag| tag.respond_to?(:call) ? tag.call(request) : tag.to_s.camelize } tags: server.config.log_tags.map { |tag| tag.respond_to?(:call) ? tag.call(request) : tag.to_s.camelize }
end end
def started_request_message def started_request_message

View file

@ -22,8 +22,8 @@ module ActionCable
id_key = data['identifier'] id_key = data['identifier']
id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
subscription_klass = connection.server.registered_channels.detect do |channel_klass| subscription_klass = connection.server.channel_classes.detect do |channel_class|
channel_klass == id_options[:channel].safe_constantize channel_class == id_options[:channel].safe_constantize
end end
if subscription_klass if subscription_klass

View file

@ -3,6 +3,7 @@ module ActionCable
autoload :Base, 'action_cable/server/base' autoload :Base, 'action_cable/server/base'
autoload :Broadcasting, 'action_cable/server/broadcasting' autoload :Broadcasting, 'action_cable/server/broadcasting'
autoload :Connections, 'action_cable/server/connections' autoload :Connections, 'action_cable/server/connections'
autoload :Configuration, 'action_cable/server/configuration'
autoload :Worker, 'action_cable/server/worker' autoload :Worker, 'action_cable/server/worker'
end end
end end

View file

@ -4,43 +4,26 @@ module ActionCable
include ActionCable::Server::Broadcasting include ActionCable::Server::Broadcasting
include ActionCable::Server::Connections 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
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})"
end end
def call(env) def call(env)
@connection_class.new(self, env).process config.connection_class.new(self, env).process
end end
def worker_pool 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 end
def pubsub def channel_classes
@pubsub ||= redis.pubsub @channel_classes ||= begin
end config.channel_paths.each { |channel_path| require channel_path }
config.channel_class_names.collect { |name| name.constantize }
def redis
@redis ||= begin
redis = EM::Hiredis.connect(@redis_config[:url])
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 end
@ -48,10 +31,22 @@ module ActionCable
@remote_connections ||= RemoteConnections.new(self) @remote_connections ||= RemoteConnections.new(self)
end end
def connection_identifiers def pubsub
@connection_class.identifiers @pubsub ||= redis.pubsub
end end
def redis
@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
end
end
def connection_identifiers
config.connection_class.identifiers
end end
end end
end end

View file

@ -10,7 +10,7 @@ module ActionCable
end end
def broadcasting_redis def broadcasting_redis
@broadcasting_redis ||= Redis.new(redis_config) @broadcasting_redis ||= Redis.new(config.redis)
end end
private private

View file

@ -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

View file

@ -17,7 +17,7 @@ class ServerTest < ActionCableTest
end end
test "channel registration" do test "channel registration" do
assert_equal ChatServer.registered_channels, Set.new([ ChatChannel ]) assert_equal ChatServer.channel_classes, Set.new([ ChatChannel ])
end end
test "subscribing to a channel with valid params" do test "subscribing to a channel with valid params" do