noah 0.0.5 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/.gitignore +9 -0
- data/LICENSE +201 -0
- data/README.md +68 -212
- data/Rakefile +70 -41
- data/TODO.md +59 -0
- data/bin/noah +2 -1
- data/bin/noah-watcher.rb +93 -0
- data/config.ru +6 -3
- data/config/warble.rb +18 -0
- data/examples/README.md +116 -0
- data/examples/cluster.ru +2 -0
- data/examples/custom-watcher.rb +10 -0
- data/examples/httpclient-server.rb +7 -0
- data/examples/httpclient.rb +12 -0
- data/examples/httpclient2.rb +28 -0
- data/examples/js/FABridge.js +1452 -0
- data/examples/js/WebSocketMain.swf +830 -0
- data/examples/js/swfobject.js +851 -0
- data/examples/js/web_socket.js +312 -0
- data/examples/logger.rb +11 -0
- data/examples/reconfiguring-sinatra-watcher.rb +11 -0
- data/examples/reconfiguring-sinatra.rb +32 -0
- data/examples/simple-post.rb +17 -0
- data/examples/websocket.html +24 -0
- data/examples/websocket.rb +41 -0
- data/lib/noah.rb +5 -8
- data/lib/noah/app.rb +20 -268
- data/lib/noah/application_routes.rb +70 -0
- data/lib/noah/ark.rb +0 -0
- data/lib/noah/configuration_routes.rb +81 -0
- data/lib/noah/ephemeral_routes.rb +19 -0
- data/lib/noah/helpers.rb +12 -14
- data/lib/noah/host_routes.rb +69 -0
- data/lib/noah/models.rb +86 -5
- data/lib/noah/models/applications.rb +41 -0
- data/lib/noah/models/configurations.rb +49 -0
- data/lib/noah/models/ephemerals.rb +33 -0
- data/lib/noah/models/hosts.rb +56 -0
- data/lib/noah/models/services.rb +54 -0
- data/lib/noah/models/watchers.rb +54 -0
- data/lib/noah/passthrough.rb +11 -0
- data/lib/noah/service_routes.rb +71 -0
- data/lib/noah/validations.rb +1 -0
- data/lib/noah/validations/watcher_validations.rb +48 -0
- data/lib/noah/version.rb +1 -1
- data/lib/noah/watcher.rb +75 -0
- data/lib/noah/watcher_routes.rb +12 -0
- data/lib/vendor/em-hiredis/Gemfile +4 -0
- data/lib/vendor/em-hiredis/README.md +61 -0
- data/lib/vendor/em-hiredis/Rakefile +2 -0
- data/lib/vendor/em-hiredis/em-hiredis-0.0.1.gem +0 -0
- data/lib/vendor/em-hiredis/em-hiredis.gemspec +23 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis.rb +22 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/client.rb +131 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/connection.rb +61 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/event_emitter.rb +29 -0
- data/lib/vendor/em-hiredis/lib/em-hiredis/version.rb +5 -0
- data/noah.gemspec +21 -17
- data/spec/application_spec.rb +30 -30
- data/spec/configuration_spec.rb +81 -14
- data/spec/ephemeral_spec.rb +52 -0
- data/spec/host_spec.rb +21 -21
- data/spec/noahapp_application_spec.rb +6 -6
- data/spec/noahapp_configuration_spec.rb +3 -3
- data/spec/noahapp_host_spec.rb +2 -2
- data/spec/noahapp_service_spec.rb +9 -9
- data/spec/noahapp_watcher_spec.rb +34 -0
- data/spec/service_spec.rb +27 -27
- data/spec/spec_helper.rb +13 -22
- data/spec/support/db/.keep +0 -0
- data/spec/support/test-redis.conf +8 -0
- data/spec/watcher_spec.rb +62 -0
- data/views/index.haml +21 -15
- metadata +124 -148
- data/Gemfile.lock +0 -85
- data/doc/coverage/index.html +0 -138
- data/doc/coverage/jquery-1.3.2.min.js +0 -19
- data/doc/coverage/jquery.tablesorter.min.js +0 -15
- data/doc/coverage/lib-helpers_rb.html +0 -393
- data/doc/coverage/lib-models_rb.html +0 -1449
- data/doc/coverage/noah_rb.html +0 -2019
- data/doc/coverage/print.css +0 -12
- data/doc/coverage/rcov.js +0 -42
- data/doc/coverage/screen.css +0 -270
- data/lib/noah/applications.rb +0 -46
- data/lib/noah/configurations.rb +0 -49
- data/lib/noah/hosts.rb +0 -54
- data/lib/noah/services.rb +0 -57
- data/lib/noah/watchers.rb +0 -18
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
module Noah
|
3
|
+
class Watcher < Model #NYI
|
4
|
+
# Don't trust anything in here yet
|
5
|
+
# I'm still trying a few things
|
6
|
+
include WatcherValidations
|
7
|
+
|
8
|
+
attribute :pattern
|
9
|
+
attribute :endpoint
|
10
|
+
|
11
|
+
index :pattern
|
12
|
+
index :endpoint
|
13
|
+
|
14
|
+
def validate
|
15
|
+
super
|
16
|
+
assert_present :endpoint
|
17
|
+
assert_present :pattern
|
18
|
+
assert_unique [:endpoint, :pattern]
|
19
|
+
assert_not_superset
|
20
|
+
assert_not_subset
|
21
|
+
end
|
22
|
+
|
23
|
+
def name
|
24
|
+
@name = Base64.encode64("#{pattern}|#{endpoint}").gsub("\n","")
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_hash
|
28
|
+
h = {:pattern => pattern, :name => name, :endpoint => endpoint, :created_at => created_at, :updated_at => updated_at}
|
29
|
+
super.merge(h)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.watch_list
|
33
|
+
arr = []
|
34
|
+
watches = self.all.sort_by(:pattern)
|
35
|
+
watches.each {|w| arr << w.name}
|
36
|
+
arr
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
# Not sure about these next two.
|
41
|
+
# Could get around patterns changing due to namespace changes
|
42
|
+
def path_to_pattern
|
43
|
+
end
|
44
|
+
|
45
|
+
def pattern_to_path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Watchers
|
50
|
+
def self.all(options = {})
|
51
|
+
options.empty? ? Watcher.all.sort : Watcher.find(options).sort
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Noah::App
|
2
|
+
# Service URIs
|
3
|
+
|
4
|
+
# get named {Service} for named {Host}
|
5
|
+
get '/s/:servicename/:hostname/?' do |servicename, hostname|
|
6
|
+
hs = host_service(hostname, servicename)
|
7
|
+
if hs.nil?
|
8
|
+
halt 404
|
9
|
+
else
|
10
|
+
hs.to_json
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
get '/s/:servicename/?' do |servicename|
|
15
|
+
s = services(:name => servicename)
|
16
|
+
s.map {|x| x.to_hash}
|
17
|
+
if s.empty?
|
18
|
+
halt 404
|
19
|
+
else
|
20
|
+
s.to_json
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
get '/s/?' do
|
25
|
+
if services.empty?
|
26
|
+
halt 404
|
27
|
+
else
|
28
|
+
services.map {|s| s.to_hash}
|
29
|
+
services.to_json
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
put '/s/:servicename/watch' do |servicename|
|
34
|
+
required_params = ["endpoint"]
|
35
|
+
data = JSON.parse(request.body.read)
|
36
|
+
(data.keys.sort == required_params.sort) ? (s = Noah::Service.find(:name => servicename).first) : (raise "Missing Parameters")
|
37
|
+
s.nil? ? (halt 404) : (w = s.watch!(:endpoint => data['endpoint']))
|
38
|
+
w.to_json
|
39
|
+
end
|
40
|
+
|
41
|
+
put '/s/:servicename/?' do |servicename|
|
42
|
+
required_params = ["status", "host", "name"]
|
43
|
+
data = JSON.parse(request.body.read)
|
44
|
+
if data.keys.sort == required_params.sort
|
45
|
+
h = Noah::Host.find(:name => data['host']).first || (raise "Invalid Host")
|
46
|
+
service = Noah::Service.find_or_create(:name => servicename, :status => data['status'], :host => h)
|
47
|
+
if service.valid?
|
48
|
+
action = service.is_new? ? "create" : "update"
|
49
|
+
service.save
|
50
|
+
r = {"action" => action, "result" => "success", "id" => service.id, "host" => h.name, "name" => service.name}
|
51
|
+
r.to_json
|
52
|
+
else
|
53
|
+
raise "#{service.errors}"
|
54
|
+
end
|
55
|
+
else
|
56
|
+
raise "Missing Parameters"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
delete '/s/:servicename/:hostname/?' do |servicename, hostname|
|
61
|
+
host = Noah::Host.find(:name => hostname).first || (halt 404)
|
62
|
+
service = Noah::Service.find(:name => servicename, :host_id => host.id).first || (halt 404)
|
63
|
+
if host && service
|
64
|
+
service.delete
|
65
|
+
r = {"action" => "delete", "result" => "success", "id" => service.id, "host" => host.name, "service" => servicename}
|
66
|
+
r.to_json
|
67
|
+
else
|
68
|
+
halt 404
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'validations','watcher_validations')
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Noah
|
2
|
+
module WatcherValidations
|
3
|
+
|
4
|
+
def assert_not_subset(error = [:pattern, :already_provided])
|
5
|
+
self.instance_of?(Noah::Watcher) ? (assert endpoint_covered?, error) : (assert false, "Validation not applicable")
|
6
|
+
end
|
7
|
+
|
8
|
+
def assert_not_superset(error = [:pattern, :replaces_existing])
|
9
|
+
self.instance_of?(Noah::Watcher) ? (assert endpoint_overrides?, error) : (assert false, "Validation not applicable")
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_valid_watch(error = [:pattern, :invalid_format])
|
13
|
+
self.instance_of?(Noah::Watcher) ? (assert pattern_valid?, error) : (assert false, "Validation not applicable")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def endpoint_covered?
|
18
|
+
watches = Watcher.all.find(:endpoint => self.endpoint).sort
|
19
|
+
watches.each do |w|
|
20
|
+
if (w.pattern.size < self.pattern.size) && self.pattern.match(/^#{w.pattern}/)
|
21
|
+
return false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
rescue ArgumentError
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
def endpoint_overrides?
|
29
|
+
watches = Watcher.all.find(:endpoint => self.endpoint).sort
|
30
|
+
watches.each do |w|
|
31
|
+
if (w.pattern.size > self.pattern.size) && w.pattern.match(/^#{self.pattern}/)
|
32
|
+
return false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue ArgumentError
|
36
|
+
return false
|
37
|
+
end
|
38
|
+
|
39
|
+
def pattern_valid?
|
40
|
+
unless self.pattern.match(/^\/\/noah\/.*\/$/)
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
rescue ArgumentError
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/noah/version.rb
CHANGED
data/lib/noah/watcher.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'uri'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
@log = Logger.new(STDOUT)
|
6
|
+
@log.level = Logger::DEBUG
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), 'passthrough')
|
9
|
+
require File.join(File.dirname(__FILE__), '..','vendor','em-hiredis','lib','em-hiredis')
|
10
|
+
|
11
|
+
module Noah
|
12
|
+
|
13
|
+
class Watcher
|
14
|
+
extend Passthrough
|
15
|
+
|
16
|
+
passthrough :redis_host, :pattern, :destination, :run!, :run_watcher
|
17
|
+
|
18
|
+
attr_accessor :my_pattern, :my_destination, :my_redis
|
19
|
+
|
20
|
+
def self.watch(&blk)
|
21
|
+
watcher = Noah::Watcher.new
|
22
|
+
watcher.instance_eval(&blk) if block_given?
|
23
|
+
watcher
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@my_redis ||= ENV['REDIS_URL']
|
28
|
+
@my_pattern ||= '//noah'
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.redis_host(host)
|
32
|
+
@my_redis = host
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.pattern(pattern)
|
36
|
+
@my_pattern = pattern
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.destination(destination)
|
40
|
+
@my_destination = destination
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.run!
|
44
|
+
@my_destination.nil? ? (raise ArgumentError) : run_watcher(@my_destination)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def self.run_watcher(dest)
|
49
|
+
log = Logger.new(STDOUT)
|
50
|
+
log.level = Logger::INFO
|
51
|
+
log.debug "#{dest.inspect}"
|
52
|
+
redis_url = URI.parse(@my_redis)
|
53
|
+
db = redis_url.path.gsub(/\//,'')
|
54
|
+
|
55
|
+
EventMachine.run do
|
56
|
+
trap("TERM") { log.info "Killed"; EventMachine.stop }
|
57
|
+
trap("INT") { log.info "Interrupted"; EventMachine.stop }
|
58
|
+
channel = EventMachine::Channel.new
|
59
|
+
r = EventMachine::Hiredis::Client.connect(redis_url.host, redis_url.port)
|
60
|
+
# Pulling out dbnum for now. Need to rethink it
|
61
|
+
#log.info "Binding to pattern #{db}:#{@my_pattern}"
|
62
|
+
log.info "Binding to pattern #{@my_pattern}"
|
63
|
+
r.psubscribe("#{@my_pattern}*")
|
64
|
+
r.on(:pmessage) do |pattern, event, message|
|
65
|
+
log.debug "Got message"
|
66
|
+
channel.push "#{message}"
|
67
|
+
end
|
68
|
+
r.errback { log.info "Something went tango-uniform" }
|
69
|
+
|
70
|
+
sub = channel.subscribe {|msg| log.info "Calling message handler"; dest.call(msg)}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
Getting started
|
2
|
+
===============
|
3
|
+
|
4
|
+
Connect to redis
|
5
|
+
|
6
|
+
redis_client = EM::Hiredis.connect
|
7
|
+
|
8
|
+
The client is a deferrable which succeeds when the underlying connection is established so you can bind to this. This isn't necessary however - any commands sent before the connection is established (or while reconnecting) will be sent to redis on connect.
|
9
|
+
|
10
|
+
redis_client.callback { puts "Redis now connected" }
|
11
|
+
|
12
|
+
All redis commands are available without any remapping of names
|
13
|
+
|
14
|
+
redis.set('foo', 'bar').callback {
|
15
|
+
redis.get('foo').callback { |value|
|
16
|
+
p [:returned, value]
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
As a shortcut, if you're only interested in binding to the success case you can simply provide a block to any command
|
21
|
+
|
22
|
+
redis.get('foo') { |value|
|
23
|
+
p [:returned, value]
|
24
|
+
}
|
25
|
+
|
26
|
+
Handling failure
|
27
|
+
----------------
|
28
|
+
|
29
|
+
All commands return a deferrable. In the case that redis replies with an error (for example you called a hash operation against a set), or in the case that the redis connection is broken before the command returns, the deferrable will fail. If you care about the failure case you should bind to the errback - for example:
|
30
|
+
|
31
|
+
redis.sadd('aset', 'member').callback {
|
32
|
+
response_deferrable = redis.hget('aset', 'member')
|
33
|
+
response_deferrable.errback { |e|
|
34
|
+
p e # => #<RuntimeError: ERR Operation against a key holding the wrong kind of value>
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
Pubsub
|
39
|
+
------
|
40
|
+
|
41
|
+
This example should explain things. Once a redis connection is in a pubsub state, you must make sure you only send pubsub commands.
|
42
|
+
|
43
|
+
redis = EM::Hiredis::Client.connect
|
44
|
+
subscriber = EM::Hiredis::Client.connect
|
45
|
+
|
46
|
+
subscriber.subscribe('bar.0')
|
47
|
+
subscriber.psubscribe('bar.*')
|
48
|
+
|
49
|
+
subscriber.on(:message) { |channel, message|
|
50
|
+
p [:message, channel, message]
|
51
|
+
}
|
52
|
+
|
53
|
+
subscriber.on(:pmessage) { |key, channel, message|
|
54
|
+
p [:pmessage, key, channel, message]
|
55
|
+
}
|
56
|
+
|
57
|
+
EM.add_periodic_timer(1) {
|
58
|
+
redis.publish("bar.#{rand(2)}", "hello").errback { |e|
|
59
|
+
p [:publisherror, e]
|
60
|
+
}
|
61
|
+
}
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "em-hiredis/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "em-hiredis"
|
7
|
+
s.version = EM::Hiredis::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Martyn Loughran"]
|
10
|
+
s.email = ["me@mloughran.com"]
|
11
|
+
s.homepage = "http://github.com/mloughran/em-hiredis"
|
12
|
+
s.summary = %q{Eventmachine redis client}
|
13
|
+
s.description = %q{Eventmachine redis client using hiredis native parser}
|
14
|
+
|
15
|
+
s.add_dependency 'hiredis', '~> 0.2.0'
|
16
|
+
|
17
|
+
s.rubyforge_project = "em-hiredis"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
|
3
|
+
module EM
|
4
|
+
module Hiredis
|
5
|
+
class << self
|
6
|
+
attr_writer :logger
|
7
|
+
|
8
|
+
def logger
|
9
|
+
@logger ||= begin
|
10
|
+
require 'logger'
|
11
|
+
log = Logger.new(STDOUT)
|
12
|
+
log.level = Logger::WARN
|
13
|
+
log
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'em-hiredis/event_emitter'
|
21
|
+
require 'em-hiredis/connection'
|
22
|
+
require 'em-hiredis/client'
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module EM::Hiredis
|
2
|
+
class Client
|
3
|
+
PUBSUB_MESSAGES = %w{message pmessage}.freeze
|
4
|
+
|
5
|
+
include EM::Hiredis::EventEmitter
|
6
|
+
include EM::Deferrable
|
7
|
+
|
8
|
+
def self.connect(host = 'localhost', port = 6379)
|
9
|
+
new(host, port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(host, port)
|
13
|
+
@host, @port = host, port
|
14
|
+
@subs, @psubs = [], []
|
15
|
+
@defs = []
|
16
|
+
@connection = EM.connect(host, port, Connection, host, port)
|
17
|
+
|
18
|
+
@connection.on(:closed) {
|
19
|
+
if @connected
|
20
|
+
@defs.each { |d| d.fail("Redis disconnected") }
|
21
|
+
@defs = []
|
22
|
+
@deferred_status = nil
|
23
|
+
@connected = false
|
24
|
+
@reconnecting = true
|
25
|
+
reconnect
|
26
|
+
else
|
27
|
+
EM.add_timer(1) { reconnect }
|
28
|
+
end
|
29
|
+
}
|
30
|
+
|
31
|
+
@connection.on(:connected) {
|
32
|
+
@connected = true
|
33
|
+
select(@db) if @db
|
34
|
+
@subs.each { |s| method_missing(:subscribe, s) }
|
35
|
+
@psubs.each { |s| method_missing(:psubscribe, s) }
|
36
|
+
succeed
|
37
|
+
|
38
|
+
if @reconnecting
|
39
|
+
@reconnecting = false
|
40
|
+
emit(:reconnected)
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
@connection.on(:message) { |reply|
|
45
|
+
if RuntimeError === reply
|
46
|
+
raise "Replies out of sync: #{reply.inspect}" if @defs.empty?
|
47
|
+
deferred = @defs.shift
|
48
|
+
deferred.fail(reply) if deferred
|
49
|
+
else
|
50
|
+
if reply && PUBSUB_MESSAGES.include?(reply[0]) # reply can be nil
|
51
|
+
kind, subscription, d1, d2 = *reply
|
52
|
+
|
53
|
+
case kind.to_sym
|
54
|
+
when :message
|
55
|
+
emit(:message, subscription, d1)
|
56
|
+
when :pmessage
|
57
|
+
emit(:pmessage, subscription, d1, d2)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
raise "Replies out of sync: #{reply.inspect}" if @defs.empty?
|
61
|
+
deferred = @defs.shift
|
62
|
+
deferred.succeed(reply) if deferred
|
63
|
+
end
|
64
|
+
end
|
65
|
+
}
|
66
|
+
|
67
|
+
@connected = false
|
68
|
+
@reconnecting = false
|
69
|
+
end
|
70
|
+
|
71
|
+
# Indicates that commands have been sent to redis but a reply has not yet
|
72
|
+
# been received.
|
73
|
+
#
|
74
|
+
# This can be useful for example to avoid stopping the
|
75
|
+
# eventmachine reactor while there are outstanding commands
|
76
|
+
#
|
77
|
+
def pending_commands?
|
78
|
+
@connected && @defs.size > 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def subscribe(channel)
|
82
|
+
@subs << channel
|
83
|
+
method_missing(:subscribe, channel)
|
84
|
+
end
|
85
|
+
|
86
|
+
def unsubscribe(channel)
|
87
|
+
@subs.delete(channel)
|
88
|
+
method_missing(:unsubscribe, channel)
|
89
|
+
end
|
90
|
+
|
91
|
+
def psubscribe(channel)
|
92
|
+
@psubs << channel
|
93
|
+
method_missing(:psubscribe, channel)
|
94
|
+
end
|
95
|
+
|
96
|
+
def punsubscribe(channel)
|
97
|
+
@psubs.delete(channel)
|
98
|
+
method_missing(:punsubscribe, channel)
|
99
|
+
end
|
100
|
+
|
101
|
+
def select(db)
|
102
|
+
@db = db
|
103
|
+
method_missing(:select, db)
|
104
|
+
end
|
105
|
+
|
106
|
+
def method_missing(sym, *args)
|
107
|
+
deferred = EM::DefaultDeferrable.new
|
108
|
+
# Shortcut for defining the callback case with just a block
|
109
|
+
deferred.callback { |result| yield(result) } if block_given?
|
110
|
+
|
111
|
+
if @connected
|
112
|
+
@connection.send_command(sym, *args)
|
113
|
+
@defs.push(deferred)
|
114
|
+
else
|
115
|
+
callback {
|
116
|
+
@connection.send_command(sym, *args)
|
117
|
+
@defs.push(deferred)
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
return deferred
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def reconnect
|
127
|
+
EM::Hiredis.logger.debug("Trying to reconnect to Redis")
|
128
|
+
@connection.reconnect @host, @port
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|