noah 0.0.5 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|