sensu-redis 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +36 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/sensu/redis.rb +43 -0
- data/lib/sensu/redis/commands.rb +93 -0
- data/lib/sensu/redis/connection.rb +112 -0
- data/lib/sensu/redis/constants.rb +96 -0
- data/lib/sensu/redis/errors.rb +19 -0
- data/lib/sensu/redis/parser.rb +66 -0
- data/lib/sensu/redis/processor.rb +79 -0
- data/sensu-redis.gemspec +24 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1dd63d72bb8617b4a11636fc4f49f601fdc58f97
|
4
|
+
data.tar.gz: 1ecffe0185d61f8b98cdbb485c1d56d5d1da9e52
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b29df8a599bb52c350a4fd0aacdde00b1472ad58ef77782d02ba06878ab0b43dbec9ef2c0c514fcf9ec9b63a2c760f92f6de155a0bf9b8dfbdfe00d31bd5afeb
|
7
|
+
data.tar.gz: d6d503398789220f4433ffacd6cf18d20b5a5930bfd3bf0acee9743e5d6c31f169b8235198f2b92b5fd8c2805b45029cbca4c83aba9a319b2e70d91d7d2ae3ee
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Sensu::Redis
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sensu/redis`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'sensu-redis'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install sensu-redis
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sensu-redis.
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "sensu/redis"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/sensu/redis.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "sensu/redis/parser"
|
3
|
+
require "sensu/redis/processor"
|
4
|
+
require "sensu/redis/commands"
|
5
|
+
require "sensu/redis/connection"
|
6
|
+
require "eventmachine"
|
7
|
+
require "uri"
|
8
|
+
|
9
|
+
module Sensu
|
10
|
+
module Redis
|
11
|
+
class Client < EM::Connection
|
12
|
+
include EM::Deferrable
|
13
|
+
include Parser
|
14
|
+
include Processor
|
15
|
+
include Commands
|
16
|
+
include Connection
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def parse_url(url)
|
20
|
+
begin
|
21
|
+
uri = URI.parse(url)
|
22
|
+
{
|
23
|
+
:host => uri.host,
|
24
|
+
:port => uri.port,
|
25
|
+
:password => uri.password
|
26
|
+
}
|
27
|
+
rescue
|
28
|
+
raise ArgumentError, "invalid redis url"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def connect(options={})
|
33
|
+
if options.is_a?(String)
|
34
|
+
options = parse_url(options)
|
35
|
+
end
|
36
|
+
options[:host] ||= "127.0.0.1"
|
37
|
+
options[:port] = (options[:port] || 6379).to_i
|
38
|
+
EM.connect(options[:host], options[:port], self, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require "sensu/redis/constants"
|
2
|
+
require "sensu/redis/errors"
|
3
|
+
|
4
|
+
module Sensu
|
5
|
+
module Redis
|
6
|
+
# Sensu Module for requesting Redis commands, intended to be
|
7
|
+
# included by Sensu::Redis::Client.
|
8
|
+
#
|
9
|
+
# You can read about RESP @ http://redis.io/topics/protocol
|
10
|
+
module Commands
|
11
|
+
# Determine the byte size of a string.
|
12
|
+
#
|
13
|
+
# @param string [String]
|
14
|
+
# @return [Integer] string byte size.
|
15
|
+
def get_size(string)
|
16
|
+
string.respond_to?(:bytesize) ? string.bytesize : string.size
|
17
|
+
end
|
18
|
+
|
19
|
+
# Send a Redis command using RESP multi bulk. This method is
|
20
|
+
# called by the Redis command methods, which are created by
|
21
|
+
# `create_command_methods()`, it simply implements RESP and
|
22
|
+
# sends commands to Redis via EM connection `send_data()`.
|
23
|
+
def send_command(*arguments)
|
24
|
+
command = "*#{arguments.size}#{DELIM}"
|
25
|
+
arguments.each do |value|
|
26
|
+
value = value.to_s
|
27
|
+
command << "$#{get_size(value)}#{DELIM}#{value}#{DELIM}"
|
28
|
+
end
|
29
|
+
if @deferred_status
|
30
|
+
send_data(command)
|
31
|
+
else
|
32
|
+
callback { send_data(command) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Create Redis command methods. Command methods just wrap
|
37
|
+
# `send_command()` and enqueue a response callback. This method
|
38
|
+
# MUST be called in the connection object's `initialize()`.
|
39
|
+
def create_command_methods!
|
40
|
+
@response_callbacks ||= []
|
41
|
+
REDIS_COMMANDS.each do |command|
|
42
|
+
self.class.send(:define_method, command.to_sym) do |*arguments, &block|
|
43
|
+
send_command(command, *arguments)
|
44
|
+
@response_callbacks << [RESPONSE_PROCESSORS[command], block]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Authenticate to Redis and select the correct DB, when
|
50
|
+
# applicable. The auth and select Redis commands must be the
|
51
|
+
# first commands (& callbacks) to run.
|
52
|
+
#
|
53
|
+
# @param password [String]
|
54
|
+
# @param db [Integer]
|
55
|
+
def auth_and_select_db(password=nil, db=nil)
|
56
|
+
callbacks = @callbacks || []
|
57
|
+
@callbacks = []
|
58
|
+
send_command(AUTH_COMMAND, password) if password
|
59
|
+
send_command(SELECT_COMMAND, db) if db
|
60
|
+
callbacks.each { |block| callback(&block) }
|
61
|
+
end
|
62
|
+
|
63
|
+
# Subscribe to a Redis PubSub channel.
|
64
|
+
#
|
65
|
+
# @param channel [String]
|
66
|
+
def subscribe(channel, &block)
|
67
|
+
@pubsub_callbacks ||= Hash.new([])
|
68
|
+
@pubsub_callbacks[channel] << block
|
69
|
+
send_command(SUBSCRIBE_COMMAND, channel, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Unsubscribe to one or more Redis PubSub channels. If a channel
|
73
|
+
# is provided, this method will unsubscribe from it. If a
|
74
|
+
# channel is not provided, this method will unsubscribe from all
|
75
|
+
# Redis PubSub channels.
|
76
|
+
#
|
77
|
+
# @param channel [String]
|
78
|
+
def unsubscribe(channel=nil, &block)
|
79
|
+
@pubsub_callbacks ||= Hash.new([])
|
80
|
+
arguments = [UNSUBSCRIBE_COMMAND]
|
81
|
+
if channel
|
82
|
+
@pubsub_callbacks[channel] = [block]
|
83
|
+
arguments << channel
|
84
|
+
else
|
85
|
+
@pubsub_callbacks.each_key do |key|
|
86
|
+
@pubsub_callbacks[key] = [block]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
send_command(arguments)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require "sensu/redis/constants"
|
2
|
+
require "sensu/redis/errors"
|
3
|
+
|
4
|
+
module Sensu
|
5
|
+
module Redis
|
6
|
+
# Sensu Module connecting to Redis.
|
7
|
+
module Connection
|
8
|
+
def initialize(options={})
|
9
|
+
create_command_methods!
|
10
|
+
@host = options[:host]
|
11
|
+
@port = options[:port]
|
12
|
+
@db = (options[:db] || 0).to_i
|
13
|
+
@password = options[:password]
|
14
|
+
@auto_reconnect = options.fetch(:auto_reconnect, true)
|
15
|
+
@reconnect_on_error = options.fetch(:reconnect_on_error, true)
|
16
|
+
@error_callback = lambda do |error|
|
17
|
+
raise(error)
|
18
|
+
end
|
19
|
+
@reconnect_callbacks = {
|
20
|
+
:before => lambda{},
|
21
|
+
:after => lambda{}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Set the on error callback.
|
26
|
+
def on_error(&block)
|
27
|
+
@error_callback = block
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set the before reconnect callback.
|
31
|
+
def before_reconnect(&block)
|
32
|
+
@reconnect_callbacks[:before] = block
|
33
|
+
end
|
34
|
+
|
35
|
+
# Set the after reconnect callback.
|
36
|
+
def after_reconnect(&block)
|
37
|
+
@reconnect_callbacks[:after] = block
|
38
|
+
end
|
39
|
+
|
40
|
+
# Create an error and pass it to the error callback.
|
41
|
+
#
|
42
|
+
# @param klass [Class]
|
43
|
+
# @param message [String]
|
44
|
+
def error(klass, message)
|
45
|
+
redis_error = klass.new(message)
|
46
|
+
@error_callback.call(redis_error)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Determine if connected to Redis.
|
50
|
+
def connected?
|
51
|
+
@connected || false
|
52
|
+
end
|
53
|
+
|
54
|
+
# Reconnect to Redis. The before reconnect callback is first
|
55
|
+
# call if not already reconnecting. This method uses a 1 second
|
56
|
+
# delay before attempting a reconnect.
|
57
|
+
def reconnect!
|
58
|
+
@reconnect_callbacks[:before].call unless @reconnecting
|
59
|
+
@reconnecting = true
|
60
|
+
EM.add_timer(1) do
|
61
|
+
reconnect(@host, @port)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Close the Redis connection after writing the current
|
66
|
+
# command/data.
|
67
|
+
def close
|
68
|
+
@closing = true
|
69
|
+
close_connection_after_writing
|
70
|
+
end
|
71
|
+
|
72
|
+
# Called by EM when the connection closes, either intentionally
|
73
|
+
# or unexpectedly.
|
74
|
+
def unbind
|
75
|
+
@deferred_status = nil
|
76
|
+
@response_callbacks = []
|
77
|
+
@multibulk_count = false
|
78
|
+
if @closing
|
79
|
+
@reconnecting = false
|
80
|
+
elsif ((@connected || @reconnecting) && @auto_reconnect) || @reconnect_on_error
|
81
|
+
reconnect!
|
82
|
+
elsif @connected
|
83
|
+
error(ConnectionError, "connection closed")
|
84
|
+
else
|
85
|
+
error(ConnectionError, "unable to connect to redis server")
|
86
|
+
end
|
87
|
+
@connected = false
|
88
|
+
end
|
89
|
+
|
90
|
+
# Validate the connection, ensuring that the Redis release
|
91
|
+
# supports Sensu's required Redis commands. A connection error
|
92
|
+
# is thrown if Redis's version does not meet the requirement.
|
93
|
+
def validate_connection!
|
94
|
+
info do |redis_info|
|
95
|
+
if redis_info[:redis_version] < "1.3.14"
|
96
|
+
error(ConnectionError, "redis version must be >= 2.0 RC 1")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Called by EM when the connection is established.
|
102
|
+
def connection_completed
|
103
|
+
@connected = true
|
104
|
+
auth_and_select_db(@password, @db)
|
105
|
+
validate_connection!
|
106
|
+
@reconnect_callbacks[:after].call if @reconnecting
|
107
|
+
@reconnecting = false
|
108
|
+
succeed
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Sensu
|
2
|
+
module Redis
|
3
|
+
# RESP (REdis Serialization Protocol) response type characters and
|
4
|
+
# delimiter (http://redis.io/topics/protocol).
|
5
|
+
OK = "OK".freeze
|
6
|
+
MINUS = "-".freeze
|
7
|
+
PLUS = "+".freeze
|
8
|
+
COLON = ":".freeze
|
9
|
+
DOLLAR = "$".freeze
|
10
|
+
ASTERISK = "*".freeze
|
11
|
+
DELIM = "\r\n".freeze
|
12
|
+
|
13
|
+
# Redis response line parser incomplete data return value.
|
14
|
+
INCOMPLETE = "incomp".freeze
|
15
|
+
|
16
|
+
# Used to return empty array reponses.
|
17
|
+
EMPTY_ARRAY = [].freeze
|
18
|
+
|
19
|
+
# Redis response boolean values.
|
20
|
+
TRUE_VALUES = %w[1 OK].freeze
|
21
|
+
|
22
|
+
# Redis pubsub response type values.
|
23
|
+
PUBSUB_RESPONSES = %w[message unsubscribe].freeze
|
24
|
+
|
25
|
+
# Redis commands that are supported by this library.
|
26
|
+
REDIS_COMMANDS = [
|
27
|
+
"set",
|
28
|
+
"setnx",
|
29
|
+
"get",
|
30
|
+
"getset",
|
31
|
+
"del",
|
32
|
+
"info",
|
33
|
+
"sadd",
|
34
|
+
"smembers",
|
35
|
+
"sismembers",
|
36
|
+
"srem",
|
37
|
+
"scard",
|
38
|
+
"hset",
|
39
|
+
"hsetnx",
|
40
|
+
"hget",
|
41
|
+
"hgetall",
|
42
|
+
"hdel",
|
43
|
+
"hincrby",
|
44
|
+
"rpush",
|
45
|
+
"lpush",
|
46
|
+
"ltrim",
|
47
|
+
"lrange",
|
48
|
+
"exists",
|
49
|
+
"ttl",
|
50
|
+
"expire",
|
51
|
+
"flushdb",
|
52
|
+
"incr"
|
53
|
+
].freeze
|
54
|
+
|
55
|
+
# Redis DB select command.
|
56
|
+
SELECT_COMMAND = "select".freeze
|
57
|
+
|
58
|
+
# Redis authentication command.
|
59
|
+
AUTH_COMMAND = "auth".freeze
|
60
|
+
|
61
|
+
# Redis PubSub subscribe command.
|
62
|
+
SUBSCRIBE_COMMAND = "subscribe".freeze
|
63
|
+
|
64
|
+
# Redis PubSub unsubscribe command.
|
65
|
+
UNSUBSCRIBE_COMMAND = "unsubscribe".freeze
|
66
|
+
|
67
|
+
# Boolean Redis response value processor.
|
68
|
+
BOOLEAN_PROCESSOR = lambda{|r| TRUE_VALUES.include?(r.to_s)}
|
69
|
+
|
70
|
+
# Redis response value processors.
|
71
|
+
RESPONSE_PROCESSORS = {
|
72
|
+
"exists" => BOOLEAN_PROCESSOR,
|
73
|
+
"sadd" => BOOLEAN_PROCESSOR,
|
74
|
+
"srem" => BOOLEAN_PROCESSOR,
|
75
|
+
"setnx" => BOOLEAN_PROCESSOR,
|
76
|
+
"del" => BOOLEAN_PROCESSOR,
|
77
|
+
"expire" => BOOLEAN_PROCESSOR,
|
78
|
+
"select" => BOOLEAN_PROCESSOR,
|
79
|
+
"hset" => BOOLEAN_PROCESSOR,
|
80
|
+
"hdel" => BOOLEAN_PROCESSOR,
|
81
|
+
"hsetnx" => BOOLEAN_PROCESSOR,
|
82
|
+
"hgetall" => lambda{|r| Hash[*r]},
|
83
|
+
"info" => lambda{|r|
|
84
|
+
info = {}
|
85
|
+
r.each_line do |line|
|
86
|
+
line.chomp!
|
87
|
+
unless line.empty?
|
88
|
+
k, v = line.split(":", 2)
|
89
|
+
info[k.to_sym] = v
|
90
|
+
end
|
91
|
+
end
|
92
|
+
info
|
93
|
+
}
|
94
|
+
}
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sensu
|
2
|
+
module Redis
|
3
|
+
# Error class for Redis connection errors.
|
4
|
+
class ConnectionError < StandardError; end
|
5
|
+
|
6
|
+
# Error class for Redis protocol (RESP) errors.
|
7
|
+
class ProtocolError < StandardError; end
|
8
|
+
|
9
|
+
# Error class for Redis command errors.
|
10
|
+
class CommandError < StandardError
|
11
|
+
attr_accessor :code
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
args[0] = "redis returned error code: #{args[0]}"
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "sensu/redis/constants"
|
2
|
+
require "sensu/redis/errors"
|
3
|
+
|
4
|
+
module Sensu
|
5
|
+
module Redis
|
6
|
+
# Sensu Module for parsing RESP (REdis Serialization Protocol).
|
7
|
+
# You can read about RESP @ http://redis.io/topics/protocol
|
8
|
+
# This module calls methods provided by other Sensu Redis modules:
|
9
|
+
# Sensu::Redis::Processor.dispatch_error()
|
10
|
+
# Sensu::Redis::Processor.dispatch_response()
|
11
|
+
# Sensu::Redis::Processor.begin_multibulk()
|
12
|
+
# Sensu::Redis::Connection.error()
|
13
|
+
module Parser
|
14
|
+
# Parse a RESP line.
|
15
|
+
#
|
16
|
+
# @param line [String]
|
17
|
+
def parse_line(line)
|
18
|
+
# Trim off the response type and delimiter (\r\n).
|
19
|
+
response = line.slice(1..-3)
|
20
|
+
# First character indicates response type.
|
21
|
+
case line[0, 1]
|
22
|
+
when MINUS # Error, e.g. -ERR
|
23
|
+
dispatch_error(response)
|
24
|
+
when PLUS # String, e.g. +OK
|
25
|
+
dispatch_response(response)
|
26
|
+
when DOLLAR # Bulk string, e.g. $3\r\nfoo\r\n
|
27
|
+
response_size = Integer(response)
|
28
|
+
if response_size == -1 # No data, return nil.
|
29
|
+
dispatch_response(nil)
|
30
|
+
elsif @buffer.size >= response_size + 2 # Complete data.
|
31
|
+
dispatch_response(@buffer.slice!(0, response_size))
|
32
|
+
@buffer.slice!(0,2) # Discard delimeter (\r\n).
|
33
|
+
else # Incomplete, have data pushed back into buffer.
|
34
|
+
return INCOMPLETE
|
35
|
+
end
|
36
|
+
when COLON # Integer, e.g. :8
|
37
|
+
dispatch_response(Integer(response))
|
38
|
+
when ASTERISK # Array, e.g. *2\r\n$3\r\foo\r\n$3\r\nbar\r\n
|
39
|
+
multibulk_count = Integer(response)
|
40
|
+
if multibulk_count == -1 || multibulk_count == 0 # No data, return [].
|
41
|
+
dispatch_response(EMPTY_ARRAY)
|
42
|
+
else
|
43
|
+
begin_multibulk(multibulk_count) # Accumulate responses.
|
44
|
+
end
|
45
|
+
else
|
46
|
+
error(ProtocolError, "response type not recognized: #{line.strip}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# EM connection receive data, parse incoming data using RESP
|
51
|
+
# (`parse_line()`).
|
52
|
+
#
|
53
|
+
# @param data [String]
|
54
|
+
def receive_data(data)
|
55
|
+
(@buffer ||= '') << data
|
56
|
+
while index = @buffer.index(DELIM)
|
57
|
+
line = @buffer.slice!(0, index+2)
|
58
|
+
if parse_line(line) == INCOMPLETE
|
59
|
+
@buffer[0...0] = line
|
60
|
+
break
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require "sensu/redis/constants"
|
2
|
+
require "sensu/redis/errors"
|
3
|
+
|
4
|
+
module Sensu
|
5
|
+
module Redis
|
6
|
+
# Sensu Module for processing Redis responses.
|
7
|
+
# This module calls methods provided by other Sensu Redis modules:
|
8
|
+
# Sensu::Redis::Connection.error()
|
9
|
+
module Processor
|
10
|
+
# Fetch the next Redis command response callback. Response
|
11
|
+
# callbacks may include an optional response processor block,
|
12
|
+
# i.e. "1" -> true.
|
13
|
+
#
|
14
|
+
# @return [Array] processor, callback.
|
15
|
+
def fetch_response_callback
|
16
|
+
@response_callbacks ||= []
|
17
|
+
@response_callbacks.shift
|
18
|
+
end
|
19
|
+
|
20
|
+
# Begin a multi bulk response array for an expected number of
|
21
|
+
# responses. Using this method causes `dispatch_response()` to
|
22
|
+
# wait until all of the expected responses have been added to
|
23
|
+
# the array, before the Redis command reponse callback is
|
24
|
+
# called.
|
25
|
+
#
|
26
|
+
# @param multibulk_count [Integer] number of expected responses.
|
27
|
+
def begin_multibulk(multibulk_count)
|
28
|
+
@multibulk_count = multibulk_count
|
29
|
+
@multibulk_values = []
|
30
|
+
end
|
31
|
+
|
32
|
+
# Dispatch a Redis error, dropping the associated Redis command
|
33
|
+
# response callback, and passing a Redis error object to the
|
34
|
+
# error callback (if set).
|
35
|
+
#
|
36
|
+
# @param code [String] Redis error code.
|
37
|
+
def dispatch_error(code)
|
38
|
+
fetch_response_callback
|
39
|
+
error(CommandError, code)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Dispatch a response. If a multi bulk response has begun, this
|
43
|
+
# method will build the completed response array before the
|
44
|
+
# associated Redis command response callback is called. If one
|
45
|
+
# or more pubsub callbacks are defined, the approprate pubsub
|
46
|
+
# callbacks are called, provided with the pubsub response. Redis
|
47
|
+
# command response callbacks may have an optional processor
|
48
|
+
# block, responsible for producing a value with the correct
|
49
|
+
# type, e.g. "1" -> true (boolean).
|
50
|
+
#
|
51
|
+
# @param value [Object]
|
52
|
+
def dispatch_response(value)
|
53
|
+
if @multibulk_count
|
54
|
+
@multibulk_values << value
|
55
|
+
@multibulk_count -= 1
|
56
|
+
if @multibulk_count == 0
|
57
|
+
value = @multibulk_values
|
58
|
+
@multibulk_count = false
|
59
|
+
else
|
60
|
+
return
|
61
|
+
end
|
62
|
+
end
|
63
|
+
if @pubsub_callbacks && value.is_a?(Array)
|
64
|
+
if PUBSUB_RESPONSES.include?(value[0])
|
65
|
+
@pubsub_callbacks[value[1]].each do |block|
|
66
|
+
block.call(*value) if block
|
67
|
+
end
|
68
|
+
return
|
69
|
+
end
|
70
|
+
end
|
71
|
+
processor, block = fetch_response_callback
|
72
|
+
if block
|
73
|
+
value = processor.call(value) if processor
|
74
|
+
block.call(value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/sensu-redis.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "sensu-redis"
|
5
|
+
spec.version = "0.1.0"
|
6
|
+
spec.authors = ["Sean Porter"]
|
7
|
+
spec.email = ["portertech@gmail.com"]
|
8
|
+
spec.summary = "The Sensu Redis client library"
|
9
|
+
spec.description = "The Sensu Redis client library"
|
10
|
+
spec.homepage = "https://github.com/sensu/sensu-redis"
|
11
|
+
spec.license = "MIT"
|
12
|
+
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
14
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
15
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
+
spec.require_paths = ["lib"]
|
17
|
+
|
18
|
+
spec.add_dependency "eventmachine"
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake", "10.5.0"
|
22
|
+
spec.add_development_dependency "rspec"
|
23
|
+
spec.add_development_dependency "codeclimate-test-reporter" unless RUBY_VERSION < "1.9"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sensu-redis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sean Porter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: eventmachine
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 10.5.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 10.5.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: codeclimate-test-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: The Sensu Redis client library
|
84
|
+
email:
|
85
|
+
- portertech@gmail.com
|
86
|
+
executables:
|
87
|
+
- console
|
88
|
+
- setup
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- bin/console
|
98
|
+
- bin/setup
|
99
|
+
- lib/sensu/redis.rb
|
100
|
+
- lib/sensu/redis/commands.rb
|
101
|
+
- lib/sensu/redis/connection.rb
|
102
|
+
- lib/sensu/redis/constants.rb
|
103
|
+
- lib/sensu/redis/errors.rb
|
104
|
+
- lib/sensu/redis/parser.rb
|
105
|
+
- lib/sensu/redis/processor.rb
|
106
|
+
- sensu-redis.gemspec
|
107
|
+
homepage: https://github.com/sensu/sensu-redis
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.4.5.1
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: The Sensu Redis client library
|
131
|
+
test_files: []
|