cod 0.4.3 → 0.4.4
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.
- data/HISTORY.txt +11 -0
- data/README +1 -1
- data/examples/example_scaffold.rb +2 -0
- data/examples/protocol-buffers/README +2 -1
- data/examples/tcp_get_ext.rb +38 -0
- data/lib/cod/service.rb +3 -1
- data/lib/cod/tcp_client.rb +14 -6
- data/lib/cod/tcp_server.rb +66 -26
- metadata +17 -23
- data/Gemfile +0 -3
- data/examples/presence/client.rb +0 -15
- data/examples/presence/server.rb +0 -30
- data/examples/queue/README +0 -9
- data/examples/queue/client.rb +0 -31
- data/examples/queue/queue.rb +0 -51
- data/examples/queue/send.rb +0 -9
data/HISTORY.txt
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
= 0.4.4 / 7Mar2012
|
2
|
+
|
3
|
+
+ Uses IO.select in the server as well, not polling for accept. This should
|
4
|
+
further reduce the CPU time consumed by servers.
|
5
|
+
|
6
|
+
! Fixes a bug where server would hang forever with messages to return in
|
7
|
+
its queue.
|
8
|
+
|
9
|
+
+ Switching to YARD for documentation, please be patient while the whole
|
10
|
+
gets a workover. This should be finished by 0.4.6 at the latest.
|
11
|
+
|
1
12
|
= 0.4.3 / 28Feb2012
|
2
13
|
|
3
14
|
! Fixes a few bugs when using tcp channels (connection was not made or not
|
data/README
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
+
$:.unshift File.expand_path(File.dirname(__FILE__))
|
3
|
+
require 'cod'
|
4
|
+
require 'example_scaffold'
|
5
|
+
|
6
|
+
2.times do
|
7
|
+
client {
|
8
|
+
chan = Cod.tcp('localhost:1234')
|
9
|
+
chan.put :get_client_id
|
10
|
+
p [:client_id, chan.get]
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
server {
|
15
|
+
server = Cod.tcp_server('localhost:1234')
|
16
|
+
client_id = 0
|
17
|
+
|
18
|
+
loop do
|
19
|
+
msg, chan = server.get_ext
|
20
|
+
|
21
|
+
p [:incoming, msg, chan.object_id.to_s(16)]
|
22
|
+
begin
|
23
|
+
case msg
|
24
|
+
when :get_client_id
|
25
|
+
client_id += 1
|
26
|
+
chan.put client_id
|
27
|
+
end
|
28
|
+
|
29
|
+
ensure
|
30
|
+
# Closes connections after one request.
|
31
|
+
chan.close
|
32
|
+
end
|
33
|
+
|
34
|
+
break if client_id >= 2
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
run
|
data/lib/cod/service.rb
CHANGED
@@ -4,7 +4,7 @@ module Cod
|
|
4
4
|
# answer. It solves problems related to timeouts, getting _your_ answer and
|
5
5
|
# not any kind of answer, etc...
|
6
6
|
#
|
7
|
-
# Synopsis
|
7
|
+
# == Synopsis
|
8
8
|
# # On the server end:
|
9
9
|
# service = server_channel.service
|
10
10
|
# service.one { |request| :answer }
|
@@ -40,6 +40,8 @@ module Cod
|
|
40
40
|
# Use Cod::Client to perform the service call. This will keep track of
|
41
41
|
# messages sent and answers received and a couple of other things.
|
42
42
|
#
|
43
|
+
# @yield [Object] request made by the client. The return value of the
|
44
|
+
# block will be returned to the client.
|
43
45
|
#
|
44
46
|
def one
|
45
47
|
rq, answer_chan = @channel.get
|
data/lib/cod/tcp_client.rb
CHANGED
@@ -25,12 +25,15 @@ module Cod
|
|
25
25
|
@serializer = serializer
|
26
26
|
@destination = destination
|
27
27
|
|
28
|
+
# TODO remove this soon
|
29
|
+
fail "Deprecated API" if destination.kind_of?(TCPSocket)
|
30
|
+
|
28
31
|
# TcpClient handles two cases: Construction via an url (destination is a
|
29
32
|
# string) and construction via a connection that has been
|
30
33
|
# preestablished (destination is a socket):
|
31
|
-
if destination.respond_to?(:
|
32
|
-
#
|
33
|
-
@connection =
|
34
|
+
if destination.respond_to?(:established?)
|
35
|
+
# Should be a connection already.
|
36
|
+
@connection = destination
|
34
37
|
else
|
35
38
|
@connection = RobustConnection.new(destination)
|
36
39
|
end
|
@@ -115,6 +118,8 @@ module Cod
|
|
115
118
|
# the other end (the deserializing end). What the deserializing code does
|
116
119
|
# with this is his problem.
|
117
120
|
#
|
121
|
+
# @private
|
122
|
+
#
|
118
123
|
OtherEnd = Struct.new(:destination) # :nodoc:
|
119
124
|
|
120
125
|
def _dump(level) # :nodoc:
|
@@ -235,9 +240,12 @@ module Cod
|
|
235
240
|
# the TcpServers clients: the tcp server manages the back channels, so
|
236
241
|
# the created channel is lent its socket only.
|
237
242
|
#
|
243
|
+
# @private
|
244
|
+
#
|
238
245
|
class Connection # :nodoc:
|
239
|
-
def initialize(socket)
|
240
|
-
@
|
246
|
+
def initialize(socket, owner)
|
247
|
+
@owner = owner
|
248
|
+
@socket = socket
|
241
249
|
end
|
242
250
|
attr_reader :socket
|
243
251
|
def try_connect
|
@@ -252,7 +260,7 @@ module Cod
|
|
252
260
|
@socket.write(buffer)
|
253
261
|
end
|
254
262
|
def close
|
255
|
-
@socket
|
263
|
+
@owner.request_close(socket)
|
256
264
|
end
|
257
265
|
end
|
258
266
|
end
|
data/lib/cod/tcp_server.rb
CHANGED
@@ -4,7 +4,7 @@ module Cod
|
|
4
4
|
# A tcp server channel. Messages are read from any of the connected sockets
|
5
5
|
# in a round robin fashion.
|
6
6
|
#
|
7
|
-
# Synopsis
|
7
|
+
# == Synopsis
|
8
8
|
# server = Cod.tcp_server('localhost:12345')
|
9
9
|
# server.get # 'a message'
|
10
10
|
# msg, chan = server.get_ext
|
@@ -13,13 +13,11 @@ module Cod
|
|
13
13
|
# connected sockets, this is up to you to implement. Instead, you can use
|
14
14
|
# one of two ways to obtain a channel for talking back to a specific client:
|
15
15
|
#
|
16
|
-
# Using #get_ext:
|
17
16
|
# msg, chan = server.get_ext
|
18
|
-
#
|
17
|
+
#
|
19
18
|
# chan is a two way connected channel to the specific client that has opened
|
20
19
|
# its communication with msg.
|
21
20
|
#
|
22
|
-
# Using plain #get:
|
23
21
|
# # on the client:
|
24
22
|
# client.put [client, :msg]
|
25
23
|
# # on the server
|
@@ -37,10 +35,14 @@ module Cod
|
|
37
35
|
@serializer = serializer
|
38
36
|
end
|
39
37
|
|
40
|
-
# Receives one object from the channel.
|
38
|
+
# Receives one object from the channel. This will receive one message from
|
39
|
+
# one of the connected clients in a round-robin fashion.
|
41
40
|
#
|
42
|
-
#
|
41
|
+
# @example
|
43
42
|
# channel.get # => object
|
43
|
+
#
|
44
|
+
# @param opts [Hash]
|
45
|
+
# @return [Object] message sent by one of the clients
|
44
46
|
#
|
45
47
|
def get(opts={})
|
46
48
|
msg, socket = _get(opts)
|
@@ -54,14 +56,18 @@ module Cod
|
|
54
56
|
# Using this method, the server can communicate back to its clients
|
55
57
|
# individually instead of collectively.
|
56
58
|
#
|
57
|
-
#
|
59
|
+
# @example Answering to the client that sent a specific message
|
58
60
|
# msg, chan = server.get_ext
|
59
61
|
# chan.put :answer
|
62
|
+
#
|
63
|
+
# @param opts [Hash]
|
64
|
+
# @return [Array<Object, TcpClient>] tuple of the message that was sent
|
65
|
+
# a channel back to the client that sent the message
|
60
66
|
def get_ext(opts={})
|
61
67
|
msg, socket = _get(opts)
|
62
68
|
return [
|
63
69
|
msg,
|
64
|
-
|
70
|
+
produce_back_channel(socket)]
|
65
71
|
end
|
66
72
|
|
67
73
|
# Closes the channel.
|
@@ -89,37 +95,65 @@ module Cod
|
|
89
95
|
def service
|
90
96
|
Service.new(self)
|
91
97
|
end
|
92
|
-
|
98
|
+
|
99
|
+
# @note It is really more convenient to just construct a Cod.tcp_client
|
93
100
|
# and ask that for a client object. In the case of TCP, this is enough.
|
94
101
|
#
|
95
102
|
def client(answers_to)
|
96
103
|
Service::Client.new(answers_to, answers_to)
|
97
104
|
end
|
98
105
|
|
106
|
+
# ------------------------------------------------------- connection owner
|
107
|
+
|
108
|
+
# Notifies the TcpServer that one of its connections needs to be closed.
|
109
|
+
# This can be triggered by using #get_ext to obtain a handle to connections
|
110
|
+
# and then calling #close on that connection.
|
111
|
+
#
|
112
|
+
# @param socket [TCPSocket] the socket that needs to be closed
|
113
|
+
# @return [void]
|
114
|
+
#
|
115
|
+
def request_close(socket)
|
116
|
+
@client_sockets.delete(socket)
|
117
|
+
socket.close
|
118
|
+
end
|
119
|
+
|
99
120
|
private
|
100
121
|
def _get(opts)
|
101
122
|
loop do
|
102
|
-
#
|
103
|
-
|
123
|
+
# Return a buffered message if there is one left.
|
124
|
+
return @messages.shift unless @messages.empty?
|
104
125
|
|
105
|
-
#
|
106
|
-
# same client.
|
126
|
+
# Shuffle the socket list around, so we don't always read from the
|
127
|
+
# same client first.
|
107
128
|
socket_list = round_robin(@client_sockets)
|
108
|
-
|
109
|
-
#
|
110
|
-
|
129
|
+
|
130
|
+
# Append the server socket to be able to react to new connections
|
131
|
+
# that are made.
|
132
|
+
socket_list << @socket
|
133
|
+
|
134
|
+
# Sleep until either a new connection is made or data is available on
|
135
|
+
# one of the old connections.
|
136
|
+
rr, _, _ = IO.select(socket_list, nil, nil)
|
111
137
|
next unless rr
|
112
138
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
else
|
118
|
-
consume_pending io, opts
|
119
|
-
end
|
139
|
+
# Accept new connections
|
140
|
+
if rr.include?(@socket)
|
141
|
+
accept_new_connections
|
142
|
+
rr.delete(@socket)
|
120
143
|
end
|
121
144
|
|
122
|
-
|
145
|
+
handle_socket_events(rr, opts)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def handle_socket_events(sockets, opts)
|
150
|
+
sockets.each do |io|
|
151
|
+
if io.eof?
|
152
|
+
@client_sockets.delete(io)
|
153
|
+
io.close
|
154
|
+
else
|
155
|
+
consume_pending io, opts
|
156
|
+
end
|
123
157
|
end
|
124
158
|
end
|
125
159
|
|
@@ -130,14 +164,14 @@ module Cod
|
|
130
164
|
io]
|
131
165
|
|
132
166
|
# More messages from this socket?
|
133
|
-
return unless IO.select([io], nil, nil, 0.
|
167
|
+
return unless IO.select([io], nil, nil, 0.0001)
|
134
168
|
end
|
135
169
|
end
|
136
170
|
|
137
171
|
def deserialize(io)
|
138
172
|
@serializer.de(io) { |obj|
|
139
173
|
obj.kind_of?(TcpClient::OtherEnd) ?
|
140
|
-
|
174
|
+
produce_back_channel(io) :
|
141
175
|
obj
|
142
176
|
}
|
143
177
|
end
|
@@ -161,5 +195,11 @@ module Cod
|
|
161
195
|
rescue Errno::EAGAIN
|
162
196
|
# This means that there are no sockets to accept. Continue.
|
163
197
|
end
|
198
|
+
|
199
|
+
def produce_back_channel(socket)
|
200
|
+
TcpClient.new(
|
201
|
+
TcpClient::Connection.new(socket, self),
|
202
|
+
@serializer)
|
203
|
+
end
|
164
204
|
end
|
165
205
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-03-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement: &
|
16
|
+
requirement: &70125556634640 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70125556634640
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &70125556634180 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70125556634180
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: flexmock
|
38
|
-
requirement: &
|
38
|
+
requirement: &70125556633740 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70125556633740
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: yard
|
49
|
-
requirement: &
|
49
|
+
requirement: &70125556633260 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70125556633260
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: guard
|
60
|
-
requirement: &
|
60
|
+
requirement: &70125556632740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70125556632740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: growl
|
71
|
-
requirement: &
|
71
|
+
requirement: &70125556632280 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70125556632280
|
80
80
|
description:
|
81
81
|
email: kaspar.schiess@absurd.li
|
82
82
|
executables: []
|
@@ -84,7 +84,6 @@ extensions: []
|
|
84
84
|
extra_rdoc_files:
|
85
85
|
- README
|
86
86
|
files:
|
87
|
-
- Gemfile
|
88
87
|
- HISTORY.txt
|
89
88
|
- LICENSE
|
90
89
|
- Rakefile
|
@@ -114,16 +113,11 @@ files:
|
|
114
113
|
- examples/master_child.rb
|
115
114
|
- examples/netcat/README
|
116
115
|
- examples/netcat/server.rb
|
117
|
-
- examples/presence/client.rb
|
118
|
-
- examples/presence/server.rb
|
119
116
|
- examples/protocol-buffers/master_child.rb
|
120
117
|
- examples/protocol-buffers/README
|
121
|
-
- examples/queue/client.rb
|
122
|
-
- examples/queue/queue.rb
|
123
|
-
- examples/queue/README
|
124
|
-
- examples/queue/send.rb
|
125
118
|
- examples/service.rb
|
126
119
|
- examples/tcp.rb
|
120
|
+
- examples/tcp_get_ext.rb
|
127
121
|
homepage: http://kschiess.github.com/cod
|
128
122
|
licenses: []
|
129
123
|
post_install_message:
|
@@ -140,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
134
|
version: '0'
|
141
135
|
segments:
|
142
136
|
- 0
|
143
|
-
hash: -
|
137
|
+
hash: -763744089584274604
|
144
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
145
139
|
none: false
|
146
140
|
requirements:
|
@@ -149,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
149
143
|
version: '0'
|
150
144
|
segments:
|
151
145
|
- 0
|
152
|
-
hash: -
|
146
|
+
hash: -763744089584274604
|
153
147
|
requirements: []
|
154
148
|
rubyforge_project:
|
155
149
|
rubygems_version: 1.8.16
|
data/Gemfile
DELETED
data/examples/presence/client.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
|
5
|
-
raise unless ARGV.first
|
6
|
-
|
7
|
-
client = Cod.tcp('localhost:12345')
|
8
|
-
client.put [client, ARGV.first]
|
9
|
-
|
10
|
-
puts "Waiting..."
|
11
|
-
$stdin.gets
|
12
|
-
client.close
|
13
|
-
$stdin.gets
|
14
|
-
|
15
|
-
|
data/examples/presence/server.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
|
2
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
|
3
|
-
require 'cod'
|
4
|
-
|
5
|
-
|
6
|
-
present = {}
|
7
|
-
server = Cod.tcpserver('localhost:12345')
|
8
|
-
|
9
|
-
loop do
|
10
|
-
# Process connection requests
|
11
|
-
while server.waiting?
|
12
|
-
connection, attributes = server.get
|
13
|
-
|
14
|
-
present[connection] = attributes
|
15
|
-
end
|
16
|
-
|
17
|
-
# Check if all connections are alive
|
18
|
-
remove = []
|
19
|
-
present.each do |conn, attrs|
|
20
|
-
if conn.connected?
|
21
|
-
puts "Alive: #{attrs.inspect}"
|
22
|
-
else
|
23
|
-
puts "Dead: #{attrs.inspect}"
|
24
|
-
remove << conn
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
remove.each { |conn| present.delete(conn) }
|
29
|
-
sleep 1
|
30
|
-
end
|
data/examples/queue/README
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
A small queue like example.
|
2
|
-
|
3
|
-
run ruby send.rb N to send N messages through queue.rb to client.rb.
|
4
|
-
Client will print statistics (calls per second) every 100 messages.
|
5
|
-
|
6
|
-
Problems:
|
7
|
-
- queue.rb seems to always consume 100% CPU
|
8
|
-
- number of messages per second is way low
|
9
|
-
- some exceptions are still not handled correctly
|
data/examples/queue/client.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
queue = Cod.tcp('localhost:12345')
|
5
|
-
|
6
|
-
queue.put [:join, queue]
|
7
|
-
|
8
|
-
class CallCounter
|
9
|
-
attr_reader :n
|
10
|
-
def initialize
|
11
|
-
@n = 0
|
12
|
-
@last_lap = [0, Time.now]
|
13
|
-
end
|
14
|
-
def inc
|
15
|
-
@n += 1
|
16
|
-
end
|
17
|
-
def calls_per_sec
|
18
|
-
ln, ll = @last_lap
|
19
|
-
@last_lap = [@n, Time.now]
|
20
|
-
|
21
|
-
(@n - ln) / (Time.now - ll)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
cc = CallCounter.new
|
26
|
-
loop do
|
27
|
-
wi = queue.get
|
28
|
-
|
29
|
-
cc.inc
|
30
|
-
puts cc.calls_per_sec if cc.n%100==0
|
31
|
-
end
|
data/examples/queue/queue.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
$:.unshift File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
2
|
-
require 'cod'
|
3
|
-
|
4
|
-
class Queue
|
5
|
-
def initialize(url)
|
6
|
-
@url = url
|
7
|
-
connect
|
8
|
-
end
|
9
|
-
|
10
|
-
def connect
|
11
|
-
@clients = []
|
12
|
-
@server = Cod.tcpserver(@url)
|
13
|
-
end
|
14
|
-
|
15
|
-
def run
|
16
|
-
loop do
|
17
|
-
handle_commands
|
18
|
-
|
19
|
-
check_connections
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def handle_commands
|
24
|
-
while @server.waiting?
|
25
|
-
cmd, *rest = @server.get
|
26
|
-
|
27
|
-
dispatch_command cmd, rest
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def dispatch_command(cmd, rest)
|
32
|
-
self.send("cmd_#{cmd}", *rest)
|
33
|
-
end
|
34
|
-
|
35
|
-
def cmd_join(connection)
|
36
|
-
puts "Join at #{Time.now}."
|
37
|
-
@clients << connection
|
38
|
-
end
|
39
|
-
|
40
|
-
def cmd_work_item
|
41
|
-
@clients.each do |client|
|
42
|
-
client.put :work_item
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def check_connections
|
47
|
-
@clients.keep_if { |client| client.connected? }
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
Queue.new('localhost:12345').run
|