kjess 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTING.md +45 -0
- data/HISTORY.rdoc +5 -0
- data/LICENSE +16 -0
- data/Manifest.txt +53 -0
- data/README.rdoc +44 -0
- data/Rakefile +337 -0
- data/example/client_test.rb +73 -0
- data/lib/kjess.rb +11 -0
- data/lib/kjess/client.rb +289 -0
- data/lib/kjess/connection.rb +119 -0
- data/lib/kjess/error.rb +5 -0
- data/lib/kjess/protocol.rb +76 -0
- data/lib/kjess/request.rb +31 -0
- data/lib/kjess/request/delete.rb +11 -0
- data/lib/kjess/request/dump_stats.rb +7 -0
- data/lib/kjess/request/flush.rb +11 -0
- data/lib/kjess/request/flush_all.rb +7 -0
- data/lib/kjess/request/get.rb +21 -0
- data/lib/kjess/request/quit.rb +7 -0
- data/lib/kjess/request/reload.rb +7 -0
- data/lib/kjess/request/set.rb +19 -0
- data/lib/kjess/request/shutdown.rb +7 -0
- data/lib/kjess/request/stats.rb +7 -0
- data/lib/kjess/request/status.rb +8 -0
- data/lib/kjess/request/version.rb +8 -0
- data/lib/kjess/response.rb +76 -0
- data/lib/kjess/response/client_error.rb +19 -0
- data/lib/kjess/response/deleted.rb +5 -0
- data/lib/kjess/response/dumped_stats.rb +48 -0
- data/lib/kjess/response/end.rb +5 -0
- data/lib/kjess/response/eof.rb +5 -0
- data/lib/kjess/response/error.rb +13 -0
- data/lib/kjess/response/flushed_all_queues.rb +6 -0
- data/lib/kjess/response/not_found.rb +5 -0
- data/lib/kjess/response/not_stored.rb +5 -0
- data/lib/kjess/response/reloaded_config.rb +6 -0
- data/lib/kjess/response/server_error.rb +18 -0
- data/lib/kjess/response/stats.rb +60 -0
- data/lib/kjess/response/stored.rb +5 -0
- data/lib/kjess/response/unknown.rb +3 -0
- data/lib/kjess/response/value.rb +26 -0
- data/lib/kjess/response/version.rb +10 -0
- data/lib/kjess/stats_cache.rb +31 -0
- data/spec/client_spec.rb +265 -0
- data/spec/kestrel_server.rb +137 -0
- data/spec/request/set_spec.rb +13 -0
- data/spec/request/version_spec.rb +17 -0
- data/spec/request_spec.rb +30 -0
- data/spec/response/client_error_spec.rb +17 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/utils.rb +18 -0
- data/spec/version_spec.rb +9 -0
- data/tasks/kestrel.rake +70 -0
- metadata +193 -0
data/lib/kjess/error.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
module KJess
|
2
|
+
# Protocl is the base class that all Kestrel requests and responses are
|
3
|
+
# developed on. it defines the DSL for creating the Request and Response
|
4
|
+
# objects that make up the Protocol.
|
5
|
+
#
|
6
|
+
class Protocol
|
7
|
+
|
8
|
+
CRLF = "\r\n"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Internal: The keyword that starts this protocol message
|
12
|
+
#
|
13
|
+
# name - the keyword to define this portion of the protocol
|
14
|
+
#
|
15
|
+
# Returns the name
|
16
|
+
def keyword( name = nil )
|
17
|
+
if name then
|
18
|
+
register( name )
|
19
|
+
@keyword = name
|
20
|
+
end
|
21
|
+
@keyword
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal: define or return the arity of this protocol item
|
25
|
+
#
|
26
|
+
# arity - the number of args this protocol item has
|
27
|
+
#
|
28
|
+
# Returns the arity
|
29
|
+
def arity( a = nil )
|
30
|
+
@arity = a if a
|
31
|
+
@arity
|
32
|
+
end
|
33
|
+
|
34
|
+
# Internal: register this protocol item with its registry
|
35
|
+
#
|
36
|
+
# name - the name under which to register the protocol
|
37
|
+
#
|
38
|
+
# Returns nothing
|
39
|
+
def register( name )
|
40
|
+
registry[name] ||= self
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :args
|
45
|
+
attr_reader :raw_args
|
46
|
+
|
47
|
+
def initialize( opts = {} )
|
48
|
+
@raw_args = opts
|
49
|
+
@args = parse_options_to_args( opts ) || []
|
50
|
+
end
|
51
|
+
|
52
|
+
# Internal: callback that child classes may use to further parse the
|
53
|
+
# initialization arguments
|
54
|
+
#
|
55
|
+
# Returns Array
|
56
|
+
def parse_options_to_args( opts ); end
|
57
|
+
|
58
|
+
# Internal: Convert the object to its protocol serialized format.
|
59
|
+
#
|
60
|
+
# This may be overridden in child classes
|
61
|
+
#
|
62
|
+
# Return a String
|
63
|
+
def to_protocol
|
64
|
+
s = keyword
|
65
|
+
s += " #{args.join(' ')}" unless args.empty?
|
66
|
+
s += CRLF
|
67
|
+
end
|
68
|
+
|
69
|
+
# Internal: return the keyword
|
70
|
+
#
|
71
|
+
# Returns a String
|
72
|
+
def keyword
|
73
|
+
self.class.keyword
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module KJess
|
2
|
+
# Request is the base Request Protocol. All Requests made to the Kestrel
|
3
|
+
# server are decendants of this class.
|
4
|
+
#
|
5
|
+
# The Request class holds the registry of all the Request decendent classes.
|
6
|
+
class Request < Protocol
|
7
|
+
Registry = Hash.new
|
8
|
+
|
9
|
+
def self.registry
|
10
|
+
Registry
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.valid_responses( list = nil )
|
14
|
+
@valid_responses = [ list ].flatten if list
|
15
|
+
@valid_responses
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
require 'kjess/response'
|
20
|
+
require 'kjess/request/flush'
|
21
|
+
require 'kjess/request/flush_all'
|
22
|
+
require 'kjess/request/delete'
|
23
|
+
require 'kjess/request/dump_stats'
|
24
|
+
require 'kjess/request/get'
|
25
|
+
require 'kjess/request/quit'
|
26
|
+
require 'kjess/request/reload'
|
27
|
+
require 'kjess/request/set'
|
28
|
+
require 'kjess/request/shutdown'
|
29
|
+
require 'kjess/request/stats'
|
30
|
+
require 'kjess/request/status'
|
31
|
+
require 'kjess/request/version'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class KJess::Request
|
2
|
+
class Get < KJess::Request
|
3
|
+
keyword 'GET'
|
4
|
+
arity 1
|
5
|
+
valid_responses [ KJess::Response::Value ]
|
6
|
+
|
7
|
+
def parse_options_to_args( opts )
|
8
|
+
a = [ opts[:queue_name] ]
|
9
|
+
|
10
|
+
a << "t=#{opts[:wait_for]}" if opts[:wait_for]
|
11
|
+
|
12
|
+
[ :open, :close, :abort, :peek ].each do |o|
|
13
|
+
a << o.to_s if opts[o]
|
14
|
+
end
|
15
|
+
|
16
|
+
[ a.join("/") ]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class KJess::Request
|
2
|
+
class Set < KJess::Request
|
3
|
+
keyword 'SET'
|
4
|
+
arity 4
|
5
|
+
valid_responses [ KJess::Response::Stored, KJess::Response::NotStored ]
|
6
|
+
|
7
|
+
attr_reader :data
|
8
|
+
|
9
|
+
def parse_options_to_args( opts )
|
10
|
+
@data = opts[:data].to_s
|
11
|
+
[ opts[:queue_name], 0, opts[:expiration] || 0 , data.bytesize ]
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_protocol
|
15
|
+
s = super
|
16
|
+
s += "#{data}#{CRLF}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module KJess
|
2
|
+
# Response is the parent class of all Response derived objects that come back
|
3
|
+
# from the Kestrel server. It holds the registry of all the Response objects
|
4
|
+
# and is responsible for parsing the initial line from the Kestrel server and
|
5
|
+
# determinig which Response child object to instantiate.
|
6
|
+
class Response < Protocol
|
7
|
+
arity 0
|
8
|
+
|
9
|
+
Registry = Hash.new
|
10
|
+
def self.registry
|
11
|
+
Registry
|
12
|
+
end
|
13
|
+
|
14
|
+
# Internal: parse the string and create the appropriate Response child
|
15
|
+
# object.
|
16
|
+
#
|
17
|
+
# str - a String from the Kestrel server
|
18
|
+
#
|
19
|
+
# Returns a new Response child object
|
20
|
+
def self.parse( str )
|
21
|
+
keyword, *args = str.strip.split
|
22
|
+
klass = Registry.fetch( keyword, KJess::Response::Unknown )
|
23
|
+
klass.new( args )
|
24
|
+
end
|
25
|
+
|
26
|
+
# Internal: callback to create the @args member
|
27
|
+
#
|
28
|
+
# opts - the opts that were passed to initialize
|
29
|
+
#
|
30
|
+
# Returns an Array
|
31
|
+
def parse_options_to_args( opts )
|
32
|
+
[ opts ].flatten
|
33
|
+
end
|
34
|
+
|
35
|
+
# Internal: create the human readable version of this response
|
36
|
+
#
|
37
|
+
# Returns a String
|
38
|
+
def message
|
39
|
+
[ keyword, raw_args ].flatten.join(' ')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Internal: callback that is used by some Responses that have more complex
|
43
|
+
# response creation.
|
44
|
+
#
|
45
|
+
# connection - the KJess::Connection object to continue to read from
|
46
|
+
#
|
47
|
+
# Returns nothing
|
48
|
+
def read_more( connection ); end
|
49
|
+
|
50
|
+
# Internal: is this Response object an error object.
|
51
|
+
#
|
52
|
+
# This is overwritte in those objects that create Exceptions
|
53
|
+
#
|
54
|
+
# Returns false
|
55
|
+
def error?
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
require 'kjess/response/client_error'
|
62
|
+
require 'kjess/response/deleted'
|
63
|
+
require 'kjess/response/dumped_stats'
|
64
|
+
require 'kjess/response/end'
|
65
|
+
require 'kjess/response/eof'
|
66
|
+
require 'kjess/response/error'
|
67
|
+
require 'kjess/response/flushed_all_queues'
|
68
|
+
require 'kjess/response/not_found'
|
69
|
+
require 'kjess/response/not_stored'
|
70
|
+
require 'kjess/response/reloaded_config'
|
71
|
+
require 'kjess/response/server_error'
|
72
|
+
require 'kjess/response/stats'
|
73
|
+
require 'kjess/response/stored'
|
74
|
+
require 'kjess/response/unknown'
|
75
|
+
require 'kjess/response/value'
|
76
|
+
require 'kjess/response/version'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'kjess/error'
|
2
|
+
class KJess::Response
|
3
|
+
class ClientError < KJess::Response
|
4
|
+
keyword 'CLIENT_ERROR'
|
5
|
+
arity 1
|
6
|
+
|
7
|
+
def message
|
8
|
+
args.join(' ')
|
9
|
+
end
|
10
|
+
|
11
|
+
def error?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def exception
|
16
|
+
KJess::ClientError.new( message )
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class KJess::Response
|
2
|
+
class DumpedStats < KJess::Response
|
3
|
+
keyword 'queue'
|
4
|
+
arity 2
|
5
|
+
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
# Internal: Read the extra data from the value
|
9
|
+
#
|
10
|
+
# Read the datablock that is after the value and then the final END marker.
|
11
|
+
#
|
12
|
+
# Returns nothing
|
13
|
+
def read_more( connection )
|
14
|
+
queue_line_re = /\Aqueue\s+'(\S+)' \{\Z/
|
15
|
+
stat_line_re = /\A(\w+)=(\S+)\Z/
|
16
|
+
stats = Hash.new
|
17
|
+
line = message.strip
|
18
|
+
current_queue = nil
|
19
|
+
|
20
|
+
begin
|
21
|
+
line.strip!
|
22
|
+
if md = stat_line_re.match( line ) then
|
23
|
+
stats[current_queue][md.captures[0]] = convert_value( md.captures[1] )
|
24
|
+
elsif md = queue_line_re.match( line ) then
|
25
|
+
current_queue = md.captures.first
|
26
|
+
stats[current_queue] = Hash.new
|
27
|
+
elsif line == "}" then
|
28
|
+
current_queue = nil
|
29
|
+
elsif line == "END" then
|
30
|
+
break
|
31
|
+
else
|
32
|
+
# do nothing -- empty line
|
33
|
+
end
|
34
|
+
end while line = connection.readline
|
35
|
+
@data = stats
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert_value( value )
|
39
|
+
if value =~ /\A\d+\Z/ then
|
40
|
+
Float( value ).to_i
|
41
|
+
elsif value =~ /\A\d+\.\d+\Z/
|
42
|
+
Float( value )
|
43
|
+
else
|
44
|
+
value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|