qpid_proton 0.21.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/transport.rb
CHANGED
data/lib/core/uri.rb
CHANGED
@@ -43,19 +43,16 @@ module Qpid::Proton
|
|
43
43
|
|
44
44
|
public
|
45
45
|
|
46
|
-
# Convert +s+ to
|
46
|
+
# Convert +s+ to an amqp: or amqps: URI
|
47
47
|
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# @note this does not give the same result as a standard URI parser in all cases.
|
52
|
-
# For standard conversion to a URI use: {#URI}(s)
|
48
|
+
# This does not give the same result as the standard URI parser in all cases.
|
49
|
+
# Short-cut strings like "host:port" are allowed, an "amqp://" prefix is added if +s+ does
|
50
|
+
# not already look like an 'amqp:' or 'amqps:' URI.
|
53
51
|
#
|
54
52
|
# @param s [String,URI] String to convert to a URI, or a URI object.
|
55
|
-
#
|
56
|
-
# @
|
57
|
-
# @raise [
|
58
|
-
# @raise [InvalidURIError] s cannot be parsed as a URI or shortcut
|
53
|
+
# @return [URI] A valid AMQP or AMQPS URI
|
54
|
+
# @raise [URI::BadURIError] s is a URI object with a non-AMQP scheme
|
55
|
+
# @raise [URI::InvalidURIError] s cannot be parsed as a URI or shortcut
|
59
56
|
# @raise [::ArgumentError] s is not a string or URI
|
60
57
|
#
|
61
58
|
def self.uri(s)
|
@@ -75,5 +72,7 @@ module Qpid::Proton
|
|
75
72
|
else DEFAULT_URI_PARSER.parse("amqp://#{s}") # Treat as a bare host:port/path string
|
76
73
|
end
|
77
74
|
end
|
75
|
+
rescue =>e
|
76
|
+
raise e.class, "#{self}.#{__method__}(#{s.inspect}): #{e}"
|
78
77
|
end
|
79
78
|
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
|
18
|
+
module Qpid::Proton
|
19
|
+
|
20
|
+
# A thread-safe queue of work for multi-threaded programs.
|
21
|
+
#
|
22
|
+
# Instances of {Connection} and objects associated with it ({Session}, {Sender},
|
23
|
+
# {Receiver}, {Delivery}, {Tracker}) are not thread-safe and must be
|
24
|
+
# used correctly when multiple threads call {Container#run}
|
25
|
+
#
|
26
|
+
# Calls to {MessagingHandler} methods by the {Container} are automatically
|
27
|
+
# serialized for each connection instance. Other threads may have code
|
28
|
+
# similarly serialized by adding it to the {Connection#work_queue} for the
|
29
|
+
# connection. Each object related to a {Connection} also provides a
|
30
|
+
# +work_queue+ method.
|
31
|
+
#
|
32
|
+
class WorkQueue
|
33
|
+
|
34
|
+
# Add code to be executed in series with other {Container} operations on the
|
35
|
+
# work queue's owner. The code will be executed as soon as possible.
|
36
|
+
#
|
37
|
+
# @note Thread Safe: may be called in any thread.
|
38
|
+
# @param non_block [Boolean] if true raise {ThreadError} if the operation would block.
|
39
|
+
# @yield [ ] the block will be invoked with no parameters in the {WorkQueue} context,
|
40
|
+
# which may be a different thread.
|
41
|
+
# @return [void]
|
42
|
+
# @raise [ThreadError] if +non_block+ is true and the operation would block
|
43
|
+
# @raise [EOFError] if the queue is closed and cannot accept more work
|
44
|
+
def add(non_block=false, &block)
|
45
|
+
@schedule.add(Time.at(0), non_block, &block)
|
46
|
+
@container.send :wake
|
47
|
+
end
|
48
|
+
|
49
|
+
# Schedule code to be executed after +delay+ seconds in series with other
|
50
|
+
# {Container} operations on the work queue's owner.
|
51
|
+
#
|
52
|
+
# Work scheduled for after the {WorkQueue} has closed will be silently dropped.
|
53
|
+
#
|
54
|
+
# @note (see #add)
|
55
|
+
# @param delay delay in seconds until the block is added to the queue.
|
56
|
+
# @param (see #add)
|
57
|
+
# @yield (see #add)
|
58
|
+
# @return [void]
|
59
|
+
# @raise (see #add)
|
60
|
+
def schedule(delay, non_block=false, &block)
|
61
|
+
@schedule.add(Time.now + delay, non_block, &block)
|
62
|
+
@container.send :wake
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def initialize(container)
|
68
|
+
@schedule = Schedule.new
|
69
|
+
@container = container
|
70
|
+
end
|
71
|
+
|
72
|
+
def close() @schedule.close; end
|
73
|
+
def process(now) @schedule.process(now); end
|
74
|
+
def next_tick() @schedule.next_tick; end
|
75
|
+
end
|
76
|
+
end
|
data/lib/qpid_proton.rb
CHANGED
@@ -26,6 +26,7 @@ rescue LoadError
|
|
26
26
|
require "kconv" # Ruby < 1.9
|
27
27
|
end
|
28
28
|
|
29
|
+
# @api qpid
|
29
30
|
# Qpid is the top level module for the Qpid project http://qpid.apache.org
|
30
31
|
# Definitions for this library are in module {Qpid::Proton}
|
31
32
|
module Qpid
|
@@ -43,8 +44,8 @@ require "core/exceptions"
|
|
43
44
|
require "util/deprecation"
|
44
45
|
require "util/version"
|
45
46
|
require "util/error_handler"
|
47
|
+
require "util/schedule"
|
46
48
|
require "util/wrapper"
|
47
|
-
require "util/timeout"
|
48
49
|
|
49
50
|
# Types
|
50
51
|
require "types/type"
|
@@ -93,10 +94,3 @@ require "core/container"
|
|
93
94
|
require "handler/reactor_messaging_adapter"
|
94
95
|
require "handler/messaging_handler" # Keep original name for compatibility
|
95
96
|
require "reactor/container"
|
96
|
-
|
97
|
-
# DEPRECATED Messenger API classes
|
98
|
-
require "messenger/subscription"
|
99
|
-
require "messenger/tracker_status"
|
100
|
-
require "messenger/tracker"
|
101
|
-
require "messenger/messenger"
|
102
|
-
|
data/lib/types/array.rb
CHANGED
@@ -49,6 +49,7 @@ module Qpid::Proton
|
|
49
49
|
# @param descriptor [Object] Optional array descriptor
|
50
50
|
def initialize(type, elements=nil, descriptor=nil)
|
51
51
|
@type, @descriptor = type, descriptor
|
52
|
+
@proton_array_header = nil
|
52
53
|
raise ArgumentError, "no type specified for array" if @type.nil?
|
53
54
|
super elements if elements
|
54
55
|
end
|
data/lib/types/hash.rb
CHANGED
@@ -37,14 +37,3 @@ class Hash # :nodoc:
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
module Qpid::Proton::Types
|
41
|
-
# @private
|
42
|
-
def self.symbol_keys(h)
|
43
|
-
h && h.reduce({}) { |x, (k, v)| x[k.to_sym] = v; x }
|
44
|
-
end
|
45
|
-
|
46
|
-
# @private
|
47
|
-
def self.symbol_array(a)
|
48
|
-
a && UniformArray.new(SYMBOL, a.collect { |v| v.to_sym })
|
49
|
-
end
|
50
|
-
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
12
|
+
# software distributed under the License is distributed on an
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
+
# KIND, either express or implied. See the License for the
|
15
|
+
# specific language governing permissions and limitations
|
16
|
+
# under the License.
|
17
|
+
|
18
|
+
module Qpid::Proton
|
19
|
+
|
20
|
+
# @private
|
21
|
+
module TimeCompare
|
22
|
+
# t1 <= t2, where nil is treated as "distant future"
|
23
|
+
def before_eq(t1, t2) (t1 && t2) ? (t1 <= t2) : t1; end
|
24
|
+
|
25
|
+
# min(t1, t2) where nil is treated as "distant future"
|
26
|
+
def earliest(t1, t2) before_eq(t1, t2) ? t1 : t2; end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @private
|
30
|
+
# A sorted, thread-safe list of scheduled Proc.
|
31
|
+
# Note: calls to #process are always serialized, but calls to #add may be concurrent.
|
32
|
+
class Schedule
|
33
|
+
include TimeCompare
|
34
|
+
Item = Struct.new(:time, :proc)
|
35
|
+
|
36
|
+
def initialize()
|
37
|
+
@lock = Mutex.new
|
38
|
+
@items = []
|
39
|
+
@closed = false
|
40
|
+
end
|
41
|
+
|
42
|
+
def next_tick()
|
43
|
+
@lock.synchronize { @items.first.time unless @items.empty? }
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return true if the Schedule was previously empty
|
47
|
+
# @raise EOFError if schedule is closed
|
48
|
+
# @raise ThreadError if +non_block+ and operation would block
|
49
|
+
def add(time, non_block=false, &proc)
|
50
|
+
# non_block ignored for now, but we may implement a bounded schedule in future.
|
51
|
+
@lock.synchronize do
|
52
|
+
raise EOFError if @closed
|
53
|
+
if at = (0...@items.size).bsearch { |i| @items[i].time > time }
|
54
|
+
@items.insert(at, Item.new(time, proc))
|
55
|
+
else
|
56
|
+
@items << Item.new(time, proc)
|
57
|
+
end
|
58
|
+
return @items.size == 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return true if the Schedule became empty as a result of this call
|
63
|
+
def process(now)
|
64
|
+
due = []
|
65
|
+
empty = @lock.synchronize do
|
66
|
+
due << @items.shift while (!@items.empty? && before_eq(@items.first.time, now))
|
67
|
+
@items.empty?
|
68
|
+
end
|
69
|
+
due.each { |i| i.proc.call() }
|
70
|
+
return empty && !due.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
# #add raises EOFError after #close.
|
74
|
+
# #process can still be called to drain the schedule.
|
75
|
+
def close()
|
76
|
+
@lock.synchronize { @closed = true }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/util/wrapper.rb
CHANGED
@@ -115,6 +115,10 @@ module Qpid::Proton
|
|
115
115
|
end
|
116
116
|
|
117
117
|
# @private
|
118
|
+
#
|
119
|
+
# Instance methods to include in classes that wrap pn_object types
|
120
|
+
# that support pn_inspect etc. Automatically extends SWIGClassHelper
|
121
|
+
#
|
118
122
|
module Wrapper
|
119
123
|
|
120
124
|
def self.included(base)
|
@@ -52,14 +52,6 @@ class OldExampleTest < MiniTest::Test
|
|
52
52
|
assert_output want, ["simple_recv.rb", "-a", make_url($port, __method__)]
|
53
53
|
end
|
54
54
|
|
55
|
-
def test_smoke
|
56
|
-
url = "127.0.0.1:#{unused_port}"
|
57
|
-
recv = run_script("recv.rb", "~#{url}")
|
58
|
-
recv.readline # Wait for "Listening"
|
59
|
-
assert_output("Status: ACCEPTED", ["send.rb", url])
|
60
|
-
assert_equal "Got: Hello World!", recv.read.strip
|
61
|
-
end
|
62
|
-
|
63
55
|
def test_client_server
|
64
56
|
want = <<EOS
|
65
57
|
-> Twas brillig, and the slithy toves
|