kjess 1.0.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.
- 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
|