qpid_proton 0.21.0 → 0.22.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 +4 -4
- data/examples/README.md +26 -10
- data/examples/broker.rb +99 -91
- data/examples/example_test.rb +11 -11
- data/ext/cproton/cproton.c +3 -3
- data/lib/core/connection.rb +18 -12
- data/lib/core/connection_driver.rb +13 -3
- data/lib/core/container.rb +276 -120
- data/lib/core/disposition.rb +1 -1
- data/lib/core/endpoint.rb +3 -0
- data/lib/core/listener.rb +6 -0
- data/lib/core/message.rb +5 -9
- data/lib/core/messaging_handler.rb +5 -1
- data/lib/core/receiver.rb +1 -2
- data/lib/core/sasl.rb +1 -1
- data/lib/core/session.rb +6 -4
- data/lib/core/terminus.rb +10 -4
- data/lib/core/transfer.rb +3 -0
- data/lib/core/transport.rb +1 -0
- data/lib/core/uri.rb +9 -10
- data/lib/core/work_queue.rb +76 -0
- data/lib/qpid_proton.rb +2 -8
- data/lib/types/array.rb +1 -0
- data/lib/types/hash.rb +0 -11
- data/lib/util/schedule.rb +79 -0
- data/lib/util/wrapper.rb +4 -0
- data/tests/old_examples/old_example_test.rb +0 -8
- data/tests/test_container.rb +203 -126
- data/tests/test_container_sasl.rb +141 -0
- data/tests/test_interop.rb +1 -1
- data/tests/test_messaging_adapter.rb +1 -1
- data/tests/test_tools.rb +30 -5
- data/tests/test_uri.rb +2 -0
- metadata +5 -9
- data/lib/messenger/messenger.rb +0 -703
- data/lib/messenger/subscription.rb +0 -36
- data/lib/messenger/tracker.rb +0 -37
- data/lib/messenger/tracker_status.rb +0 -68
- data/lib/util/timeout.rb +0 -49
- data/tests/old_examples/recv.rb +0 -23
- data/tests/old_examples/send.rb +0 -21
data/lib/core/container.rb
CHANGED
@@ -19,8 +19,11 @@
|
|
19
19
|
require 'thread'
|
20
20
|
require 'set'
|
21
21
|
require_relative 'listener'
|
22
|
+
require_relative 'work_queue'
|
22
23
|
|
23
24
|
module Qpid::Proton
|
25
|
+
public
|
26
|
+
|
24
27
|
# An AMQP container manages a set of {Listener}s and {Connection}s which
|
25
28
|
# contain {#Sender} and {#Receiver} links to transfer messages. Usually, each
|
26
29
|
# AMQP client or server process has a single container for all of its
|
@@ -29,63 +32,7 @@ module Qpid::Proton
|
|
29
32
|
# One or more threads can call {#run}, events generated by all the listeners and
|
30
33
|
# connections will be dispatched in the {#run} threads.
|
31
34
|
class Container
|
32
|
-
|
33
|
-
|
34
|
-
# Container driver applies options and adds container context to events
|
35
|
-
class ConnectionTask < Qpid::Proton::HandlerDriver
|
36
|
-
def initialize container, io, opts, server=false
|
37
|
-
super io, opts[:handler]
|
38
|
-
transport.set_server if server
|
39
|
-
transport.apply opts
|
40
|
-
connection.apply opts
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class ListenTask < Listener
|
45
|
-
|
46
|
-
def initialize(io, handler, container)
|
47
|
-
super
|
48
|
-
@closing = @closed = nil
|
49
|
-
env = ENV['PN_TRACE_EVT']
|
50
|
-
if env && ["true", "1", "yes", "on"].include?(env.downcase)
|
51
|
-
@log_prefix = "[0x#{object_id.to_s(16)}](PN_LISTENER_"
|
52
|
-
else
|
53
|
-
@log_prefix = nil
|
54
|
-
end
|
55
|
-
dispatch(:on_open);
|
56
|
-
end
|
57
|
-
|
58
|
-
def process
|
59
|
-
return if @closed
|
60
|
-
unless @closing
|
61
|
-
begin
|
62
|
-
return @io.accept, dispatch(:on_accept)
|
63
|
-
rescue IO::WaitReadable, Errno::EINTR
|
64
|
-
rescue IOError, SystemCallError => e
|
65
|
-
close e
|
66
|
-
end
|
67
|
-
end
|
68
|
-
ensure
|
69
|
-
if @closing
|
70
|
-
@io.close rescue nil
|
71
|
-
@closed = true
|
72
|
-
dispatch(:on_error, @condition) if @condition
|
73
|
-
dispatch(:on_close)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def can_read?() !finished?; end
|
78
|
-
def can_write?() false; end
|
79
|
-
def finished?() @closed; end
|
80
|
-
|
81
|
-
def dispatch(method, *args)
|
82
|
-
# TODO aconway 2017-11-27: better logging
|
83
|
-
STDERR.puts "#{@log_prefix}#{([method[3..-1].upcase]+args).join ', '})" if @log_prefix
|
84
|
-
@handler.__send__(method, self, *args) if @handler && @handler.respond_to?(method)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
public
|
35
|
+
include TimeCompare
|
89
36
|
|
90
37
|
# Error raised if the container is used after {#stop} has been called.
|
91
38
|
class StoppedError < RuntimeError
|
@@ -106,11 +53,13 @@ module Qpid::Proton
|
|
106
53
|
# concurrently.
|
107
54
|
#
|
108
55
|
def initialize(*args)
|
56
|
+
@handler, @id, @panic = nil
|
109
57
|
case args.size
|
110
58
|
when 2 then @handler, @id = args
|
111
59
|
when 1 then
|
112
60
|
@id = String.try_convert(args[0]) || (args[0].to_s if args[0].is_a? Symbol)
|
113
61
|
@handler = args[0] unless @id
|
62
|
+
when 0 then
|
114
63
|
else raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..2"
|
115
64
|
end
|
116
65
|
# Use an empty messaging adapter to give default behaviour if there's no global handler.
|
@@ -119,16 +68,17 @@ module Qpid::Proton
|
|
119
68
|
|
120
69
|
# Implementation note:
|
121
70
|
#
|
122
|
-
# - #run threads take work from @work
|
123
|
-
# -
|
124
|
-
# - The Container thread does IO.select
|
71
|
+
# - #run threads take work items from @work, process them, and rearm them for select
|
72
|
+
# - work items are: ConnectionTask, ListenTask, :start, :select, :schedule
|
125
73
|
# - nil on the @work queue makes a #run thread exit
|
126
74
|
|
127
75
|
@work = Queue.new
|
128
76
|
@work << :start
|
129
|
-
@work <<
|
130
|
-
@wake =
|
77
|
+
@work << :select
|
78
|
+
@wake = SelectWaker.new # Wakes #run thread in IO.select
|
131
79
|
@auto_stop = true # Stop when @active drops to 0
|
80
|
+
@schedule = Schedule.new
|
81
|
+
@schedule_working = false # True if :schedule is on the work queue
|
132
82
|
|
133
83
|
# Following instance variables protected by lock
|
134
84
|
@lock = Mutex.new
|
@@ -161,7 +111,7 @@ module Qpid::Proton
|
|
161
111
|
|
162
112
|
# Number of threads in {#run}
|
163
113
|
# @return [Bool] {#run} thread count
|
164
|
-
def running
|
114
|
+
def running() @lock.synchronize { @running }; end
|
165
115
|
|
166
116
|
# Open an AMQP connection.
|
167
117
|
#
|
@@ -220,10 +170,25 @@ module Qpid::Proton
|
|
220
170
|
|
221
171
|
# Run the container: wait for IO activity, dispatch events to handlers.
|
222
172
|
#
|
223
|
-
# More than one thread can call {#run} concurrently,
|
224
|
-
# all
|
225
|
-
# {
|
226
|
-
# listener
|
173
|
+
# *Multi-threaading* : More than one thread can call {#run} concurrently,
|
174
|
+
# the container will use all {#run} threads as a thread pool. Calls to
|
175
|
+
# {MessagingHandler} or {Listener::Handler} methods are serialized for each
|
176
|
+
# connection or listener. See {WorkQueue} for coordinating with other
|
177
|
+
# threads.
|
178
|
+
#
|
179
|
+
# *Exceptions*: If any handler method raises an exception it will stop the
|
180
|
+
# container, and the exception will be raised by all calls to {#run}. For
|
181
|
+
# single threaded code this is often desirable. Multi-threaded server
|
182
|
+
# applications should normally rescue exceptions in the handler and deal
|
183
|
+
# with them in another way: logging, closing the connection with an error
|
184
|
+
# condition, signalling another thread etc.
|
185
|
+
#
|
186
|
+
# @return [void] Returns when the container stops, see {#stop} and {#auto_stop}
|
187
|
+
#
|
188
|
+
# @raise [StoppedError] If the container has already been stopped when {#run} was called.
|
189
|
+
#
|
190
|
+
# @raise [Exception] If any {MessagingHandler} or {Listener::Handler} managed by
|
191
|
+
# the container raises an exception, that exception will be raised by {#run}
|
227
192
|
#
|
228
193
|
def run
|
229
194
|
@lock.synchronize do
|
@@ -231,45 +196,9 @@ module Qpid::Proton
|
|
231
196
|
raise StoppedError if @stopped
|
232
197
|
end
|
233
198
|
while task = @work.pop
|
234
|
-
|
235
|
-
|
236
|
-
when :start
|
237
|
-
@adapter.on_container_start(self) if @adapter.respond_to? :on_container_start
|
238
|
-
|
239
|
-
when Container
|
240
|
-
r, w = [@wake[0]], []
|
241
|
-
@lock.synchronize do
|
242
|
-
@selectable.each do |s|
|
243
|
-
r << s if s.send :can_read?
|
244
|
-
w << s if s.send :can_write?
|
245
|
-
end
|
246
|
-
end
|
247
|
-
r, w = IO.select(r, w)
|
248
|
-
selected = Set.new(r).merge(w)
|
249
|
-
drain_wake if selected.delete?(@wake[0])
|
250
|
-
stop_select = nil
|
251
|
-
@lock.synchronize do
|
252
|
-
if stop_select = @stopped # close everything
|
253
|
-
selected += @selectable
|
254
|
-
selected.each { |s| s.close @stop_err }
|
255
|
-
@wake.each { |fd| fd.close() }
|
256
|
-
end
|
257
|
-
@selectable -= selected # Remove selected tasks
|
258
|
-
end
|
259
|
-
selected.each { |s| @work << s } # Queue up tasks needing #process
|
260
|
-
@work << self unless stop_select
|
261
|
-
|
262
|
-
when ConnectionTask then
|
263
|
-
task.process
|
264
|
-
rearm task
|
265
|
-
|
266
|
-
when ListenTask then
|
267
|
-
io, opts = task.process
|
268
|
-
add(connection_driver(io, opts, true)) if io
|
269
|
-
rearm task
|
270
|
-
end
|
271
|
-
# TODO aconway 2017-10-26: scheduled tasks, heartbeats
|
199
|
+
run_one(task, Time.now)
|
272
200
|
end
|
201
|
+
raise @panic if @panic
|
273
202
|
ensure
|
274
203
|
@lock.synchronize do
|
275
204
|
if (@running -= 1) > 0
|
@@ -291,37 +220,264 @@ module Qpid::Proton
|
|
291
220
|
# {StoppedError} on attempting. Create a new container if you want to
|
292
221
|
# resume activity.
|
293
222
|
#
|
294
|
-
# @param error [Condition] Optional
|
223
|
+
# @param error [Condition] Optional error condition passed to
|
224
|
+
# {MessagingHandler#on_transport_error} for each connection and
|
225
|
+
# {Listener::Handler::on_error} for each listener.
|
295
226
|
#
|
296
|
-
|
227
|
+
# @param panic [Exception] Optional exception raised by all concurrent calls
|
228
|
+
# to run()
|
229
|
+
#
|
230
|
+
def stop(error=nil, panic=nil)
|
297
231
|
@lock.synchronize do
|
298
|
-
|
299
|
-
@stopped = true
|
232
|
+
return if @stopped
|
300
233
|
@stop_err = Condition.convert(error)
|
234
|
+
@panic = panic
|
235
|
+
@stopped = true
|
301
236
|
check_stop_lh
|
302
237
|
# NOTE: @stopped =>
|
303
238
|
# - no new run threads can join
|
304
239
|
# - no more select calls after next wakeup
|
305
240
|
# - once @active == 0, all threads will be stopped with nil
|
306
241
|
end
|
307
|
-
wake
|
242
|
+
@wake.wake
|
308
243
|
end
|
309
244
|
|
310
|
-
|
245
|
+
# Schedule code to be executed after a delay.
|
246
|
+
# @param delay [Numeric] delay in seconds, must be >= 0
|
247
|
+
# @yield [ ] the block is invoked with no parameters in a {#run} thread after +delay+ has elapsed
|
248
|
+
# @return [void]
|
249
|
+
# @raise [ThreadError] if +non_block+ is true and the operation would block
|
250
|
+
def schedule(delay, non_block=false, &block)
|
251
|
+
not_stopped
|
252
|
+
@lock.synchronize { @active += 1 } if @schedule.add(Time.now + delay, non_block, &block)
|
253
|
+
@wake.wake
|
254
|
+
end
|
311
255
|
|
312
|
-
|
256
|
+
private
|
313
257
|
|
314
|
-
|
315
|
-
# thread doesn't get stuck in select while there is other work on the queue.
|
316
|
-
def work_wake(task) @work << task; wake; end
|
258
|
+
def wake() @wake.wake; end
|
317
259
|
|
318
|
-
|
260
|
+
# Container driver applies options and adds container context to events
|
261
|
+
class ConnectionTask < Qpid::Proton::HandlerDriver
|
262
|
+
include TimeCompare
|
263
|
+
|
264
|
+
def initialize container, io, opts, server=false
|
265
|
+
super io, opts[:handler]
|
266
|
+
transport.set_server if server
|
267
|
+
transport.apply opts
|
268
|
+
connection.apply opts
|
269
|
+
@work_queue = WorkQueue.new container
|
270
|
+
connection.instance_variable_set(:@work_queue, @work_queue)
|
271
|
+
end
|
272
|
+
def next_tick() earliest(super, @work_queue.send(:next_tick)); end
|
273
|
+
def process(now) @work_queue.send(:process, now); super(); end
|
274
|
+
|
275
|
+
def dispatch # Intercept dispatch to close work_queue
|
276
|
+
super
|
277
|
+
@work_queue.send(:close) if read_closed? && write_closed?
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
class ListenTask < Listener
|
282
|
+
|
283
|
+
def initialize(io, handler, container)
|
284
|
+
super
|
285
|
+
@closing = @closed = nil
|
286
|
+
env = ENV['PN_TRACE_EVT']
|
287
|
+
if env && ["true", "1", "yes", "on"].include?(env.downcase)
|
288
|
+
@log_prefix = "[0x#{object_id.to_s(16)}](PN_LISTENER_"
|
289
|
+
else
|
290
|
+
@log_prefix = nil
|
291
|
+
end
|
292
|
+
dispatch(:on_open);
|
293
|
+
end
|
294
|
+
|
295
|
+
def process
|
296
|
+
return if @closed
|
297
|
+
unless @closing
|
298
|
+
begin
|
299
|
+
return @io.accept, dispatch(:on_accept)
|
300
|
+
rescue IO::WaitReadable, Errno::EINTR
|
301
|
+
rescue IOError, SystemCallError => e
|
302
|
+
close e
|
303
|
+
end
|
304
|
+
end
|
305
|
+
ensure
|
306
|
+
if @closing
|
307
|
+
@io.close rescue nil
|
308
|
+
@closed = true
|
309
|
+
dispatch(:on_error, @condition) if @condition
|
310
|
+
dispatch(:on_close)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def can_read?() !finished?; end
|
315
|
+
def can_write?() false; end
|
316
|
+
def finished?() @closed; end
|
317
|
+
|
318
|
+
def dispatch(method, *args)
|
319
|
+
# TODO aconway 2017-11-27: better logging
|
320
|
+
STDERR.puts "#{@log_prefix}#{([method[3..-1].upcase]+args).join ', '})" if @log_prefix
|
321
|
+
@handler.__send__(method, self, *args) if @handler && @handler.respond_to?(method)
|
322
|
+
end
|
323
|
+
|
324
|
+
def next_tick() nil; end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Selectable object that can be used to wake IO.select from another thread
|
328
|
+
class SelectWaker
|
329
|
+
def initialize
|
330
|
+
@rd, @wr = IO.pipe
|
331
|
+
@lock = Mutex.new
|
332
|
+
@set = false
|
333
|
+
end
|
334
|
+
|
335
|
+
def to_io() @rd; end
|
336
|
+
|
337
|
+
def wake
|
338
|
+
@lock.synchronize do
|
339
|
+
return if @set # Don't write if already has data
|
340
|
+
@set = true
|
341
|
+
begin @wr.write_nonblock('x') rescue IO::WaitWritable end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def reset
|
346
|
+
@lock.synchronize do
|
347
|
+
return unless @set
|
348
|
+
begin @rd.read_nonblock(1) rescue IO::WaitReadable end
|
349
|
+
@set = false
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def close
|
354
|
+
@rd.close
|
355
|
+
@wr.close
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
# Handle a single item from the @work queue, this is the heart of the #run loop.
|
360
|
+
def run_one(task, now)
|
361
|
+
case task
|
362
|
+
|
363
|
+
when :start
|
364
|
+
@adapter.on_container_start(self) if @adapter.respond_to? :on_container_start
|
365
|
+
|
366
|
+
when :select
|
367
|
+
# Compute read/write select sets and minimum next_tick for select timeout
|
368
|
+
r, w = [@wake], []
|
369
|
+
next_tick = @schedule.next_tick
|
370
|
+
@lock.synchronize do
|
371
|
+
@selectable.each do |s|
|
372
|
+
r << s if s.send :can_read?
|
373
|
+
w << s if s.send :can_write?
|
374
|
+
next_tick = earliest(s.next_tick, next_tick)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
timeout = ((next_tick > now) ? next_tick - now : 0) if next_tick
|
379
|
+
r, w = IO.select(r, w, nil, timeout)
|
380
|
+
now = Time.now unless timeout == 0
|
381
|
+
@wake.reset if r && r.delete(@wake)
|
382
|
+
|
383
|
+
# selected is a Set to eliminate duplicates between r, w and next_tick due.
|
384
|
+
selected = Set.new
|
385
|
+
selected.merge(r) if r
|
386
|
+
selected.merge(w) if w
|
387
|
+
@lock.synchronize do
|
388
|
+
if @stopped # close everything
|
389
|
+
@selectable.each { |s| s.close @stop_err; @work << s }
|
390
|
+
@selectable.clear
|
391
|
+
@wake.close
|
392
|
+
return
|
393
|
+
end
|
394
|
+
if !@schedule_working && before_eq(@schedule.next_tick, now)
|
395
|
+
@schedule_working = true
|
396
|
+
@work << :schedule
|
397
|
+
end
|
398
|
+
selected.merge(@selectable.select { |s| before_eq(s.next_tick, now) })
|
399
|
+
@selectable -= selected # Remove selected tasks from @selectable
|
400
|
+
end
|
401
|
+
selected.each { |s| @work << s } # Queue up tasks needing #process
|
402
|
+
@work << :select # Enable next select
|
403
|
+
|
404
|
+
when ConnectionTask then
|
405
|
+
maybe_panic { task.process now }
|
406
|
+
rearm task
|
407
|
+
|
408
|
+
when ListenTask then
|
409
|
+
io, opts = maybe_panic { task.process }
|
410
|
+
add(connection_driver(io, opts, true)) if io
|
411
|
+
rearm task
|
412
|
+
|
413
|
+
when :schedule then
|
414
|
+
if maybe_panic { @schedule.process now }
|
415
|
+
@lock.synchronize { @active -= 1; check_stop_lh }
|
416
|
+
else
|
417
|
+
@lock.synchronize { @schedule_working = false }
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
def do_select
|
423
|
+
# Compute the sets to select for read and write, and the minimum next_tick for the timeout
|
424
|
+
r, w = [@wake], []
|
425
|
+
next_tick = nil
|
426
|
+
@lock.synchronize do
|
427
|
+
@selectable.each do |s|
|
428
|
+
r << s if s.can_read?
|
429
|
+
w << s if s.can_write?
|
430
|
+
next_tick = earliest(s.next_tick, next_tick)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
next_tick = earliest(@schedule.next_tick, next_tick)
|
434
|
+
|
435
|
+
# Do the select and queue up all resulting work
|
436
|
+
now = Time.now
|
437
|
+
timeout = next_tick - now if next_tick
|
438
|
+
r, w = (timeout.nil? || timeout > 0) && IO.select(r, w, nil, timeout)
|
439
|
+
@wake.reset
|
440
|
+
selected = Set.new
|
441
|
+
@lock.synchronize do
|
442
|
+
if @stopped
|
443
|
+
@selectable.each { |s| s.close @stop_err; @work << s }
|
444
|
+
@wake.close
|
445
|
+
return
|
446
|
+
end
|
447
|
+
# Check if schedule has items due and is not already working
|
448
|
+
if !@schedule_working && before_eq(@schedule.next_tick, now)
|
449
|
+
@work << :schedule
|
450
|
+
@schedule_working = true
|
451
|
+
end
|
452
|
+
# Eliminate duplicates between r, w and next_tick due.
|
453
|
+
selected.merge(r) if r
|
454
|
+
selected.delete(@wake)
|
455
|
+
selected.merge(w) if w
|
456
|
+
@selectable -= selected
|
457
|
+
selected.merge(@selectable.select { |s| before_eq(s.next_tick, now) })
|
458
|
+
@selectable -= selected
|
459
|
+
end
|
460
|
+
selected.each { |s| @work << s } # Queue up tasks needing #process
|
461
|
+
@work << :select
|
462
|
+
end
|
463
|
+
|
464
|
+
# Rescue any exception raised by the block and stop the container.
|
465
|
+
def maybe_panic
|
319
466
|
begin
|
320
|
-
|
321
|
-
rescue
|
467
|
+
yield
|
468
|
+
rescue Exception => e
|
469
|
+
stop(nil, e)
|
470
|
+
nil
|
322
471
|
end
|
323
472
|
end
|
324
473
|
|
474
|
+
# Normally if we add work we need to set a wakeup to ensure a single #run
|
475
|
+
# thread doesn't get stuck in select while there is other work on the queue.
|
476
|
+
def work_wake(task)
|
477
|
+
@work << task
|
478
|
+
@wake.wake
|
479
|
+
end
|
480
|
+
|
325
481
|
def connection_driver(io, opts=nil, server=false)
|
326
482
|
opts ||= {}
|
327
483
|
opts[:container] = self
|
@@ -350,7 +506,7 @@ module Qpid::Proton
|
|
350
506
|
@selectable << task
|
351
507
|
end
|
352
508
|
end
|
353
|
-
wake
|
509
|
+
@wake.wake
|
354
510
|
end
|
355
511
|
|
356
512
|
def check_stop_lh
|
@@ -361,7 +517,7 @@ module Qpid::Proton
|
|
361
517
|
end
|
362
518
|
end
|
363
519
|
|
364
|
-
def not_stopped
|
520
|
+
def not_stopped() raise StoppedError if @lock.synchronize { @stopped }; end
|
365
521
|
|
366
522
|
end
|
367
523
|
end
|
data/lib/core/disposition.rb
CHANGED
data/lib/core/endpoint.rb
CHANGED
@@ -67,6 +67,9 @@ module Qpid::Proton
|
|
67
67
|
self.connection.transport
|
68
68
|
end
|
69
69
|
|
70
|
+
# @return [WorkQueue] the work queue for work on this endpoint.
|
71
|
+
def work_queue() connection.work_queue; end
|
72
|
+
|
70
73
|
# @private
|
71
74
|
# @return [Bool] true if {#state} has all the bits of `mask` set
|
72
75
|
def check_state(mask) (self.state & mask) == mask; end
|
data/lib/core/listener.rb
CHANGED
@@ -29,6 +29,9 @@ module Qpid::Proton
|
|
29
29
|
# connections. This class simply returns a fixed set of options for every
|
30
30
|
# connection accepted, but you can subclass and override all of the on_
|
31
31
|
# methods to provide more interesting behaviour.
|
32
|
+
#
|
33
|
+
# *Note*: If a {Listener} method raises an exception, it will stop the {Container}
|
34
|
+
# that the handler is running in. See {Container#run}
|
32
35
|
class Handler
|
33
36
|
# @param opts [Hash] Options to return from on_accept.
|
34
37
|
def initialize(opts=nil) @opts = opts || {}; end
|
@@ -72,6 +75,9 @@ module Qpid::Proton
|
|
72
75
|
# Get the {IO} server socket used by the listener
|
73
76
|
def to_io() @io; end
|
74
77
|
|
78
|
+
# Get the IP port used by the listener
|
79
|
+
def port() to_io.addr[1]; end
|
80
|
+
|
75
81
|
private # Called by {Container}
|
76
82
|
|
77
83
|
def initialize(io, handler, container)
|
data/lib/core/message.rb
CHANGED
@@ -73,15 +73,8 @@ module Qpid::Proton
|
|
73
73
|
# @private
|
74
74
|
def pre_encode
|
75
75
|
# encode elements from the message
|
76
|
-
Codec::Data.from_object(Cproton::pn_message_properties(@impl),
|
77
|
-
|
78
|
-
Codec::Data.from_object(Cproton::pn_message_instructions(@impl),
|
79
|
-
!@instructions.empty? && Types.symbol_keys!(@instructions))
|
80
|
-
if @annotations # Make sure keys are symbols
|
81
|
-
@annotations.keys.each do |k|
|
82
|
-
@annotations[k.to_sym] = @annotations.delete(k) unless k.is_a? Symbol
|
83
|
-
end
|
84
|
-
end
|
76
|
+
Codec::Data.from_object(Cproton::pn_message_properties(@impl), !@properties.empty? && @properties)
|
77
|
+
Codec::Data.from_object(Cproton::pn_message_instructions(@impl), !@instructions.empty? && @instructions)
|
85
78
|
Codec::Data.from_object(Cproton::pn_message_annotations(@impl), !@annotations.empty? && @annotations)
|
86
79
|
Codec::Data.from_object(Cproton::pn_message_body(@impl), @body)
|
87
80
|
end
|
@@ -95,6 +88,7 @@ module Qpid::Proton
|
|
95
88
|
@properties = {}
|
96
89
|
@instructions = {}
|
97
90
|
@annotations = {}
|
91
|
+
@body = nil
|
98
92
|
self.body = body unless body.nil?
|
99
93
|
if !opts.nil? then
|
100
94
|
opts.each do |k, v|
|
@@ -510,6 +504,8 @@ module Qpid::Proton
|
|
510
504
|
# @return [Object] body of the message.
|
511
505
|
attr_accessor :body
|
512
506
|
|
507
|
+
def inspect() pre_encode; super; end
|
508
|
+
|
513
509
|
private
|
514
510
|
|
515
511
|
def check(err) # :nodoc:
|
@@ -28,6 +28,9 @@ module Qpid::Proton
|
|
28
28
|
# {StopAutoResponse} from +#on_xxx_open+ or +#on_xxx_close+. The application becomes responsible
|
29
29
|
# for calling +#open/#close+ at a later point.
|
30
30
|
#
|
31
|
+
# *Note*: If a {MessagingHandler} method raises an exception, it will stop the {Container}
|
32
|
+
# that the handler is running in. See {Container#run}
|
33
|
+
#
|
31
34
|
class MessagingHandler
|
32
35
|
|
33
36
|
# @return [Hash] handler options, see {#initialize}
|
@@ -177,7 +180,8 @@ module Qpid::Proton
|
|
177
180
|
# @!group Unhandled events
|
178
181
|
|
179
182
|
# @!method on_error(error_condition)
|
180
|
-
#
|
183
|
+
# Called on an error if no more specific on_xxx_error method is provided.
|
184
|
+
# If on_error() is also not defined, the connection is closed with error_condition
|
181
185
|
# @param error_condition [Condition] Provides information about the error.
|
182
186
|
|
183
187
|
# @!method on_unhandled(method_name, *args)
|
data/lib/core/receiver.rb
CHANGED
@@ -35,11 +35,10 @@ module Qpid::Proton
|
|
35
35
|
# @param address [String] address of the source to receive from
|
36
36
|
# @overload open_receiver(opts)
|
37
37
|
# @param opts [Hash] Receiver options, see {Receiver#open}
|
38
|
-
# @option opts [
|
38
|
+
# @option opts [Integer] :credit_window automatically maintain this much credit
|
39
39
|
# for messages to be pre-fetched while the current message is processed.
|
40
40
|
# @option opts [Boolean] :auto_accept if true, deliveries that are not settled by
|
41
41
|
# the application in {MessagingHandler#on_message} are automatically accepted.
|
42
|
-
# @option opts [Integer] :credit_window (10) automatically replenish credits for flow control.
|
43
42
|
# @option opts [Boolean] :dynamic (false) dynamic property for source {Terminus#dynamic}
|
44
43
|
# @option opts [String,Hash] :source source address or source options, see {Terminus#apply}
|
45
44
|
# @option opts [String,Hash] :target target address or target options, see {Terminus#apply}
|
data/lib/core/sasl.rb
CHANGED
data/lib/core/session.rb
CHANGED
@@ -114,16 +114,14 @@ module Qpid::Proton
|
|
114
114
|
# @param opts [Hash] receiver options, see {Receiver#open}
|
115
115
|
# @return [Receiver]
|
116
116
|
def open_receiver(opts=nil)
|
117
|
-
|
118
|
-
Receiver.new(Cproton.pn_receiver(@impl, name)).open(opts)
|
117
|
+
Receiver.new(Cproton.pn_receiver(@impl, link_name(opts))).open(opts)
|
119
118
|
end
|
120
119
|
|
121
120
|
# Create and open a {Sender} link, see {#open}
|
122
121
|
# @param opts [Hash] sender options, see {Sender#open}
|
123
122
|
# @return [Sender]
|
124
123
|
def open_sender(opts=nil)
|
125
|
-
|
126
|
-
Sender.new(Cproton.pn_sender(@impl, name)).open(opts)
|
124
|
+
Sender.new(Cproton.pn_sender(@impl, link_name(opts))).open(opts)
|
127
125
|
end
|
128
126
|
|
129
127
|
# Get the links on this Session.
|
@@ -150,6 +148,10 @@ module Qpid::Proton
|
|
150
148
|
|
151
149
|
private
|
152
150
|
|
151
|
+
def link_name(opts)
|
152
|
+
(opts.respond_to?(:to_hash) && opts[:name]) || connection.link_name
|
153
|
+
end
|
154
|
+
|
153
155
|
def _local_condition
|
154
156
|
Cproton.pn_session_condition(@impl)
|
155
157
|
end
|
data/lib/core/terminus.rb
CHANGED
@@ -68,7 +68,7 @@ module Qpid::Proton
|
|
68
68
|
# @private
|
69
69
|
PROTON_METHOD_PREFIX = "pn_terminus"
|
70
70
|
# @private
|
71
|
-
|
71
|
+
extend Util::SWIGClassHelper
|
72
72
|
|
73
73
|
# @!attribute type
|
74
74
|
#
|
@@ -234,15 +234,21 @@ module Qpid::Proton
|
|
234
234
|
when :dynamic then self.dynamic = !!v
|
235
235
|
when :distribution_mode then self.distribution_mode = v
|
236
236
|
when :durability_mode then self.durability_mode = v
|
237
|
-
when :timeout then self.timeout = v
|
237
|
+
when :timeout then self.timeout = v.round # Should be integer seconds
|
238
238
|
when :expiry_policy then self.expiry_policy = v
|
239
|
-
when :filter then self.filter
|
240
|
-
when :capabilities then self.capabilities
|
239
|
+
when :filter then self.filter << v
|
240
|
+
when :capabilities then self.capabilities << v
|
241
241
|
end
|
242
242
|
end
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
+
def inspect()
|
247
|
+
"\#<#{self.class}: address=#{address.inspect} dynamic?=#{dynamic?.inspect}>"
|
248
|
+
end
|
249
|
+
|
250
|
+
def to_s() inspect; end
|
251
|
+
|
246
252
|
can_raise_error([:type=, :address=, :durability=, :expiry_policy=,
|
247
253
|
:timeout=, :dynamic=, :distribution_mode=, :copy],
|
248
254
|
:error_class => Qpid::Proton::LinkError)
|
data/lib/core/transfer.rb
CHANGED
@@ -88,6 +88,9 @@ module Qpid::Proton
|
|
88
88
|
# @return [Transport] The parent connection's transport.
|
89
89
|
def transport() self.connection.transport; end
|
90
90
|
|
91
|
+
# @return [WorkQueue] The parent connection's work-queue.
|
92
|
+
def work_queue() self.connection.work_queue; end
|
93
|
+
|
91
94
|
# @deprecated internal use only
|
92
95
|
proton_caller :writable?
|
93
96
|
# @deprecated internal use only
|