cztop 1.1.1 → 1.2.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/CHANGES.md +16 -0
- data/README.md +61 -56
- data/cztop.gemspec +2 -4
- data/lib/cztop/actor.rb +26 -22
- data/lib/cztop/certificate.rb +19 -11
- data/lib/cztop/message.rb +5 -1
- data/lib/cztop/send_receive_methods.rb +106 -2
- data/lib/cztop/socket/types.rb +18 -0
- data/lib/cztop/version.rb +1 -1
- data/lib/cztop/zsock_options.rb +16 -2
- metadata +3 -66
- data/.github/workflows/coverage.yml +0 -20
- data/.github/workflows/draft_api.yml +0 -27
- data/.github/workflows/stable_api.yml +0 -26
- data/.gitignore +0 -10
- data/.projections.json +0 -4
- data/.rspec +0 -2
- data/.rubocop.yml +0 -175
- data/.yardopts +0 -1
- data/Rakefile +0 -6
- data/ci/install-libczmq +0 -22
- data/ci/install-libzmq +0 -22
- data/examples/async/.gitignore +0 -1
- data/examples/async/Gemfile +0 -5
- data/examples/async/README.md +0 -1
- data/examples/async/async.rb +0 -35
- data/examples/ruby_actor/actor.rb +0 -100
- data/examples/simple_req_rep/rep.rb +0 -12
- data/examples/simple_req_rep/req.rb +0 -35
- data/examples/taxi_system/.gitignore +0 -2
- data/examples/taxi_system/Makefile +0 -2
- data/examples/taxi_system/README.gsl +0 -115
- data/examples/taxi_system/README.md +0 -276
- data/examples/taxi_system/broker.rb +0 -97
- data/examples/taxi_system/client.rb +0 -34
- data/examples/taxi_system/generate_keys.rb +0 -24
- data/examples/taxi_system/start_broker.sh +0 -2
- data/examples/taxi_system/start_clients.sh +0 -11
- data/examples/weather_pub_sub/pub.rb +0 -24
- data/examples/weather_pub_sub/sub.rb +0 -33
- data/lib/cztop/async.rb +0 -124
- data/perf/README.md +0 -80
- data/perf/inproc_lat.rb +0 -49
- data/perf/inproc_thru.rb +0 -42
- data/perf/local_lat.rb +0 -35
- data/perf/remote_lat.rb +0 -26
@@ -1,115 +0,0 @@
|
|
1
|
-
.output "README.md"
|
2
|
-
.template 1
|
3
|
-
# Taxi System
|
4
|
-
|
5
|
-
Suppose you're running a taxi company. You have a set of taxi drivers
|
6
|
-
working for you. You'd like to connect them to your central server, so they're
|
7
|
-
ready to get service requests from customers who'd like to get picked up by a
|
8
|
-
taxi from some place X. As soon as a customer sends his service request, the
|
9
|
-
central server will send the closest taxi nearby that's available to the
|
10
|
-
customer.
|
11
|
-
|
12
|
-
Of course you want the communication between the broker and the taxi drivers to
|
13
|
-
be secure, meaning you want encryption and authentication.
|
14
|
-
|
15
|
-
You also want ping-pong heartbeating, as you want to have confidence you can
|
16
|
-
get in touch with your taxi drivers any time you want. And if a service
|
17
|
-
request can't be delivered to a particular taxi driver, you wanna know
|
18
|
-
immediately.
|
19
|
-
|
20
|
-
This solution is implemented using CLIENT/SERVER sockets and the CURVE
|
21
|
-
security mechanism.
|
22
|
-
|
23
|
-
## Broker
|
24
|
-
|
25
|
-
Here's a possible implementation of the broker. What you'll have to provide
|
26
|
-
are the environment variables `BROKER_ADDRESS` (the public TCP endpoint),
|
27
|
-
`BROKER_CERT` (path to the broker's secret+public keys), and `CLIENT_CERTS`
|
28
|
-
(directory to taxi drivers' certificates, public keys only).
|
29
|
-
|
30
|
-
After the start, the broker will just start listening for the drivers (CLIENT
|
31
|
-
sockets) to connect. After a driver has connected, authenticated, and sent its
|
32
|
-
`HELLO` message, the broker answers with a `WELCOME` or `WELCOMEBACK` message,
|
33
|
-
depending if the driver was connected before (it might have reconnected and
|
34
|
-
been assigned a new routing ID).
|
35
|
-
|
36
|
-
The broker will present you with a Pry shell. Right before starting the shell,
|
37
|
-
there's a small usage information, but it's not very well visible due to Pry's
|
38
|
-
noisy start. It's simple, though. Inside that shell, you can use the method
|
39
|
-
`#send_command(driver, command)`. Example:
|
40
|
-
|
41
|
-
```
|
42
|
-
pry> send_command("driver1", "foobar")
|
43
|
-
```
|
44
|
-
|
45
|
-
Depending on whether the driver is connected, it'll send the message or report
|
46
|
-
that it cannot do so.
|
47
|
-
|
48
|
-
```ruby
|
49
|
-
.literal from "broker.rb"
|
50
|
-
```
|
51
|
-
|
52
|
-
## Client
|
53
|
-
|
54
|
-
Here you have to provide the environment variables `BROKER_ADDRESS` (ditto),
|
55
|
-
`BROKER_CERT` (public key only), `CLIENT_CERT` (taxi driver's certificate
|
56
|
-
containing the secret+public keys).
|
57
|
-
|
58
|
-
After connecting to the broker and completing the security handshake, the
|
59
|
-
client sends a `HELLO` message, after which it immediately expects some answer
|
60
|
-
from the broker (see above). After that, it just listens for messages (service
|
61
|
-
requests) and prints them into the terminal.
|
62
|
-
|
63
|
-
```ruby
|
64
|
-
.literal from "client.rb"
|
65
|
-
```
|
66
|
-
|
67
|
-
## How to run the example
|
68
|
-
|
69
|
-
### Generate broker's and drivers' keys
|
70
|
-
|
71
|
-
Here's a simple script that'll create the broker's certificate and the taxi
|
72
|
-
drivers' certificates. There are also public key only files so a minimum amount
|
73
|
-
of information can be made available on one system, e.g. a taxi driver's system
|
74
|
-
must not know the broker's secret key. Also, the broker doesn't necessarily
|
75
|
-
need to know the clients' secret keys just to authenticate them.
|
76
|
-
|
77
|
-
```ruby
|
78
|
-
.literal from "generate_keys.rb"
|
79
|
-
|
80
|
-
```
|
81
|
-
Run it as follows:
|
82
|
-
|
83
|
-
```
|
84
|
-
\./generate_keys.rb
|
85
|
-
```
|
86
|
-
|
87
|
-
### Start broker
|
88
|
-
|
89
|
-
Run this:
|
90
|
-
|
91
|
-
```
|
92
|
-
\./start_broker.sh
|
93
|
-
```
|
94
|
-
|
95
|
-
which will execute the following script:
|
96
|
-
|
97
|
-
```sh
|
98
|
-
.literal from "start_broker.sh"
|
99
|
-
```
|
100
|
-
|
101
|
-
### Start driver software instances
|
102
|
-
|
103
|
-
Run this in another terminal:
|
104
|
-
|
105
|
-
```
|
106
|
-
\./start_clients.sh
|
107
|
-
```
|
108
|
-
|
109
|
-
which will execute the following script:
|
110
|
-
|
111
|
-
```sh
|
112
|
-
.literal from "start_clients.sh"
|
113
|
-
```
|
114
|
-
|
115
|
-
.endtemplate
|
@@ -1,276 +0,0 @@
|
|
1
|
-
# Taxi System
|
2
|
-
|
3
|
-
Suppose you're running a taxi company. You have a set of taxi drivers
|
4
|
-
working for you. You'd like to connect them to your central server, so they're
|
5
|
-
ready to get service requests from customers who'd like to get picked up by a
|
6
|
-
taxi from some place X. As soon as a customer sends his service request, the
|
7
|
-
central server will send the closest taxi nearby that's available to the
|
8
|
-
customer.
|
9
|
-
|
10
|
-
Of course you want the communication between the broker and the taxi drivers to
|
11
|
-
be secure, meaning you want encryption and authentication.
|
12
|
-
|
13
|
-
You also want ping-pong heartbeating, as you want to have confidence you can
|
14
|
-
get in touch with your taxi drivers any time you want. And if a service
|
15
|
-
request can't be delivered to a particular taxi driver, you wanna know
|
16
|
-
immediately.
|
17
|
-
|
18
|
-
This solution is implemented using CLIENT/SERVER sockets and the CURVE
|
19
|
-
security mechanism.
|
20
|
-
|
21
|
-
## Broker
|
22
|
-
|
23
|
-
Here's a possible implementation of the broker. What you'll have to provide
|
24
|
-
are the environment variables `BROKER_ADDRESS` (the public TCP endpoint),
|
25
|
-
`BROKER_CERT` (path to the broker's secret+public keys), and `CLIENT_CERTS`
|
26
|
-
(directory to taxi drivers' certificates, public keys only).
|
27
|
-
|
28
|
-
After the start, the broker will just start listening for the drivers (CLIENT
|
29
|
-
sockets) to connect. After a driver has connected, authenticated, and sent its
|
30
|
-
`HELLO` message, the broker answers with a `WELCOME` or `WELCOMEBACK` message,
|
31
|
-
depending if the driver was connected before (it might have reconnected and
|
32
|
-
been assigned a new routing ID).
|
33
|
-
|
34
|
-
The broker will present you with a Pry shell. Right before starting the shell,
|
35
|
-
there's a small usage information, but it's not very well visible due to Pry's
|
36
|
-
noisy start. It's simple, though. Inside that shell, you can use the method
|
37
|
-
`#send_command(driver, command)`. Example:
|
38
|
-
|
39
|
-
```
|
40
|
-
pry> send_command("driver1", "foobar")
|
41
|
-
```
|
42
|
-
|
43
|
-
Depending on whether the driver is connected, it'll send the message or report
|
44
|
-
that it cannot do so.
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
#!/usr/bin/env ruby
|
48
|
-
require 'pry'
|
49
|
-
require 'pathname'
|
50
|
-
require 'cztop'
|
51
|
-
|
52
|
-
endpoint = ENV["BROKER_ADDRESS"]
|
53
|
-
broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
|
54
|
-
client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
|
55
|
-
drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
|
56
|
-
|
57
|
-
authenticator = CZTop::Authenticator.new
|
58
|
-
authenticator.verbose!
|
59
|
-
authenticator.curve(client_certs)
|
60
|
-
|
61
|
-
# create and bind socket
|
62
|
-
@socket = CZTop::Socket::SERVER.new
|
63
|
-
@socket.CURVE_server!(broker_cert)
|
64
|
-
#socket.options.sndtimeo = 0
|
65
|
-
@socket.options.heartbeat_ivl = 100#ms
|
66
|
-
@socket.options.heartbeat_timeout = 300#ms
|
67
|
-
@socket.bind(endpoint)
|
68
|
-
|
69
|
-
puts ">>> Socket bound to #{endpoint.inspect}"
|
70
|
-
|
71
|
-
# get and print socket events
|
72
|
-
Thread.new do
|
73
|
-
monitor = CZTop::Monitor.new(@socket)
|
74
|
-
monitor.listen("ALL")
|
75
|
-
monitor.start
|
76
|
-
while msg = monitor.next
|
77
|
-
puts ">>> Socket event: #{msg.inspect}"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
# receive messages from drivers
|
82
|
-
@driver_map = {} # driver name => routing ID
|
83
|
-
Thread.new do
|
84
|
-
|
85
|
-
# CZTop::Loop (zloop) doesn't work with SERVER sockets :(
|
86
|
-
poller = CZTop::Poller.new(@socket)
|
87
|
-
while true
|
88
|
-
puts "waiting for socket to become readable ..."
|
89
|
-
socket = poller.wait
|
90
|
-
puts "socket is readable"
|
91
|
-
msg = socket.receive
|
92
|
-
puts "got message"
|
93
|
-
command, argument = msg[0].split("\t", 2)
|
94
|
-
|
95
|
-
case command
|
96
|
-
when "HELLO"
|
97
|
-
driver = argument
|
98
|
-
puts ">>> Driver #{driver.inspect} has connected."
|
99
|
-
welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
|
100
|
-
|
101
|
-
# remember driver's assigned message routing ID
|
102
|
-
@driver_map[driver] = msg.routing_id
|
103
|
-
|
104
|
-
# send WELCOME or WELCOMEBACK
|
105
|
-
rep = CZTop::Message.new(welcome)
|
106
|
-
rep.routing_id = @driver_map[driver]
|
107
|
-
socket << rep
|
108
|
-
puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def send_command(driver, command)
|
114
|
-
if command.nil? || command.empty?
|
115
|
-
puts "!!! No message given."
|
116
|
-
return
|
117
|
-
end
|
118
|
-
if not @driver_map.key?(driver)
|
119
|
-
puts "!!! Driver #{driver.inspect} has never connected."
|
120
|
-
return
|
121
|
-
end
|
122
|
-
puts ">>> Sending message to #{driver.inspect} ..."
|
123
|
-
msg = CZTop::Message.new(command)
|
124
|
-
msg.routing_id = @driver_map[driver]
|
125
|
-
@socket << msg
|
126
|
-
rescue SocketError
|
127
|
-
puts "!!! Driver #{driver.inspect} isn't connected anymore."
|
128
|
-
end
|
129
|
-
|
130
|
-
##
|
131
|
-
# REPL for user to play
|
132
|
-
#
|
133
|
-
puts <<MSG
|
134
|
-
You can now send messages to the drivers yourself.
|
135
|
-
The use the method #send_command, like this:
|
136
|
-
|
137
|
-
pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
|
138
|
-
|
139
|
-
This should show something like this in the client.rb terminal:
|
140
|
-
|
141
|
-
03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
|
142
|
-
MSG
|
143
|
-
|
144
|
-
binding.pry
|
145
|
-
```
|
146
|
-
|
147
|
-
## Client
|
148
|
-
|
149
|
-
Here you have to provide the environment variables `BROKER_ADDRESS` (ditto),
|
150
|
-
`BROKER_CERT` (public key only), `CLIENT_CERT` (taxi driver's certificate
|
151
|
-
containing the secret+public keys).
|
152
|
-
|
153
|
-
After connecting to the broker and completing the security handshake, the
|
154
|
-
client sends a `HELLO` message, after which it immediately expects some answer
|
155
|
-
from the broker (see above). After that, it just listens for messages (service
|
156
|
-
requests) and prints them into the terminal.
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
#!/usr/bin/env ruby
|
160
|
-
require 'cztop'
|
161
|
-
|
162
|
-
endpoint = ENV["BROKER_ADDRESS"]
|
163
|
-
broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
|
164
|
-
client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
|
165
|
-
|
166
|
-
@socket = CZTop::Socket::CLIENT.new
|
167
|
-
@socket.CURVE_client!(client_cert, broker_cert)
|
168
|
-
@socket.options.sndtimeo = 2000#ms
|
169
|
-
|
170
|
-
# heartbeating:
|
171
|
-
# * send PING every 100ms
|
172
|
-
# * close connection after 300ms of no life sign from broker
|
173
|
-
# * tell broker to close connection after 500ms of no life sign from client
|
174
|
-
@socket.options.heartbeat_ivl = 100#ms
|
175
|
-
@socket.options.heartbeat_timeout = 300#ms
|
176
|
-
@socket.options.heartbeat_ttl = 500#ms
|
177
|
-
|
178
|
-
@socket.connect(endpoint)
|
179
|
-
puts ">>> connected."
|
180
|
-
|
181
|
-
# tell broker who we are
|
182
|
-
@socket << "HELLO\t#{client_cert["driver_name"]}"
|
183
|
-
puts ">>> sent HELLO."
|
184
|
-
welcome = @socket.receive[0]
|
185
|
-
puts ">>> got #{welcome}."
|
186
|
-
|
187
|
-
poller = CZTop::Poller.new(@socket)
|
188
|
-
while true
|
189
|
-
socket = poller.wait
|
190
|
-
message = socket.receive
|
191
|
-
puts ">>> received message: #{message[0].inspect}"
|
192
|
-
end
|
193
|
-
```
|
194
|
-
|
195
|
-
## How to run the example
|
196
|
-
|
197
|
-
### Generate broker's and drivers' keys
|
198
|
-
|
199
|
-
Here's a simple script that'll create the broker's certificate and the taxi
|
200
|
-
drivers' certificates. There are also public key only files so a minimum amount
|
201
|
-
of information can be made available on one system, e.g. a taxi driver's system
|
202
|
-
must not know the broker's secret key. Also, the broker doesn't necessarily
|
203
|
-
need to know the clients' secret keys just to authenticate them.
|
204
|
-
|
205
|
-
```ruby
|
206
|
-
#!/usr/bin/env ruby
|
207
|
-
require 'cztop'
|
208
|
-
require 'fileutils'
|
209
|
-
FileUtils.cd(File.dirname(__FILE__))
|
210
|
-
FileUtils.mkdir "public_keys"
|
211
|
-
FileUtils.mkdir "public_keys/drivers"
|
212
|
-
FileUtils.mkdir "secret_keys"
|
213
|
-
FileUtils.mkdir "secret_keys/drivers"
|
214
|
-
#FileUtils.mkdir "certs/drivers"
|
215
|
-
|
216
|
-
DRIVERS = %w[ driver1 driver2 driver3 ]
|
217
|
-
|
218
|
-
# broker certificate
|
219
|
-
cert = CZTop::Certificate.new
|
220
|
-
cert.save("secret_keys/broker")
|
221
|
-
cert.save_public("public_keys/broker")
|
222
|
-
|
223
|
-
# driver certificates
|
224
|
-
DRIVERS.each do |driver_name|
|
225
|
-
cert = CZTop::Certificate.new
|
226
|
-
cert["driver_name"] = driver_name
|
227
|
-
cert.save "secret_keys/drivers/#{driver_name}"
|
228
|
-
cert.save_public "public_keys/drivers/#{driver_name}"
|
229
|
-
end
|
230
|
-
|
231
|
-
```
|
232
|
-
Run it as follows:
|
233
|
-
|
234
|
-
```
|
235
|
-
./generate_keys.rb
|
236
|
-
```
|
237
|
-
|
238
|
-
### Start broker
|
239
|
-
|
240
|
-
Run this:
|
241
|
-
|
242
|
-
```
|
243
|
-
./start_broker.sh
|
244
|
-
```
|
245
|
-
|
246
|
-
which will execute the following script:
|
247
|
-
|
248
|
-
```sh
|
249
|
-
#!/bin/sh -x
|
250
|
-
BROKER_ADDRESS=tcp://127.0.0.1:4455 BROKER_CERT=secret_keys/broker CLIENT_CERTS=public_keys/drivers ./broker.rb
|
251
|
-
```
|
252
|
-
|
253
|
-
### Start driver software instances
|
254
|
-
|
255
|
-
Run this in another terminal:
|
256
|
-
|
257
|
-
```
|
258
|
-
./start_clients.sh
|
259
|
-
```
|
260
|
-
|
261
|
-
which will execute the following script:
|
262
|
-
|
263
|
-
```sh
|
264
|
-
#!/bin/sh -x
|
265
|
-
export BROKER_ADDRESS=tcp://127.0.0.1:4455
|
266
|
-
export BROKER_CERT=public_keys/broker
|
267
|
-
CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
|
268
|
-
CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
|
269
|
-
CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
|
270
|
-
jobs
|
271
|
-
jobs -p
|
272
|
-
jobs -l
|
273
|
-
trap 'kill $(jobs -p)' EXIT
|
274
|
-
wait
|
275
|
-
```
|
276
|
-
|
@@ -1,97 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'pry'
|
3
|
-
require 'pathname'
|
4
|
-
require 'cztop'
|
5
|
-
|
6
|
-
endpoint = ENV["BROKER_ADDRESS"]
|
7
|
-
broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
|
8
|
-
client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
|
9
|
-
drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
|
10
|
-
|
11
|
-
authenticator = CZTop::Authenticator.new
|
12
|
-
authenticator.verbose!
|
13
|
-
authenticator.curve(client_certs)
|
14
|
-
|
15
|
-
# create and bind socket
|
16
|
-
@socket = CZTop::Socket::SERVER.new
|
17
|
-
@socket.CURVE_server!(broker_cert)
|
18
|
-
#socket.options.sndtimeo = 0
|
19
|
-
@socket.options.heartbeat_ivl = 100#ms
|
20
|
-
@socket.options.heartbeat_timeout = 300#ms
|
21
|
-
@socket.bind(endpoint)
|
22
|
-
|
23
|
-
puts ">>> Socket bound to #{endpoint.inspect}"
|
24
|
-
|
25
|
-
# get and print socket events
|
26
|
-
Thread.new do
|
27
|
-
monitor = CZTop::Monitor.new(@socket)
|
28
|
-
monitor.listen("ALL")
|
29
|
-
monitor.start
|
30
|
-
while msg = monitor.next
|
31
|
-
puts ">>> Socket event: #{msg.inspect}"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# receive messages from drivers
|
36
|
-
@driver_map = {} # driver name => routing ID
|
37
|
-
Thread.new do
|
38
|
-
|
39
|
-
poller = CZTop::Poller.new(@socket)
|
40
|
-
while true
|
41
|
-
puts "waiting for socket to become readable ..."
|
42
|
-
socket = poller.simple_wait
|
43
|
-
puts "socket is readable"
|
44
|
-
msg = socket.receive
|
45
|
-
puts "got message"
|
46
|
-
command, argument = msg[0].split("\t", 2)
|
47
|
-
|
48
|
-
case command
|
49
|
-
when "HELLO"
|
50
|
-
driver = argument
|
51
|
-
puts ">>> Driver #{driver.inspect} has connected."
|
52
|
-
welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
|
53
|
-
|
54
|
-
# remember driver's assigned message routing ID
|
55
|
-
@driver_map[driver] = msg.routing_id
|
56
|
-
|
57
|
-
# send WELCOME or WELCOMEBACK
|
58
|
-
rep = CZTop::Message.new(welcome)
|
59
|
-
rep.routing_id = @driver_map[driver]
|
60
|
-
socket << rep
|
61
|
-
puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def send_command(driver, command)
|
67
|
-
if command.nil? || command.empty?
|
68
|
-
puts "!!! No message given."
|
69
|
-
return
|
70
|
-
end
|
71
|
-
if not @driver_map.key?(driver)
|
72
|
-
puts "!!! Driver #{driver.inspect} has never connected."
|
73
|
-
return
|
74
|
-
end
|
75
|
-
puts ">>> Sending message to #{driver.inspect} ..."
|
76
|
-
msg = CZTop::Message.new(command)
|
77
|
-
msg.routing_id = @driver_map[driver]
|
78
|
-
@socket << msg
|
79
|
-
rescue SocketError
|
80
|
-
puts "!!! Driver #{driver.inspect} isn't connected anymore."
|
81
|
-
end
|
82
|
-
|
83
|
-
##
|
84
|
-
# REPL for user to play
|
85
|
-
#
|
86
|
-
puts <<MSG
|
87
|
-
You can now send messages to the drivers yourself.
|
88
|
-
The use the method #send_command, like this:
|
89
|
-
|
90
|
-
pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
|
91
|
-
|
92
|
-
This should show something like this in the client.rb terminal:
|
93
|
-
|
94
|
-
03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
|
95
|
-
MSG
|
96
|
-
|
97
|
-
binding.pry
|
@@ -1,34 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'cztop'
|
3
|
-
|
4
|
-
endpoint = ENV["BROKER_ADDRESS"]
|
5
|
-
broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
|
6
|
-
client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
|
7
|
-
|
8
|
-
@socket = CZTop::Socket::CLIENT.new
|
9
|
-
@socket.CURVE_client!(client_cert, broker_cert)
|
10
|
-
@socket.options.sndtimeo = 2000#ms
|
11
|
-
|
12
|
-
# heartbeating:
|
13
|
-
# * send PING every 100ms
|
14
|
-
# * close connection after 300ms of no life sign from broker
|
15
|
-
# * tell broker to close connection after 500ms of no life sign from client
|
16
|
-
@socket.options.heartbeat_ivl = 100#ms
|
17
|
-
@socket.options.heartbeat_timeout = 300#ms
|
18
|
-
@socket.options.heartbeat_ttl = 500#ms
|
19
|
-
|
20
|
-
@socket.connect(endpoint)
|
21
|
-
puts ">>> connected."
|
22
|
-
|
23
|
-
# tell broker who we are
|
24
|
-
@socket << "HELLO\t#{client_cert["driver_name"]}"
|
25
|
-
puts ">>> sent HELLO."
|
26
|
-
welcome = @socket.receive[0]
|
27
|
-
puts ">>> got #{welcome}."
|
28
|
-
|
29
|
-
poller = CZTop::Poller.new(@socket)
|
30
|
-
while true
|
31
|
-
socket = poller.simple_wait
|
32
|
-
message = socket.receive
|
33
|
-
puts ">>> received message: #{message[0].inspect}"
|
34
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
require 'cztop'
|
3
|
-
require 'fileutils'
|
4
|
-
FileUtils.cd(File.dirname(__FILE__))
|
5
|
-
FileUtils.mkdir "public_keys"
|
6
|
-
FileUtils.mkdir "public_keys/drivers"
|
7
|
-
FileUtils.mkdir "secret_keys"
|
8
|
-
FileUtils.mkdir "secret_keys/drivers"
|
9
|
-
#FileUtils.mkdir "certs/drivers"
|
10
|
-
|
11
|
-
DRIVERS = %w[ driver1 driver2 driver3 ]
|
12
|
-
|
13
|
-
# broker certificate
|
14
|
-
cert = CZTop::Certificate.new
|
15
|
-
cert.save("secret_keys/broker")
|
16
|
-
cert.save_public("public_keys/broker")
|
17
|
-
|
18
|
-
# driver certificates
|
19
|
-
DRIVERS.each do |driver_name|
|
20
|
-
cert = CZTop::Certificate.new
|
21
|
-
cert["driver_name"] = driver_name
|
22
|
-
cert.save "secret_keys/drivers/#{driver_name}"
|
23
|
-
cert.save_public "public_keys/drivers/#{driver_name}"
|
24
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
#!/bin/sh -x
|
2
|
-
export BROKER_ADDRESS=tcp://127.0.0.1:4455
|
3
|
-
export BROKER_CERT=public_keys/broker
|
4
|
-
CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
|
5
|
-
CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
|
6
|
-
CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
|
7
|
-
jobs
|
8
|
-
jobs -p
|
9
|
-
jobs -l
|
10
|
-
trap 'kill $(jobs -p)' EXIT
|
11
|
-
wait
|
@@ -1,24 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# Weather update server, based on ZMQ's zguide.
|
4
|
-
# Binds PUB socket to ipc:///tmp/weather_pubsub_example
|
5
|
-
# Publishes random weather updates
|
6
|
-
#
|
7
|
-
|
8
|
-
require 'cztop'
|
9
|
-
|
10
|
-
# create and bind socket
|
11
|
-
socket = CZTop::Socket::PUB.new("ipc:///tmp/weather_pubsub_example")
|
12
|
-
puts "<<< Socket bound to #{socket.last_endpoint.inspect}"
|
13
|
-
|
14
|
-
while true
|
15
|
-
# Generate values for zipcodes
|
16
|
-
zipcode = rand(100000)
|
17
|
-
temperature = rand(215) - 80
|
18
|
-
relhumidity = rand(50) + 10
|
19
|
-
|
20
|
-
update = "%05d %d %d" % [zipcode, temperature, relhumidity]
|
21
|
-
puts update
|
22
|
-
|
23
|
-
socket << update
|
24
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# Weather update client, based on that from ZMQ's zguide.
|
4
|
-
# Connects SUB socket to ipc:///tmp/weather_pubsub_example
|
5
|
-
# Collects weather updates and finds avg temp in zipcode
|
6
|
-
#
|
7
|
-
|
8
|
-
require 'cztop'
|
9
|
-
|
10
|
-
COUNT = 100
|
11
|
-
|
12
|
-
# Create socket, connect to publisher.
|
13
|
-
socket = CZTop::Socket::SUB.new("ipc:///tmp/weather_pubsub_example")
|
14
|
-
puts ">>> Socket Connected"
|
15
|
-
|
16
|
-
# Subscribe to zipcode. Default: Chicago - 60606
|
17
|
-
filter = ARGV.size > 0 ? ARGV[0] : "60606"
|
18
|
-
socket.subscribe(filter)
|
19
|
-
|
20
|
-
# gather & process COUNT updates.
|
21
|
-
print "Gathering #{COUNT} samples."
|
22
|
-
total_temp = 0
|
23
|
-
1.upto(COUNT) do |update_nbr|
|
24
|
-
msg = socket.receive
|
25
|
-
|
26
|
-
zipcode, temperature, relhumidity = msg[0].split.map(&:to_i)
|
27
|
-
total_temp += temperature
|
28
|
-
# just to show that we're doing something...
|
29
|
-
print "." if update_nbr % 5 == 0
|
30
|
-
end
|
31
|
-
print "\n"
|
32
|
-
|
33
|
-
puts "Average temperatuer for zipcode #{filter} was #{total_temp / COUNT}F."
|