qpid_proton 0.19.0 → 0.21.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 +76 -0
- data/examples/broker.rb +167 -0
- data/examples/client.rb +79 -0
- data/examples/direct_recv.rb +61 -0
- data/examples/direct_send.rb +67 -0
- data/examples/example_test.rb +109 -0
- data/examples/helloworld.rb +57 -0
- data/examples/server.rb +70 -0
- data/examples/simple_recv.rb +57 -0
- data/examples/simple_send.rb +63 -0
- data/examples/ssl_certs/README.txt +24 -0
- data/examples/ssl_certs/tclient-certificate.p12 +0 -0
- data/examples/ssl_certs/tclient-certificate.pem +19 -0
- data/examples/ssl_certs/tclient-full.p12 +0 -0
- data/examples/ssl_certs/tclient-private-key.pem +30 -0
- data/examples/ssl_certs/tserver-certificate.p12 +0 -0
- data/examples/ssl_certs/tserver-certificate.pem +19 -0
- data/examples/ssl_certs/tserver-full.p12 +0 -0
- data/examples/ssl_certs/tserver-private-key.pem +30 -0
- data/examples/ssl_send.rb +70 -0
- data/ext/cproton/cproton.c +105 -74
- data/lib/core/container.rb +2 -1
- data/lib/core/ssl_domain.rb +1 -1
- data/lib/core/uri.rb +15 -9
- data/lib/handler/messaging_adapter.rb +20 -5
- data/tests/old_examples/broker.rb +200 -0
- data/tests/old_examples/client.rb +81 -0
- data/tests/old_examples/direct_recv.rb +64 -0
- data/tests/old_examples/direct_send.rb +63 -0
- data/tests/old_examples/helloworld.rb +72 -0
- data/tests/old_examples/helloworld_direct.rb +73 -0
- data/tests/old_examples/lib/debugging.rb +25 -0
- data/tests/old_examples/lib/driver.rb +68 -0
- data/tests/old_examples/lib/qpid_examples.rb +26 -0
- data/tests/old_examples/lib/selectable.rb +119 -0
- data/tests/old_examples/lib/send_and_receive.rb +89 -0
- data/tests/old_examples/old_example_test.rb +107 -0
- data/tests/old_examples/recv.rb +23 -0
- data/tests/old_examples/send.rb +21 -0
- data/tests/old_examples/server.rb +75 -0
- data/tests/old_examples/simple_recv.rb +57 -0
- data/tests/old_examples/simple_send.rb +54 -0
- data/tests/test_connection_driver.rb +134 -0
- data/tests/test_container.rb +319 -0
- data/tests/test_data.rb +66 -0
- data/tests/test_delivery.rb +110 -0
- data/tests/test_interop.rb +131 -0
- data/tests/test_messaging_adapter.rb +223 -0
- data/tests/test_old_adapter.rb +228 -0
- data/tests/test_tools.rb +147 -0
- data/tests/test_uri.rb +83 -0
- metadata +49 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6495371bf4622d74d87cfd02d4e58323652572eb
|
4
|
+
data.tar.gz: 79af23eb910b3f38a1252530b318c45cafe6af54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52e822deb2d458caa735b88d0d6dc5d5e6377d16e836d744d80cdf847c1fcff89b1f22e2e178aa653411e2ffecefb7e314dfa3315f10034c77795cecf4146414
|
7
|
+
data.tar.gz: 4cea7fcfbdfadaf4c7fc1319303186c0282292134397c4d536eb46b9e8abccb719164b1b964b09a712aba95fab2193c00a502d1c39fbdace8b6ff636a594fc40
|
data/examples/README.md
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
## Simple Examples
|
2
|
+
|
3
|
+
### The Broker
|
4
|
+
|
5
|
+
The examples come with a sample broker which can be used by other examples and which also works as an example itself. For now we'll just start up the broker example and tell it to listen on port 8888:
|
6
|
+
|
7
|
+
````
|
8
|
+
$ ruby broker.rb amqp://:8888
|
9
|
+
Listening on amqp://:8888
|
10
|
+
````
|
11
|
+
|
12
|
+
This example broker will receive messages, create queues as needed, and deliver messages to endpoints.
|
13
|
+
|
14
|
+
### Hello World Using A Broker
|
15
|
+
|
16
|
+
Our first example creates an endpoint that sends messages to a queue to which it is subscribed. So it both sends and receives a message.
|
17
|
+
|
18
|
+
To start it, simply run:
|
19
|
+
|
20
|
+
```
|
21
|
+
$ ruby helloworld.rb //:8888
|
22
|
+
Hello world!
|
23
|
+
```
|
24
|
+
|
25
|
+
As you can see, the classic message was output by the example. Now let's take a look at what's going on under the covers.
|
26
|
+
|
27
|
+
#### Events When Talking To A Broker
|
28
|
+
|
29
|
+
The following events occur while **helloworld.rb** runs:
|
30
|
+
|
31
|
+
* **on_start** - Fired when the application is started.
|
32
|
+
* **on_sendable** - Fired when a message can be sent.
|
33
|
+
* **on_message** - Fired when a message is received.
|
34
|
+
|
35
|
+
## More Complex Examples
|
36
|
+
|
37
|
+
Now that we've covered the basics with the archetypical hello world app, let's look at some more interesting examples.
|
38
|
+
|
39
|
+
The following two client examples send and receive messages to an external broker or server:
|
40
|
+
|
41
|
+
* **simple_send.rb** - connect to a server, send messages to an address
|
42
|
+
* **simple_recv.rb** - connect to a server, receives messages from an address
|
43
|
+
|
44
|
+
For example: start `broker.rb`; run `simple_send.rb` to send messages to a
|
45
|
+
broker queue; then `simple_recv.rb` to receive the messages from the broker.
|
46
|
+
|
47
|
+
The following two examples are *servers* that can be connected to directly, without a broker:
|
48
|
+
|
49
|
+
* **direct_send.rb** - sends messages directly to a receiver and listens for responses itself, and
|
50
|
+
* **direct_recv.rb** - receives messages directly.
|
51
|
+
|
52
|
+
For example if you start `direct_recv.rb`, you can connect to it directly with
|
53
|
+
`simple_send.rb` vice-versa with `direct_send.rb` and `simple_recv.rb`
|
54
|
+
|
55
|
+
In this set of examples we see the following event occurring, in addition to what we've seen before:
|
56
|
+
|
57
|
+
* **on_transport_close** - Fired when the network transport is closed.
|
58
|
+
|
59
|
+
## Now About That Broker example
|
60
|
+
|
61
|
+
The **broker.rb** example application is a nice demonstration of doing something more interesting in Ruby with Proton.
|
62
|
+
|
63
|
+
The way the broker works is to listen to incoming connections, examine the components of the address for that connection, attach that connection to an exchange managing that address and then it sends any messages destined for that address to them.
|
64
|
+
|
65
|
+
The components of the broker example include:
|
66
|
+
* **Broker** - A class that extends the MessagingHandler class. It accepts incoming connections, manages subscribing them to exchanges, and transfers messages between them.
|
67
|
+
* **MessageQueue** - Distributes messages to subscriptions.
|
68
|
+
|
69
|
+
The Broker manages a map connecting a queue address to the instance of Exchange that holds references to the endpoints of interest.
|
70
|
+
|
71
|
+
The broker application demonstrates a new set of events:
|
72
|
+
|
73
|
+
* **on_link_open** - Fired when a remote link is opened. From this event the broker grabs the address and subscribes the link to an exchange for that address.
|
74
|
+
* **on_link_close** - Fired when a remote link is closed. From this event the broker grabs the address and unsubscribes the link from that exchange.
|
75
|
+
* **on_connection_close** - Fired when a remote connection is closed but the local end is still open.
|
76
|
+
* **on_transport_close** - Fired when the protocol transport has closed. The broker removes all links for the disconnected connection, avoiding workign with endpoints that are now gone.
|
data/examples/broker.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
require 'pathname'
|
23
|
+
|
24
|
+
class MessageQueue
|
25
|
+
|
26
|
+
def initialize(dynamic = false)
|
27
|
+
@dynamic = dynamic
|
28
|
+
@queue = Queue.new
|
29
|
+
@consumers = []
|
30
|
+
end
|
31
|
+
|
32
|
+
def subscribe(consumer)
|
33
|
+
@consumers << (consumer)
|
34
|
+
end
|
35
|
+
|
36
|
+
def unsubscribe(consumer)
|
37
|
+
if @consumers.include?(consumer)
|
38
|
+
@consumers.delete(consumer)
|
39
|
+
end
|
40
|
+
@consumers.empty? && (@dynamic || @queue.empty?)
|
41
|
+
end
|
42
|
+
|
43
|
+
def publish(message)
|
44
|
+
@queue << message
|
45
|
+
self.dispatch
|
46
|
+
end
|
47
|
+
|
48
|
+
def dispatch(consumer = nil)
|
49
|
+
if consumer
|
50
|
+
c = [consumer]
|
51
|
+
else
|
52
|
+
c = @consumers
|
53
|
+
end
|
54
|
+
|
55
|
+
while self.deliver_to(c) do
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def deliver_to(consumers)
|
60
|
+
result = false
|
61
|
+
consumers.each do |consumer|
|
62
|
+
if consumer.credit > 0 && !@queue.empty?
|
63
|
+
consumer.send(@queue.pop(true))
|
64
|
+
result = true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
return result
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
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
|
+
|
92
|
+
def on_container_start(container)
|
93
|
+
# Options for incoming connections, provide SSL configuration if we have it.
|
94
|
+
opts = {:ssl_domain => @ssl_domain} if @ssl_domain
|
95
|
+
@listener = container.listen(@url, Qpid::Proton::Listener::Handler.new(opts))
|
96
|
+
STDOUT.puts "Listening on #{@url.inspect}"; STDOUT.flush
|
97
|
+
end
|
98
|
+
|
99
|
+
def queue(address)
|
100
|
+
unless @queues.has_key?(address)
|
101
|
+
@queues[address] = MessageQueue.new
|
102
|
+
end
|
103
|
+
@queues[address]
|
104
|
+
end
|
105
|
+
|
106
|
+
def on_sender_open(sender)
|
107
|
+
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)
|
113
|
+
elsif sender.remote_source.address
|
114
|
+
sender.source.address = sender.remote_source.address
|
115
|
+
self.queue(sender.source.address).subscribe(sender)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def on_receiver_open(receiver)
|
120
|
+
if receiver.remote_target.address
|
121
|
+
receiver.target.address = receiver.remote_target.address
|
122
|
+
end
|
123
|
+
end
|
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
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def on_sender_close(sender)
|
134
|
+
self.unsubscribe(sender)
|
135
|
+
end
|
136
|
+
|
137
|
+
def on_connection_close(connection)
|
138
|
+
self.remove_stale_consumers(connection)
|
139
|
+
end
|
140
|
+
|
141
|
+
def on_transport_close(transport)
|
142
|
+
self.remove_stale_consumers(transport.connection)
|
143
|
+
end
|
144
|
+
|
145
|
+
def remove_stale_consumers(connection)
|
146
|
+
connection.each_sender { |s| unsubscribe(s) }
|
147
|
+
end
|
148
|
+
|
149
|
+
def on_sendable(sender)
|
150
|
+
q = self.queue(sender.source.address)
|
151
|
+
q.dispatch(sender)
|
152
|
+
end
|
153
|
+
|
154
|
+
def on_message(delivery, message)
|
155
|
+
q = self.queue(delivery.link.target.address)
|
156
|
+
q.publish(message)
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
if ARGV.size != 1
|
162
|
+
STDERR.puts "Usage: #{__FILE__} URL
|
163
|
+
Start an example broker listening on URL"
|
164
|
+
return 1
|
165
|
+
end
|
166
|
+
url, = ARGV
|
167
|
+
Qpid::Proton::Container.new(Broker.new(url)).run
|
data/examples/client.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
|
23
|
+
class Client < Qpid::Proton::MessagingHandler
|
24
|
+
|
25
|
+
def initialize(url, address, requests)
|
26
|
+
super()
|
27
|
+
@url = url
|
28
|
+
@address = address
|
29
|
+
@requests = requests
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_container_start(container)
|
33
|
+
c = container.connect(@url)
|
34
|
+
@sender = c.open_sender(@address)
|
35
|
+
@receiver = c.open_receiver({:dynamic => true})
|
36
|
+
end
|
37
|
+
|
38
|
+
def next_request
|
39
|
+
if @receiver.remote_source.address
|
40
|
+
req = Qpid::Proton::Message.new
|
41
|
+
req.reply_to = @receiver.remote_source.address
|
42
|
+
req.body = @requests.first
|
43
|
+
puts "-> #{req.body}"
|
44
|
+
@sender.send(req)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_receiver_open(receiver)
|
49
|
+
next_request
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_message(delivery, message)
|
53
|
+
puts "<- #{message.body}"
|
54
|
+
@requests.delete_at(0)
|
55
|
+
if !@requests.empty?
|
56
|
+
next_request
|
57
|
+
else
|
58
|
+
delivery.connection.close
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_transport_error(transport)
|
63
|
+
raise "Connection error: #{transport.condition}"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
REQUESTS = ["Twas brillig, and the slithy toves",
|
69
|
+
"Did gire and gymble in the wabe.",
|
70
|
+
"All mimsy were the borogroves,",
|
71
|
+
"And the mome raths outgrabe."]
|
72
|
+
|
73
|
+
if ARGV.size != 2
|
74
|
+
STDERR.puts "Usage: #{__FILE__} URL ADDRESS
|
75
|
+
Connect to URL and send messages to ADDRESS"
|
76
|
+
return 1
|
77
|
+
end
|
78
|
+
url, address = ARGV
|
79
|
+
Qpid::Proton::Container.new(Client.new(url, address, REQUESTS)).run
|
@@ -0,0 +1,61 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
|
23
|
+
class DirectReceive < Qpid::Proton::MessagingHandler
|
24
|
+
|
25
|
+
def initialize(url, address, count)
|
26
|
+
super()
|
27
|
+
@url = url
|
28
|
+
@address = address
|
29
|
+
@expected = count
|
30
|
+
@received = 0
|
31
|
+
end
|
32
|
+
|
33
|
+
class ListenOnce < Qpid::Proton::Listener::Handler
|
34
|
+
def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
|
35
|
+
def on_accept(l) l.close; end
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_container_start(container)
|
39
|
+
container.listen(@url, ListenOnce.new)
|
40
|
+
end
|
41
|
+
|
42
|
+
def on_message(delivery, message)
|
43
|
+
if @expected.zero? || (@received < @expected)
|
44
|
+
puts "Received: #{message.body}"
|
45
|
+
@received = @received + 1
|
46
|
+
if @received == @expected
|
47
|
+
delivery.connection.close
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
unless (2..3).include? ARGV.size
|
54
|
+
STDERR.puts "Usage: #{__FILE__} URL ADDRESS [COUNT]
|
55
|
+
Listen on URL and receive COUNT messages from ADDRESS"
|
56
|
+
return 1
|
57
|
+
end
|
58
|
+
url, address, count = ARGV
|
59
|
+
count = Integer(count || 10)
|
60
|
+
Qpid::Proton::Container.new(DirectReceive.new(url, address, count)).run
|
61
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
|
23
|
+
class DirectSend < Qpid::Proton::MessagingHandler
|
24
|
+
|
25
|
+
def initialize(url, address, expected)
|
26
|
+
super()
|
27
|
+
@url = url
|
28
|
+
@address = address
|
29
|
+
@sent = 0
|
30
|
+
@confirmed = 0
|
31
|
+
@expected = expected
|
32
|
+
end
|
33
|
+
|
34
|
+
class ListenOnce < Qpid::Proton::Listener::Handler
|
35
|
+
def on_open(l) STDOUT.puts "Listening\n"; STDOUT.flush; end
|
36
|
+
def on_accept(l) l.close; end
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_container_start(container)
|
40
|
+
container.listen(@url, ListenOnce.new)
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_sendable(sender)
|
44
|
+
while sender.credit > 0 && @sent < @expected
|
45
|
+
msg = Qpid::Proton::Message.new("sequence #{@sent}", { :id => @sent } )
|
46
|
+
sender.send(msg)
|
47
|
+
@sent = @sent + 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def on_tracker_accept(tracker)
|
52
|
+
@confirmed = @confirmed + 1
|
53
|
+
if @confirmed == @expected
|
54
|
+
puts "All #{@expected} messages confirmed!"
|
55
|
+
tracker.connection.close
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
unless (2..3).include? ARGV.size
|
61
|
+
STDERR.puts "Usage: #{__FILE__} URL ADDRESS [COUNT]
|
62
|
+
Listen on URL and send COUNT messages to ADDRESS"
|
63
|
+
return 1
|
64
|
+
end
|
65
|
+
url, address, count = ARGV
|
66
|
+
count = Integer(count || 10)
|
67
|
+
Qpid::Proton::Container.new(DirectSend.new(url, address, count)).run
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
5
|
+
# distributed with this work for additional information
|
6
|
+
# regarding copyright ownership. The ASF licenses this file
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance
|
9
|
+
# with the License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
14
|
+
# software distributed under the License is distributed on an
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
16
|
+
# KIND, either express or implied. See the License for the
|
17
|
+
# specific language governing permissions and limitations
|
18
|
+
# under the License.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'minitest/autorun'
|
22
|
+
require 'qpid_proton'
|
23
|
+
require 'socket'
|
24
|
+
require 'rbconfig'
|
25
|
+
|
26
|
+
begin
|
27
|
+
MiniTest::Test
|
28
|
+
rescue NameError # For older versions of MiniTest
|
29
|
+
MiniTest::Test = MiniTest::Unit::TestCase
|
30
|
+
end
|
31
|
+
|
32
|
+
# URL with an unused port
|
33
|
+
def test_url()
|
34
|
+
"amqp://:#{TCPServer.open(0) { |s| s.addr[1] }}"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class ExampleTest < MiniTest::Test
|
39
|
+
|
40
|
+
def run_script(*args)
|
41
|
+
return IO.popen([ RbConfig.ruby ] + args.map { |a| a.to_s })
|
42
|
+
end
|
43
|
+
|
44
|
+
def assert_output(want, *args)
|
45
|
+
assert_equal(want.strip, run_script(*args).read.strip)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_helloworld
|
49
|
+
assert_output("Hello world!", "helloworld.rb", $url, __method__)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_client_server
|
53
|
+
want = <<EOS
|
54
|
+
-> Twas brillig, and the slithy toves
|
55
|
+
<- TWAS BRILLIG, AND THE SLITHY TOVES
|
56
|
+
-> Did gire and gymble in the wabe.
|
57
|
+
<- DID GIRE AND GYMBLE IN THE WABE.
|
58
|
+
-> All mimsy were the borogroves,
|
59
|
+
<- ALL MIMSY WERE THE BOROGROVES,
|
60
|
+
-> And the mome raths outgrabe.
|
61
|
+
<- AND THE MOME RATHS OUTGRABE.
|
62
|
+
EOS
|
63
|
+
server = run_script("server.rb", $url, __method__)
|
64
|
+
assert_output(want.strip, "client.rb", $url, __method__)
|
65
|
+
ensure
|
66
|
+
Process.kill :TERM, server.pid if server
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_send_recv
|
70
|
+
assert_output("All 10 messages confirmed!", "simple_send.rb", $url, __method__)
|
71
|
+
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
72
|
+
assert_output(want.strip, "simple_recv.rb", $url, __method__)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_ssl_send_recv
|
76
|
+
out = run_script("ssl_send.rb", $url, __method__).read.strip
|
77
|
+
assert_match(/Connection secured with "...*\"\nAll 10 messages confirmed!/, out)
|
78
|
+
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
79
|
+
assert_output(want.strip, "simple_recv.rb", $url, __method__)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_direct_recv
|
83
|
+
url = test_url
|
84
|
+
p = run_script("direct_recv.rb", url, __method__)
|
85
|
+
p.readline # Wait till ready
|
86
|
+
assert_output("All 10 messages confirmed!", "simple_send.rb", url, __method__)
|
87
|
+
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
88
|
+
assert_equal(want.strip, p.read.strip)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_direct_send
|
92
|
+
url = test_url
|
93
|
+
p = run_script("direct_send.rb", url, __method__)
|
94
|
+
p.readline # Wait till ready
|
95
|
+
want = (0..9).reduce("") { |x,y| x << "Received: sequence #{y}\n" }
|
96
|
+
assert_output(want.strip, "simple_recv.rb", url, __method__)
|
97
|
+
assert_equal("All 10 messages confirmed!", p.read.strip)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Start the broker before all tests.
|
102
|
+
$url = test_url
|
103
|
+
$broker = IO.popen([RbConfig.ruby, 'broker.rb', $url])
|
104
|
+
$broker.readline
|
105
|
+
|
106
|
+
# Kill the broker after all tests
|
107
|
+
MiniTest.after_run do
|
108
|
+
Process.kill(:TERM, $broker.pid) if $broker
|
109
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
|
23
|
+
class HelloWorld < Qpid::Proton::MessagingHandler
|
24
|
+
|
25
|
+
def initialize(url, address)
|
26
|
+
super()
|
27
|
+
@url, @address = url, address
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_container_start(container)
|
31
|
+
conn = container.connect(@url)
|
32
|
+
conn.open_sender(@address)
|
33
|
+
conn.open_receiver(@address)
|
34
|
+
end
|
35
|
+
|
36
|
+
def on_sendable(sender)
|
37
|
+
sender.send(Qpid::Proton::Message.new("Hello world!"))
|
38
|
+
sender.close
|
39
|
+
end
|
40
|
+
|
41
|
+
def on_message(delivery, message)
|
42
|
+
puts message.body
|
43
|
+
delivery.connection.close
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_transport_error(transport)
|
47
|
+
raise "Connection error: #{transport.condition}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if ARGV.size != 2
|
52
|
+
STDERR.puts "Usage: #{__FILE__} URL ADDRESS
|
53
|
+
Connect to URL, send a message to ADDRESS and receive it back"
|
54
|
+
return 1
|
55
|
+
end
|
56
|
+
url, address = ARGV
|
57
|
+
Qpid::Proton::Container.new(HelloWorld.new(url, address)).run
|
data/examples/server.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#--
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing,
|
13
|
+
# software distributed under the License is distributed on an
|
14
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
15
|
+
# KIND, either express or implied. See the License for the
|
16
|
+
# specific language governing permissions and limitations
|
17
|
+
# under the License.
|
18
|
+
#++
|
19
|
+
|
20
|
+
require 'qpid_proton'
|
21
|
+
require 'optparse'
|
22
|
+
|
23
|
+
class Server < Qpid::Proton::MessagingHandler
|
24
|
+
|
25
|
+
def initialize(url, address)
|
26
|
+
super()
|
27
|
+
@url = url
|
28
|
+
@address = address
|
29
|
+
@senders = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_container_start(container)
|
33
|
+
c = container.connect(@url)
|
34
|
+
c.open_receiver(@address)
|
35
|
+
@relay = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def on_connection_open(connection)
|
39
|
+
if connection.offered_capabilities &&
|
40
|
+
connection.offered_capabilities.contain?("ANONYMOUS-RELAY")
|
41
|
+
@relay = connection.open_sender({:target => nil})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def on_message(delivery, message)
|
46
|
+
return unless message.reply_to # Not a request message
|
47
|
+
puts "<- #{message.body}"
|
48
|
+
unless (sender = @relay)
|
49
|
+
sender = (@senders[message.reply_to] ||= delivery.connection.open_sender(message.reply_to))
|
50
|
+
end
|
51
|
+
reply = Qpid::Proton::Message.new
|
52
|
+
reply.address = message.reply_to
|
53
|
+
reply.body = message.body.upcase
|
54
|
+
puts "-> #{reply.body}"
|
55
|
+
reply.correlation_id = message.correlation_id
|
56
|
+
sender.send(reply)
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_transport_error(transport)
|
60
|
+
raise "Connection error: #{transport.condition}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if ARGV.size != 2
|
65
|
+
STDERR.puts "Usage: #{__FILE__} URL ADDRESS
|
66
|
+
Server listening on URL, reply to messages to ADDRESS"
|
67
|
+
return 1
|
68
|
+
end
|
69
|
+
url, address = ARGV
|
70
|
+
Qpid::Proton::Container.new(Server.new(url, address)).run
|