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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 606167f90e6d8e39827fd3166b073468735f6cb9
|
4
|
+
data.tar.gz: 8a98a50b98eebc56846228ed843780d9c139fc06
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5850008fb8352a0773900878d0bc1afba63e8b8d6caacb9602fa4ff501086ed5b7fcf07edc978fd446866bce66e432698dee49c639fafb3eaf47097b4701b9c
|
7
|
+
data.tar.gz: dcd40be0c4ef4cf579e906606030120cd36e6bba9d59e9850e9443454ec6ff4c5da6a9678b1e11c726fd2cc6b65b5033bcbef953a057255b9bef851df756f024
|
data/examples/README.md
CHANGED
@@ -58,19 +58,35 @@ In this set of examples we see the following event occurring, in addition to wha
|
|
58
58
|
|
59
59
|
## Now About That Broker example
|
60
60
|
|
61
|
-
The **broker.rb** example application is a nice demonstration of doing something more interesting in Ruby with Proton.
|
61
|
+
The **broker.rb** example application is a nice demonstration of doing something more interesting in Ruby with Proton, and shows how to use multiple threads.
|
62
62
|
|
63
|
-
The
|
63
|
+
The broker listens for incoming connections and sender/receiver links. It uses the source and target address of senders and receivers to identify a queue. Messages from receivers go on the queue, and are sent via senders.
|
64
64
|
|
65
65
|
The components of the broker example include:
|
66
|
-
* **Broker**
|
67
|
-
* **
|
68
|
-
|
69
|
-
The Broker manages a map connecting a queue address to the instance of Exchange that holds references to the endpoints of interest.
|
66
|
+
* **Broker** is a Listener::Handler that accepts connections, and manages the set of named queues.
|
67
|
+
* **BrokerHandler** extends MessagingHandler to accept incoming connections, senders and receivers and transfers messages between them and the Broker's queues.
|
68
|
+
* **MessageQueue** - A queue of messages that keeps track of waiting senders.
|
70
69
|
|
71
70
|
The broker application demonstrates a new set of events:
|
72
71
|
|
73
|
-
* **
|
74
|
-
* **
|
75
|
-
* **on_connection_close** - Fired when
|
76
|
-
* **on_transport_close** - Fired when the
|
72
|
+
* **on_sender_open** - Fired when a sender link is opened, the broker gets the address and starts sending messages from the corresponding queue.
|
73
|
+
* **on_sender_close** - Fired when a sender link is closed, remove the sender from the queue so no more messages are sent.
|
74
|
+
* **on_connection_close** - Fired when the remote connection is closes, close all senders.
|
75
|
+
* **on_transport_close** - Fired when the transport (socket) has closed, close all senders.
|
76
|
+
|
77
|
+
It also demonstrates aspects of multi-threaded proton:
|
78
|
+
|
79
|
+
* **Thread safe MessageQueue** Uses a Mutex to make actions atomic when called concurrently.
|
80
|
+
|
81
|
+
* **Using WorkQueue** Proton objects like Sender are not thread safe. They are
|
82
|
+
normally only used in MessagingHandler#on_ callbacks. To request work from a
|
83
|
+
different thread you can add a code block to a WorkQueue, as shown in
|
84
|
+
MessageQueue#push.
|
85
|
+
|
86
|
+
* **Listener::Handler** The broker creates a new BrokerHandler instance for
|
87
|
+
each accepted connection. The container ensures that calls on each handler instance
|
88
|
+
are serialized even if there are multiple threads in the container.
|
89
|
+
|
90
|
+
* **Calling Container#run in multiple threads** The Container uses threads that call
|
91
|
+
#run as a thread pool to dispatch calls to MessagingHandler instances. Even
|
92
|
+
if there are multiple threads, calls to handler instance are serialized.
|
data/examples/broker.rb
CHANGED
@@ -21,139 +21,142 @@ require 'qpid_proton'
|
|
21
21
|
require 'optparse'
|
22
22
|
require 'pathname'
|
23
23
|
|
24
|
+
# Thread safe message queue that notifies waiting senders when messages arrive.
|
24
25
|
class MessageQueue
|
25
26
|
|
26
|
-
def initialize
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
27
|
+
def initialize
|
28
|
+
@lock = Mutex.new # Make ations on the queue atomic
|
29
|
+
@messages = [] # Messages on the queue
|
30
|
+
@waiting = [] # Senders that are waiting for messages
|
31
|
+
end
|
32
|
+
|
33
|
+
# Push a message onto the queue and notify any waiting senders
|
34
|
+
def push(message)
|
35
|
+
@lock.synchronize do
|
36
|
+
@messages << message
|
37
|
+
unless @waiting.empty? # Notify waiting senders
|
38
|
+
# NOTE: the call to self.send_to is added to the sender's work_queue,
|
39
|
+
# and will be executed in the sender's thread
|
40
|
+
@waiting.each { |s| s.work_queue.add { self.send_to(s); } }
|
41
|
+
@waiting.clear
|
42
|
+
end
|
39
43
|
end
|
40
|
-
@consumers.empty? && (@dynamic || @queue.empty?)
|
41
|
-
end
|
42
|
-
|
43
|
-
def publish(message)
|
44
|
-
@queue << message
|
45
|
-
self.dispatch
|
46
44
|
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
46
|
+
# Pop a message off the queue.
|
47
|
+
# If no messages available, record sender as waiting and return nil.
|
48
|
+
def pop(sender)
|
49
|
+
@lock.synchronize do
|
50
|
+
if @messages.empty?
|
51
|
+
@waiting << sender
|
52
|
+
nil
|
53
|
+
else
|
54
|
+
@messages.shift
|
55
|
+
end
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
59
|
+
# NOTE: Called in sender's thread.
|
60
|
+
# Pull messages from the queue as long as sender has credit.
|
61
|
+
# If queue runs out of messages, record sender as waiting.
|
62
|
+
def send_to(sender)
|
63
|
+
while sender.credit > 0 && (message = pop(sender))
|
64
|
+
sender.send(message)
|
66
65
|
end
|
67
|
-
return result
|
68
66
|
end
|
69
67
|
|
68
|
+
def forget(sender)
|
69
|
+
@lock.synchronize { @waiting.delete(sender) }
|
70
|
+
end
|
70
71
|
end
|
71
72
|
|
72
|
-
class Broker < Qpid::Proton::MessagingHandler
|
73
|
-
|
74
|
-
def initialize(url)
|
75
|
-
super()
|
76
|
-
@url = url
|
77
|
-
@queues = {}
|
78
|
-
begin # Optional SSL setup, ignore if we don't find cert files etc.
|
79
|
-
@ssl_domain = Qpid::Proton::SSLDomain.new(Qpid::Proton::SSLDomain::MODE_SERVER)
|
80
|
-
cert_passsword = "tserverpw"
|
81
|
-
if Gem.win_platform? # Use P12 certs for windows schannel
|
82
|
-
@ssl_domain.credentials("ssl_certs/tserver-certificate.p12", "", cert_passsword)
|
83
|
-
else
|
84
|
-
@ssl_domain.credentials("ssl_certs/tserver-certificate.pem", "ssl_certs/tserver-private-key.pem", cert_passsword)
|
85
|
-
end
|
86
|
-
@ssl_domain.allow_unsecured_client # SSL is optional, this is not secure.
|
87
|
-
rescue
|
88
|
-
@ssl_domain = nil # Don't worry if we can't set up SSL.
|
89
|
-
end
|
90
|
-
end
|
91
73
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
@listener = container.listen(@url, Qpid::Proton::Listener::Handler.new(opts))
|
96
|
-
STDOUT.puts "Listening on #{@url.inspect}"; STDOUT.flush
|
97
|
-
end
|
74
|
+
# Handler for broker connections. In a multi-threaded application you should
|
75
|
+
# normally create a separate handler instance for each connection.
|
76
|
+
class BrokerHandler < Qpid::Proton::MessagingHandler
|
98
77
|
|
99
|
-
def
|
100
|
-
|
101
|
-
@queues[address] = MessageQueue.new
|
102
|
-
end
|
103
|
-
@queues[address]
|
78
|
+
def initialize(broker)
|
79
|
+
@broker = broker
|
104
80
|
end
|
105
81
|
|
106
82
|
def on_sender_open(sender)
|
107
83
|
if sender.remote_source.dynamic?
|
108
|
-
address = SecureRandom.uuid
|
109
|
-
sender.source.address = address
|
110
|
-
q = MessageQueue.new(true)
|
111
|
-
@queues[address] = q
|
112
|
-
q.subscribe(sender)
|
84
|
+
sender.source.address = SecureRandom.uuid
|
113
85
|
elsif sender.remote_source.address
|
114
86
|
sender.source.address = sender.remote_source.address
|
115
|
-
|
87
|
+
else
|
88
|
+
sender.connection.close("no source address")
|
89
|
+
return
|
116
90
|
end
|
91
|
+
q = @broker.queue(sender.source.address)
|
92
|
+
q.send_to(sender)
|
117
93
|
end
|
118
94
|
|
119
95
|
def on_receiver_open(receiver)
|
120
96
|
if receiver.remote_target.address
|
121
97
|
receiver.target.address = receiver.remote_target.address
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
def unsubscribe(link)
|
126
|
-
if @queues.has_key?(link.source.address)
|
127
|
-
if @queues[link.source.address].unsubscribe(link)
|
128
|
-
@queues.delete(link.source.address)
|
129
|
-
end
|
98
|
+
else
|
99
|
+
receiver.connection.close("no target address")
|
130
100
|
end
|
131
101
|
end
|
132
102
|
|
133
103
|
def on_sender_close(sender)
|
134
|
-
|
104
|
+
q = @broker.queue(sender.source.address)
|
105
|
+
q.forget(sender) if q
|
135
106
|
end
|
136
107
|
|
137
108
|
def on_connection_close(connection)
|
138
|
-
|
109
|
+
connection.each_sender { |s| on_sender_close(s) }
|
139
110
|
end
|
140
111
|
|
141
112
|
def on_transport_close(transport)
|
142
|
-
|
143
|
-
end
|
144
|
-
|
145
|
-
def remove_stale_consumers(connection)
|
146
|
-
connection.each_sender { |s| unsubscribe(s) }
|
113
|
+
transport.connection.each_sender { |s| on_sender_close(s) }
|
147
114
|
end
|
148
115
|
|
149
116
|
def on_sendable(sender)
|
150
|
-
|
151
|
-
q.dispatch(sender)
|
117
|
+
@broker.queue(sender.source.address).send_to(sender)
|
152
118
|
end
|
153
119
|
|
154
120
|
def on_message(delivery, message)
|
155
|
-
|
156
|
-
|
121
|
+
@broker.queue(delivery.receiver.target.address).push(message)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Broker manages the queues and accepts incoming connections.
|
126
|
+
class Broker < Qpid::Proton::Listener::Handler
|
127
|
+
|
128
|
+
def initialize
|
129
|
+
@queues = {}
|
130
|
+
@connection_options = {}
|
131
|
+
ssl_setup
|
132
|
+
end
|
133
|
+
|
134
|
+
def ssl_setup
|
135
|
+
# Optional SSL setup
|
136
|
+
ssl = Qpid::Proton::SSLDomain.new(Qpid::Proton::SSLDomain::MODE_SERVER)
|
137
|
+
cert_passsword = "tserverpw"
|
138
|
+
if Gem.win_platform? # Use P12 certs for windows schannel
|
139
|
+
ssl.credentials("ssl_certs/tserver-certificate.p12", "", cert_passsword)
|
140
|
+
else
|
141
|
+
ssl.credentials("ssl_certs/tserver-certificate.pem", "ssl_certs/tserver-private-key.pem", cert_passsword)
|
142
|
+
end
|
143
|
+
ssl.allow_unsecured_client # SSL is optional, this is not secure.
|
144
|
+
@connection_options[:ssl_domain] = ssl if ssl
|
145
|
+
rescue
|
146
|
+
# Don't worry if we can't set up SSL.
|
147
|
+
end
|
148
|
+
|
149
|
+
def on_open(l)
|
150
|
+
STDOUT.puts "Listening on #{l}\n"; STDOUT.flush
|
151
|
+
end
|
152
|
+
|
153
|
+
# Create a new BrokerHandler instance for each connection we accept
|
154
|
+
def on_accept(l)
|
155
|
+
{ :handler => BrokerHandler.new(self) }.update(@connection_options)
|
156
|
+
end
|
157
|
+
|
158
|
+
def queue(address)
|
159
|
+
@queues[address] ||= MessageQueue.new
|
157
160
|
end
|
158
161
|
|
159
162
|
end
|
@@ -164,4 +167,9 @@ Start an example broker listening on URL"
|
|
164
167
|
return 1
|
165
168
|
end
|
166
169
|
url, = ARGV
|
167
|
-
Qpid::Proton::Container.new
|
170
|
+
container = Qpid::Proton::Container.new
|
171
|
+
container.listen(url, Broker.new)
|
172
|
+
|
173
|
+
# Run the container in multiple threads.
|
174
|
+
threads = 4.times.map { Thread.new { container.run }}
|
175
|
+
threads.each { |t| t.join }
|
data/examples/example_test.rb
CHANGED
@@ -46,7 +46,7 @@ class ExampleTest < MiniTest::Test
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_helloworld
|
49
|
-
assert_output("Hello world!", "helloworld.rb", $url,
|
49
|
+
assert_output("Hello world!", "helloworld.rb", $url, "examples")
|
50
50
|
end
|
51
51
|
|
52
52
|
def test_client_server
|
@@ -60,40 +60,40 @@ class ExampleTest < MiniTest::Test
|
|
60
60
|
-> And the mome raths outgrabe.
|
61
61
|
<- AND THE MOME RATHS OUTGRABE.
|
62
62
|
EOS
|
63
|
-
server = run_script("server.rb", $url,
|
64
|
-
assert_output(want.strip, "client.rb", $url,
|
63
|
+
server = run_script("server.rb", $url, "examples")
|
64
|
+
assert_output(want.strip, "client.rb", $url, "examples")
|
65
65
|
ensure
|
66
66
|
Process.kill :TERM, server.pid if server
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_send_recv
|
70
|
-
assert_output("All 10 messages confirmed!", "simple_send.rb", $url,
|
70
|
+
assert_output("All 10 messages confirmed!", "simple_send.rb", $url, "examples")
|
71
71
|
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
72
|
-
assert_output(want.strip, "simple_recv.rb", $url,
|
72
|
+
assert_output(want.strip, "simple_recv.rb", $url, "examples")
|
73
73
|
end
|
74
74
|
|
75
75
|
def test_ssl_send_recv
|
76
|
-
out = run_script("ssl_send.rb", $url,
|
76
|
+
out = run_script("ssl_send.rb", $url, "examples").read.strip
|
77
77
|
assert_match(/Connection secured with "...*\"\nAll 10 messages confirmed!/, out)
|
78
78
|
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
79
|
-
assert_output(want.strip, "simple_recv.rb", $url,
|
79
|
+
assert_output(want.strip, "simple_recv.rb", $url, "examples")
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_direct_recv
|
83
83
|
url = test_url
|
84
|
-
p = run_script("direct_recv.rb", url,
|
84
|
+
p = run_script("direct_recv.rb", url, "examples")
|
85
85
|
p.readline # Wait till ready
|
86
|
-
assert_output("All 10 messages confirmed!", "simple_send.rb", url,
|
86
|
+
assert_output("All 10 messages confirmed!", "simple_send.rb", url, "examples")
|
87
87
|
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
88
88
|
assert_equal(want.strip, p.read.strip)
|
89
89
|
end
|
90
90
|
|
91
91
|
def test_direct_send
|
92
92
|
url = test_url
|
93
|
-
p = run_script("direct_send.rb", url,
|
93
|
+
p = run_script("direct_send.rb", url, "examples")
|
94
94
|
p.readline # Wait till ready
|
95
95
|
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
96
|
-
assert_output(want.strip, "simple_recv.rb", url,
|
96
|
+
assert_output(want.strip, "simple_recv.rb", url, "examples")
|
97
97
|
assert_equal("All 10 messages confirmed!", p.read.strip)
|
98
98
|
end
|
99
99
|
end
|
data/ext/cproton/cproton.c
CHANGED
@@ -19329,7 +19329,7 @@ _wrap_pn_data_put_decimal32(int argc, VALUE *argv, VALUE self) {
|
|
19329
19329
|
}
|
19330
19330
|
arg1 = (pn_data_t *)(argp1);
|
19331
19331
|
{
|
19332
|
-
arg2 =
|
19332
|
+
arg2 = NUM2UINT(argv[1]);
|
19333
19333
|
}
|
19334
19334
|
result = (int)pn_data_put_decimal32(arg1,arg2);
|
19335
19335
|
vresult = SWIG_From_int((int)(result));
|
@@ -20044,7 +20044,7 @@ _wrap_pn_data_get_decimal32(int argc, VALUE *argv, VALUE self) {
|
|
20044
20044
|
arg1 = (pn_data_t *)(argp1);
|
20045
20045
|
result = (pn_decimal32_t)pn_data_get_decimal32(arg1);
|
20046
20046
|
{
|
20047
|
-
vresult =
|
20047
|
+
vresult = UINT2NUM(result);
|
20048
20048
|
}
|
20049
20049
|
return vresult;
|
20050
20050
|
fail:
|
@@ -23711,7 +23711,7 @@ SWIGEXPORT void Init_cproton(void) {
|
|
23711
23711
|
rb_define_module_function(mCproton, "pni_connection_driver", _wrap_pni_connection_driver, -1);
|
23712
23712
|
rb_define_const(mCproton, "PROTON_IMPORT_EXPORT_H", SWIG_From_int((int)(1)));
|
23713
23713
|
rb_define_const(mCproton, "PN_VERSION_MAJOR", SWIG_From_int((int)(0)));
|
23714
|
-
rb_define_const(mCproton, "PN_VERSION_MINOR", SWIG_From_int((int)(
|
23714
|
+
rb_define_const(mCproton, "PN_VERSION_MINOR", SWIG_From_int((int)(22)));
|
23715
23715
|
rb_define_const(mCproton, "PN_VERSION_POINT", SWIG_From_int((int)(0)));
|
23716
23716
|
rb_define_const(mCproton, "PROTON_TYPES_H", SWIG_From_int((int)(1)));
|
23717
23717
|
rb_define_const(mCproton, "PN_MILLIS_MAX", SWIG_From_unsigned_SS_int((unsigned int)((~0U))));
|
data/lib/core/connection.rb
CHANGED
@@ -124,9 +124,8 @@ module Qpid::Proton
|
|
124
124
|
|
125
125
|
# @private
|
126
126
|
def apply opts
|
127
|
-
# NOTE: Only connection options are set here.
|
128
|
-
# with {Transport#apply}
|
129
|
-
# on_connection_bound if not using a connection_driver)
|
127
|
+
# NOTE: Only connection options are set here.
|
128
|
+
# Transport options must be applied with {Transport#apply}
|
130
129
|
@container = opts[:container]
|
131
130
|
cid = opts[:container_id] || (@container && @container.id) || SecureRandom.uuid
|
132
131
|
cid = cid.to_s if cid.is_a? Symbol # Allow symbols as container name
|
@@ -135,12 +134,9 @@ module Qpid::Proton
|
|
135
134
|
Cproton.pn_connection_set_password(@impl, opts[:password]) if opts[:password]
|
136
135
|
Cproton.pn_connection_set_hostname(@impl, opts[:virtual_host]) if opts[:virtual_host]
|
137
136
|
@link_prefix = opts[:link_prefix] || cid
|
138
|
-
Codec::Data.from_object(Cproton.pn_connection_offered_capabilities(@impl),
|
139
|
-
|
140
|
-
Codec::Data.from_object(Cproton.
|
141
|
-
Types.symbol_array(opts[:desired_capabilities]))
|
142
|
-
Codec::Data.from_object(Cproton.pn_connection_properties(@impl),
|
143
|
-
Types.symbol_keys(opts[:properties]))
|
137
|
+
Codec::Data.from_object(Cproton.pn_connection_offered_capabilities(@impl), opts[:offered_capabilities])
|
138
|
+
Codec::Data.from_object(Cproton.pn_connection_desired_capabilities(@impl), opts[:desired_capabilities])
|
139
|
+
Codec::Data.from_object(Cproton.pn_connection_properties(@impl), opts[:properties])
|
144
140
|
end
|
145
141
|
|
146
142
|
# Idle-timeout advertised by the remote peer, in seconds.
|
@@ -253,17 +249,24 @@ module Qpid::Proton
|
|
253
249
|
return enum_for(:each_link) unless block_given?
|
254
250
|
l = Cproton.pn_link_head(@impl, 0);
|
255
251
|
while l
|
256
|
-
yield
|
252
|
+
l2 = l # get next before yield, in case yield closes l and unlinks it
|
257
253
|
l = Cproton.pn_link_next(l, 0)
|
254
|
+
yield Link.wrap(l2)
|
258
255
|
end
|
259
256
|
self
|
260
257
|
end
|
261
258
|
|
262
259
|
# Get the {Sender} links - see {#each_link}
|
263
|
-
def each_sender()
|
260
|
+
def each_sender()
|
261
|
+
return enum_for(:each_sender) unless block_given?
|
262
|
+
each_link.select { |l| yield l if l.sender? }
|
263
|
+
end
|
264
264
|
|
265
265
|
# Get the {Receiver} links - see {#each_link}
|
266
|
-
|
266
|
+
def each_receiver()
|
267
|
+
return enum_for(:each_receiver) unless block_given?
|
268
|
+
each_link.select { |l| yield l if l.receiver? }
|
269
|
+
end
|
267
270
|
|
268
271
|
# @deprecated use {#MessagingHandler} to handle work
|
269
272
|
def work_head
|
@@ -282,6 +285,9 @@ module Qpid::Proton
|
|
282
285
|
@link_prefix + "/" + (@link_count += 1).to_s(32)
|
283
286
|
end
|
284
287
|
|
288
|
+
# @return [WorkQueue] work queue to execute code serialized correctly for this connection
|
289
|
+
attr_reader :work_queue
|
290
|
+
|
285
291
|
protected
|
286
292
|
|
287
293
|
def _local_condition
|
@@ -118,9 +118,17 @@ module Qpid::Proton
|
|
118
118
|
def tick(now=Time.now)
|
119
119
|
transport = Cproton.pni_connection_driver_transport(@impl)
|
120
120
|
ms = Cproton.pn_transport_tick(transport, (now.to_r * 1000).to_i)
|
121
|
-
|
121
|
+
@next_tick = ms.zero? ? nil : Time.at(ms.to_r / 1000);
|
122
|
+
unless @next_tick
|
123
|
+
idle = Cproton.pn_transport_get_idle_timeout(transport);
|
124
|
+
@next_tick = now + (idle.to_r / 1000) unless idle.zero?
|
125
|
+
end
|
126
|
+
@next_tick
|
122
127
|
end
|
123
128
|
|
129
|
+
# Time returned by the last call to {#tick}
|
130
|
+
attr_accessor :next_tick
|
131
|
+
|
124
132
|
# Disconnect the write side of the transport, *without* sending an AMQP
|
125
133
|
# close frame. To close politely, you should use {Connection#close}, the
|
126
134
|
# transport will close itself once the protocol close is complete.
|
@@ -181,6 +189,7 @@ module Qpid::Proton
|
|
181
189
|
case e.method # Events that affect the driver
|
182
190
|
when :on_transport_tail_closed then close_read
|
183
191
|
when :on_transport_head_closed then close_write
|
192
|
+
when :on_transport_closed then @io.close rescue nil # Allow double-close
|
184
193
|
end
|
185
194
|
e.dispatch @adapter
|
186
195
|
end
|
@@ -192,10 +201,11 @@ module Qpid::Proton
|
|
192
201
|
# or nil if there are no scheduled events
|
193
202
|
def process(now=Time.now)
|
194
203
|
read
|
204
|
+
dispatch
|
195
205
|
next_tick = tick(now)
|
196
|
-
dispatch
|
206
|
+
dispatch
|
197
207
|
write
|
198
|
-
dispatch
|
208
|
+
dispatch
|
199
209
|
return next_tick
|
200
210
|
end
|
201
211
|
end
|