mqrpc 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mqrpc/agent.rb +65 -38
- data/lib/mqrpc/functions/ping.rb +3 -1
- data/lib/mqrpc/logger.rb +13 -0
- data/lib/mqrpc/message.rb +4 -0
- data/lib/mqrpc/message.rb.orig +132 -0
- data/lib/mqrpc/message.rb.rej +19 -0
- data/lib/mqrpc/operation.rb +30 -7
- data/lib/mqrpc/sizedhash.rb +5 -4
- data/lib/mqrpc/test.diff +32 -0
- metadata +5 -2
data/lib/mqrpc/agent.rb
CHANGED
@@ -78,11 +78,7 @@ module MQRPC
|
|
78
78
|
case state
|
79
79
|
when :blocked
|
80
80
|
MQRPC::logger.info("Queue '#{k}' is full, unsubscribing from #{source}")
|
81
|
-
|
82
|
-
mq_q = @mq.queue(source, :durable => true)
|
83
|
-
mq_q.bind(exchange, :key => "*")
|
84
|
-
mq_q.unsubscribe
|
85
|
-
@queues.delete(source)
|
81
|
+
unsubscribe(source)
|
86
82
|
when :ready
|
87
83
|
MQRPC::logger.info("Queue '#{k}' is ready, resubscribing to #{source}")
|
88
84
|
subscribe(source)
|
@@ -113,6 +109,7 @@ module MQRPC
|
|
113
109
|
|
114
110
|
def start_amqp
|
115
111
|
@amqpthread = Thread.new do
|
112
|
+
Thread.current[:name] = "AMQP"
|
116
113
|
# Create connection to AMQP, and in turn, the main EventMachine loop.
|
117
114
|
amqp_config = {:host => @config.mqhost,
|
118
115
|
:port => @config.mqport,
|
@@ -133,11 +130,9 @@ module MQRPC
|
|
133
130
|
subscribe(@id)
|
134
131
|
|
135
132
|
# TODO(sissel): make this a deferred thread that reads from a Queue
|
136
|
-
#EM.add_periodic_timer(5) { handle_new_subscriptions }
|
137
133
|
EM.defer { handle_subscriptions }
|
138
134
|
|
139
135
|
EM.add_periodic_timer(1) do
|
140
|
-
# TODO(sissel): add locking
|
141
136
|
@outbuffer.each_key { |dest| flushout(dest) }
|
142
137
|
@outbuffer.clear
|
143
138
|
end
|
@@ -147,6 +142,7 @@ module MQRPC
|
|
147
142
|
|
148
143
|
def start_receiver
|
149
144
|
Thread.new do
|
145
|
+
Thread.current[:name] = "receiver"
|
150
146
|
while true
|
151
147
|
header, message = @receive_queue.pop
|
152
148
|
handle_message(header, message)
|
@@ -155,9 +151,27 @@ module MQRPC
|
|
155
151
|
end # def start_receiver
|
156
152
|
|
157
153
|
def subscribe(name)
|
154
|
+
MQRPC::logger.info "Wanting to subscribe to queue #{name}"
|
158
155
|
@want_subscriptions << [:queue, name]
|
159
156
|
end # def subscribe
|
160
157
|
|
158
|
+
def unsubscribe(name)
|
159
|
+
exchange = @mq.topic(@config.mqexchange, :durable => true)
|
160
|
+
mq_q = @mq.queue(name, :durable => true)
|
161
|
+
mq_q.bind(exchange, :key => "*")
|
162
|
+
|
163
|
+
op = Operation.new
|
164
|
+
mq_q.unsubscribe { op.finished }
|
165
|
+
op.wait_until_finished
|
166
|
+
@queues.delete(name)
|
167
|
+
|
168
|
+
#mq_q.unsubscribe { @queues.delete(name) }
|
169
|
+
## wait for unsubscribe to finish; it's async
|
170
|
+
#while @queues.member?(name)
|
171
|
+
#sleep(0.1)
|
172
|
+
#end
|
173
|
+
end # def unsubscribe
|
174
|
+
|
161
175
|
def subscribe_topic(name)
|
162
176
|
@want_subscriptions << [:topic, name]
|
163
177
|
end # def subscribe_topic
|
@@ -177,8 +191,13 @@ module MQRPC
|
|
177
191
|
return
|
178
192
|
end
|
179
193
|
|
180
|
-
|
181
|
-
|
194
|
+
begin
|
195
|
+
obj = JSON::load(msg_body)
|
196
|
+
rescue JSON::ParserError
|
197
|
+
MQRPC::logger.warn("Skipping non-JSON message: #{msg_body}")
|
198
|
+
hdr.ack
|
199
|
+
return
|
200
|
+
end
|
182
201
|
if !obj.is_a?(Array)
|
183
202
|
obj = [obj]
|
184
203
|
end
|
@@ -222,24 +241,52 @@ module MQRPC
|
|
222
241
|
end # def handle_message
|
223
242
|
|
224
243
|
def run
|
244
|
+
Thread.current[:name] ||= "#{self.class.name}#run"
|
225
245
|
@amqpthread.join
|
226
246
|
end # run
|
227
247
|
|
228
248
|
def can_receive?(message_class)
|
249
|
+
if self.class.message_handlers == nil
|
250
|
+
self.class.message_handlers = []
|
251
|
+
end
|
252
|
+
|
229
253
|
return self.class.message_handlers.include?(message_class)
|
230
254
|
end
|
231
255
|
|
232
256
|
def handle_subscriptions
|
257
|
+
Thread.current[:name] = "subscriptionhandler"
|
233
258
|
while true do
|
234
|
-
|
235
|
-
|
259
|
+
queuetype, name = @want_subscriptions.pop
|
260
|
+
|
261
|
+
case queuetype
|
236
262
|
when :queue
|
237
|
-
|
263
|
+
if @queues.include?(name)
|
264
|
+
MQRPC::logger.info "Ignoring subscription request to queue "\
|
265
|
+
"#{name}, already subscribed."
|
266
|
+
next
|
267
|
+
end
|
238
268
|
MQRPC::logger.info "Subscribing to queue #{name}"
|
269
|
+
# Send a dummy message to queue #{name} so there's at least
|
270
|
+
# one message to receive, and wake up our Operation.
|
271
|
+
sendmsg(name, DummyMessage.new)
|
239
272
|
exchange = @mq.topic(@config.mqexchange, :durable => true)
|
240
273
|
mq_q = @mq.queue(name, :durable => true)
|
241
274
|
mq_q.bind(exchange, :key => "*")
|
242
|
-
|
275
|
+
op = Operation.new
|
276
|
+
mq_q.subscribe(:ack => true) do |hdr, msg|
|
277
|
+
op.finished
|
278
|
+
return if msg.is_a?(DummyMessage)
|
279
|
+
queue = hdr.routing_key
|
280
|
+
MQRPC::logger.info("received message on #{queue}")
|
281
|
+
@receive_queue << [hdr, msg]
|
282
|
+
MQRPC::logger.info("finished receiving message on #{queue}")
|
283
|
+
MQRPC::logger.info("msg: #{msg}")
|
284
|
+
MQRPC::logger.info("#{queue} queue size: #{@receive_queue.length}")
|
285
|
+
end
|
286
|
+
# Wait until we receive our first message (might be DummyMessage,
|
287
|
+
# doesn't matter) -- this confirms we are subscribed. subscribe
|
288
|
+
# is async...
|
289
|
+
op.wait_until_finished
|
243
290
|
@queues << name
|
244
291
|
when :topic
|
245
292
|
MQRPC::logger.info "Subscribing to topic #{name}"
|
@@ -249,30 +296,9 @@ module MQRPC
|
|
249
296
|
:auto_delete => true).bind(exchange, :key => name)
|
250
297
|
mq_q.subscribe { |hdr, msg| @receive_queue << [hdr, msg] }
|
251
298
|
@topics << name
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
def handle_new_subscriptions
|
257
|
-
todo = @want_queues - @queues
|
258
|
-
todo.each do |queue|
|
259
|
-
MQRPC::logger.info "Subscribing to queue #{queue}"
|
260
|
-
mq_q = @mq.queue(queue, :durable => true)
|
261
|
-
mq_q.subscribe(:ack => true) { |hdr, msg| @receive_queue << [hdr, msg] }
|
262
|
-
@queues << queue
|
263
|
-
end # todo.each
|
264
|
-
|
265
|
-
todo = @want_topics - @topics
|
266
|
-
todo.each do |topic|
|
267
|
-
MQRPC::logger.info "Subscribing to topic #{topic}"
|
268
|
-
exchange = @mq.topic(@config.mqexchange)
|
269
|
-
mq_q = @mq.queue("#{@id}-#{topic}",
|
270
|
-
:exclusive => true,
|
271
|
-
:auto_delete => true).bind(exchange, :key => topic)
|
272
|
-
mq_q.subscribe { |hdr, msg| @receive_queue << [hdr, msg] }
|
273
|
-
@topics << topic
|
274
|
-
end # todo.each
|
275
|
-
end # handle_new_subscriptions
|
299
|
+
end # case queuetype
|
300
|
+
end # while true
|
301
|
+
end # def handle_subscriptions
|
276
302
|
|
277
303
|
def flushout(destination)
|
278
304
|
msgs = @outbuffer[destination]
|
@@ -315,7 +341,8 @@ module MQRPC
|
|
315
341
|
end
|
316
342
|
|
317
343
|
if block_given?
|
318
|
-
op = Operation.new
|
344
|
+
op = Operation.new &callback
|
345
|
+
MQRPC::logger.debug "New operation for #{msg.id}"
|
319
346
|
@message_operations[msg.id] = op
|
320
347
|
return op
|
321
348
|
end
|
data/lib/mqrpc/functions/ping.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'mqrpc/messages/ping'
|
3
3
|
|
4
|
-
module MQRPC; module Functions;
|
4
|
+
module MQRPC; module Functions; class Ping
|
5
|
+
#handle MQRPC::Messages::PingRequest, :PingRequestHandler
|
6
|
+
|
5
7
|
def PingRequestHandler(request)
|
6
8
|
MQRPC::logger.debug "received PingRequest (#{request.pingdata})"
|
7
9
|
response = MQRPC::Messages::PingResponse.new
|
data/lib/mqrpc/logger.rb
CHANGED
@@ -13,3 +13,16 @@ module MQRPC
|
|
13
13
|
@logger = logger
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
# Make logger include the thread id.
|
18
|
+
class FormatterWithThread < Logger::Formatter
|
19
|
+
Format = "%s, [%s#%d/%s] %5s -- %s: %s\n"
|
20
|
+
|
21
|
+
def call(severity, time, progname, msg)
|
22
|
+
thread_id = (Thread.current[:name] or Thread.current)
|
23
|
+
Format % [severity[0..0], format_datetime(time), $$, thread_id,
|
24
|
+
severity, progname, msg2str(msg)]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
MQRPC::logger.formatter = FormatterWithThread.new
|
data/lib/mqrpc/message.rb
CHANGED
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'thread'
|
3
|
+
require 'mqrpc/logger'
|
4
|
+
|
5
|
+
module BindToHash
|
6
|
+
def header(method, key=nil)
|
7
|
+
key = method.to_s if key == nil
|
8
|
+
hashbind(method, "/#{key}")
|
9
|
+
end
|
10
|
+
|
11
|
+
def argument(method, key=nil)
|
12
|
+
key = method.to_s if key == nil
|
13
|
+
hashbind(method, "/args/#{key}")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def hashbind(method, key)
|
18
|
+
hashpath = __genhashpath(key)
|
19
|
+
self.class_eval %(
|
20
|
+
def #{method}
|
21
|
+
return #{hashpath}
|
22
|
+
end
|
23
|
+
def #{method}=(val)
|
24
|
+
#{hashpath} = val
|
25
|
+
end
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def __genhashpath(key)
|
31
|
+
# TODO(sissel): enforce 'key' needs to be a string or symbol?
|
32
|
+
path = key.split("/").select { |x| x.length > 0 }\
|
33
|
+
.map { |x| "[#{x.inspect}]" }
|
34
|
+
return "@data#{path.join("")}"
|
35
|
+
end
|
36
|
+
end # modules BindToHash
|
37
|
+
|
38
|
+
module MQRPC
|
39
|
+
class Message
|
40
|
+
extend BindToHash
|
41
|
+
@@idseq = 0
|
42
|
+
@@idlock = Mutex.new
|
43
|
+
@@knowntypes = Hash.new
|
44
|
+
attr_accessor :data
|
45
|
+
|
46
|
+
# Message attributes
|
47
|
+
header :id
|
48
|
+
header :message_class
|
49
|
+
header :delayable
|
50
|
+
header :reply_to
|
51
|
+
header :timestamp
|
52
|
+
header :args
|
53
|
+
|
54
|
+
def self.inherited(subclass)
|
55
|
+
MQRPC::logger.debug "Message '#{subclass.name}' subclasses #{self.name}"
|
56
|
+
@@knowntypes[subclass.name] = subclass
|
57
|
+
|
58
|
+
# Call the class initializer if it has one.
|
59
|
+
if subclass.respond_to?(:class_initialize)
|
60
|
+
subclass.class_initialize
|
61
|
+
end
|
62
|
+
end # def self.inherited
|
63
|
+
|
64
|
+
def self.new_from_data(data)
|
65
|
+
obj = nil
|
66
|
+
name = data["message_class"]
|
67
|
+
if @@knowntypes.has_key?(name)
|
68
|
+
obj = @@knowntypes[name].new
|
69
|
+
else
|
70
|
+
$stderr.puts "No known message class: #{name}, #{data.inspect}"
|
71
|
+
obj = Message.new
|
72
|
+
end
|
73
|
+
obj.data = data
|
74
|
+
return obj
|
75
|
+
end
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
@data = Hash.new
|
79
|
+
# Don't delay messages by defualt
|
80
|
+
self.delayable = false
|
81
|
+
|
82
|
+
generate_id!
|
83
|
+
self.message_class = self.class.name
|
84
|
+
self.args = Hash.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def generate_id!
|
88
|
+
@@idlock.synchronize do
|
89
|
+
self.id = @@idseq
|
90
|
+
#puts "Generating id. #{self.class}.id == #{self.id}"
|
91
|
+
@@idseq += 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def age
|
96
|
+
return Time.now.to_f - timestamp
|
97
|
+
end
|
98
|
+
|
99
|
+
def to_json(*args)
|
100
|
+
return @data.to_json(*args)
|
101
|
+
end
|
102
|
+
|
103
|
+
protected
|
104
|
+
attr :data
|
105
|
+
end # class Message
|
106
|
+
|
107
|
+
class RequestMessage < Message
|
108
|
+
# Nothing.
|
109
|
+
end # class RequestMessage
|
110
|
+
|
111
|
+
class ResponseMessage < Message
|
112
|
+
header :in_reply_to
|
113
|
+
header :from_queue
|
114
|
+
|
115
|
+
def initialize(source_request=nil)
|
116
|
+
super()
|
117
|
+
|
118
|
+
# Copy the request id if we are given a source_request
|
119
|
+
if source_request.is_a?(RequestMessage)
|
120
|
+
self.in_reply_to = source_request.id
|
121
|
+
#self.delayable = source_request.delayable
|
122
|
+
end
|
123
|
+
self.args = Hash.new
|
124
|
+
end
|
125
|
+
|
126
|
+
# Report the success of the request this response is for.
|
127
|
+
# Should be implemented by subclasses.
|
128
|
+
def success?
|
129
|
+
raise NotImplementedError
|
130
|
+
end
|
131
|
+
end # class ResponseMessage
|
132
|
+
end # module MQRPC
|
@@ -0,0 +1,19 @@
|
|
1
|
+
***************
|
2
|
+
*** 108,113 ****
|
3
|
+
# Nothing.
|
4
|
+
end # class RequestMessage
|
5
|
+
|
6
|
+
class ResponseMessage < Message
|
7
|
+
header :in_reply_to
|
8
|
+
header :from_queue
|
9
|
+
--- 108,117 ----
|
10
|
+
# Nothing.
|
11
|
+
end # class RequestMessage
|
12
|
+
|
13
|
+
+ class DummyMessage < Message
|
14
|
+
+ # Nothing.
|
15
|
+
+ end # class DummyMessage
|
16
|
+
+
|
17
|
+
class ResponseMessage < Message
|
18
|
+
header :in_reply_to
|
19
|
+
header :from_queue
|
data/lib/mqrpc/operation.rb
CHANGED
@@ -6,9 +6,14 @@ module MQRPC
|
|
6
6
|
# A single message operation
|
7
7
|
# * Takes a callback to call when a message is received
|
8
8
|
# * Allows you to wait for the operation to complete.
|
9
|
-
# * An operation is 'complete' when the callback returns
|
9
|
+
# * An operation is 'complete' when the callback returns.
|
10
|
+
#
|
11
|
+
# If your callback returns :continue, then we will not call finished.
|
12
|
+
# This allows you to have an operation that is invoked multiple times,
|
13
|
+
# such as for streaming blocks of data, and only finish when you know
|
14
|
+
# you are done.
|
10
15
|
class Operation
|
11
|
-
def initialize(callback)
|
16
|
+
def initialize(&callback)
|
12
17
|
@mutex = Mutex.new
|
13
18
|
@callback = callback
|
14
19
|
@cv = ConditionVariable.new
|
@@ -21,9 +26,7 @@ module MQRPC
|
|
21
26
|
@mutex.synchronize do
|
22
27
|
ret = @callback.call(*args)
|
23
28
|
if ret != :continue
|
24
|
-
|
25
|
-
@finished = true
|
26
|
-
@cv.signal
|
29
|
+
_withlock_finished
|
27
30
|
end
|
28
31
|
return ret
|
29
32
|
end
|
@@ -34,15 +37,35 @@ module MQRPC
|
|
34
37
|
# immediately.
|
35
38
|
def wait_until_finished
|
36
39
|
@mutex.synchronize do
|
37
|
-
if !
|
40
|
+
if !_withlock_finished?
|
38
41
|
@cv.wait(@mutex)
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end # def wait_until_finished
|
42
45
|
|
43
|
-
|
46
|
+
# Is the operation finished yet?
|
44
47
|
def finished?
|
48
|
+
@mutex.synchronize do
|
49
|
+
return _withlock_finished?
|
50
|
+
end
|
51
|
+
end # def finished?
|
52
|
+
|
53
|
+
# Declare that the operation is finished.
|
54
|
+
def finished
|
55
|
+
@mutex.synchronize do
|
56
|
+
return _withlock_finished
|
57
|
+
end
|
58
|
+
end # def finished
|
59
|
+
|
60
|
+
protected
|
61
|
+
def _withlock_finished?
|
45
62
|
return @finished
|
46
63
|
end # def finished?
|
64
|
+
|
65
|
+
def _withlock_finished
|
66
|
+
@finished = true
|
67
|
+
@cv.signal
|
68
|
+
end
|
69
|
+
|
47
70
|
end # class Operation
|
48
71
|
end # module MQRPC
|
data/lib/mqrpc/sizedhash.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'mqrpc'
|
3
3
|
|
4
|
+
# A mutex which logs every enter/exit on synchronize
|
4
5
|
class TrackingMutex < Mutex
|
5
6
|
def synchronize(&blk)
|
6
|
-
|
7
|
+
MQRPC::logger.debug "Enter synchronize #{self} @ #{caller[0]}"
|
7
8
|
super { blk.call }
|
8
|
-
|
9
|
+
MQRPC::logger.debug "Exit synchronize #{self} @ #{caller[0]}"
|
9
10
|
end # def synchronize
|
10
11
|
end # clas TrackingMutex < Mutex
|
11
12
|
|
@@ -17,7 +18,7 @@ class SizedThreadSafeHash
|
|
17
18
|
attr_reader :size
|
18
19
|
|
19
20
|
def initialize(size, &callback)
|
20
|
-
@lock =
|
21
|
+
@lock = Mutex.new
|
21
22
|
@size = size
|
22
23
|
@condvar = ConditionVariable.new
|
23
24
|
@data = Hash.new
|
@@ -30,7 +31,7 @@ class SizedThreadSafeHash
|
|
30
31
|
@lock.synchronize do
|
31
32
|
# If adding a new item, wait if the hash is full
|
32
33
|
if !@data.has_key?(key) and _withlock_full?
|
33
|
-
MQRPC::logger.info "#{self}: Waiting to add key #{key.inspect}, hash is full (
|
34
|
+
MQRPC::logger.info "#{self}: Waiting to add key #{key.inspect}, hash is full (thread #{Thread.current})"
|
34
35
|
if @state != :blocked
|
35
36
|
@state = :blocked
|
36
37
|
@callback.call(@state) if @callback
|
data/lib/mqrpc/test.diff
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Index: lib/mqrpc/agent.rb
|
2
|
+
===================================================================
|
3
|
+
--- agent.rb (revision 318)
|
4
|
+
+++ agent.rb (working copy)
|
5
|
+
@@ -267,10 +267,16 @@
|
6
|
+
end
|
7
|
+
MQRPC::logger.info "Subscribing to queue #{name}"
|
8
|
+
@queues << name
|
9
|
+
+ # Send a dummy message to queue #{name} so there's at least
|
10
|
+
+ # one message to receive, and wake up our Operation.
|
11
|
+
+ sendmsg(name, DummyMessage.new)
|
12
|
+
exchange = @mq.topic(@config.mqexchange, :durable => true)
|
13
|
+
mq_q = @mq.queue(name, :durable => true)
|
14
|
+
mq_q.bind(exchange, :key => "*")
|
15
|
+
+ op = Operation.new
|
16
|
+
mq_q.subscribe(:ack => true) do |hdr, msg|
|
17
|
+
+ op.finished
|
18
|
+
+ return if msg.is_a?(DummyMessage)
|
19
|
+
queue = hdr.routing_key
|
20
|
+
MQRPC::logger.info("received message on #{queue}")
|
21
|
+
@receive_queue << [hdr, msg]
|
22
|
+
@@ -278,6 +284,10 @@
|
23
|
+
MQRPC::logger.info("msg: #{msg}")
|
24
|
+
MQRPC::logger.info("#{queue} queue size: #{@receive_queue.length}")
|
25
|
+
end
|
26
|
+
+ # Wait until we receive our first message (might be DummyMessage,
|
27
|
+
+ # doesn't matter) -- this confirms we are subscribed. subscribe
|
28
|
+
+ # is async...
|
29
|
+
+ op.wait_until_finished
|
30
|
+
when :topic
|
31
|
+
MQRPC::logger.info "Subscribing to topic #{name}"
|
32
|
+
exchange = @mq.topic(@config.mqexchange, :durable => true)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mqrpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sissel, Pete Fritchman
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-20 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -53,12 +53,15 @@ extra_rdoc_files: []
|
|
53
53
|
files:
|
54
54
|
- lib/mqrpc/agent.rb
|
55
55
|
- lib/mqrpc/config.rb
|
56
|
+
- lib/mqrpc/test.diff
|
56
57
|
- lib/mqrpc/logger.rb
|
57
58
|
- lib/mqrpc/functions/ping.rb
|
58
59
|
- lib/mqrpc/message.rb
|
60
|
+
- lib/mqrpc/message.rb.orig
|
59
61
|
- lib/mqrpc/operation.rb
|
60
62
|
- lib/mqrpc/messages/ping.rb
|
61
63
|
- lib/mqrpc/sizedhash.rb
|
64
|
+
- lib/mqrpc/message.rb.rej
|
62
65
|
- lib/mqrpc.rb
|
63
66
|
has_rdoc: true
|
64
67
|
homepage: http://code.google.com/p/logstash/wiki/MQRPC
|