2016-08-06 13:13:46 -04:00
|
|
|
require "thread"
|
2016-01-31 10:00:00 -05:00
|
|
|
|
2016-08-06 13:13:46 -04:00
|
|
|
gem "em-hiredis", "~> 0.3.0"
|
|
|
|
gem "redis", "~> 3.0"
|
|
|
|
require "em-hiredis"
|
|
|
|
require "redis"
|
2016-01-31 10:00:00 -05:00
|
|
|
|
|
|
|
EventMachine.epoll if EventMachine.epoll?
|
|
|
|
EventMachine.kqueue if EventMachine.kqueue?
|
|
|
|
|
|
|
|
module ActionCable
|
|
|
|
module SubscriptionAdapter
|
|
|
|
class EventedRedis < Base # :nodoc:
|
|
|
|
@@mutex = Mutex.new
|
|
|
|
|
2016-02-13 21:05:04 -05:00
|
|
|
# Overwrite this factory method for EventMachine Redis connections if you want to use a different Redis connection library than EM::Hiredis.
|
2016-02-04 06:10:35 -05:00
|
|
|
# This is needed, for example, when using Makara proxies for distributed Redis.
|
|
|
|
cattr_accessor(:em_redis_connector) { ->(config) { EM::Hiredis.connect(config[:url]) } }
|
|
|
|
|
2016-02-13 21:05:04 -05:00
|
|
|
# Overwrite this factory method for Redis connections if you want to use a different Redis connection library than Redis.
|
2016-02-04 06:10:35 -05:00
|
|
|
# This is needed, for example, when using Makara proxies for distributed Redis.
|
|
|
|
cattr_accessor(:redis_connector) { ->(config) { ::Redis.new(url: config[:url]) } }
|
|
|
|
|
2016-01-31 10:00:00 -05:00
|
|
|
def initialize(*)
|
|
|
|
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
|
2016-02-04 06:10:35 -05:00
|
|
|
@redis_connection_for_subscriptions ||= self.class.em_redis_connector.call(@server.config.cable).tap do |redis|
|
2016-01-31 10:00:00 -05:00
|
|
|
redis.on(:reconnect_failed) do
|
2016-03-18 00:23:26 -04:00
|
|
|
@logger.error "[ActionCable] Redis reconnect failed."
|
2016-01-31 10:00:00 -05:00
|
|
|
end
|
2016-04-21 12:43:55 -04:00
|
|
|
|
|
|
|
redis.on(:failed) do
|
|
|
|
@logger.error "[ActionCable] Redis connection has failed."
|
|
|
|
end
|
2016-01-31 10:00:00 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def redis_connection_for_broadcasts
|
|
|
|
@redis_connection_for_broadcasts || @server.mutex.synchronize do
|
2016-02-04 06:10:35 -05:00
|
|
|
@redis_connection_for_broadcasts ||= self.class.redis_connector.call(@server.config.cable)
|
2016-01-31 10:00:00 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def ensure_reactor_running
|
|
|
|
return if EventMachine.reactor_running?
|
|
|
|
@@mutex.synchronize do
|
|
|
|
Thread.new { EventMachine.run } unless EventMachine.reactor_running?
|
|
|
|
Thread.pass until EventMachine.reactor_running?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|