cql-rb 2.0.0.pre0 → 2.0.0.pre1

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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -2
  3. data/lib/cql.rb +8 -3
  4. data/lib/cql/client.rb +21 -356
  5. data/lib/cql/client/authenticators.rb +70 -0
  6. data/lib/cql/client/batch.rb +54 -0
  7. data/lib/cql/client/{asynchronous_client.rb → client.rb} +241 -6
  8. data/lib/cql/client/connector.rb +3 -2
  9. data/lib/cql/client/{asynchronous_prepared_statement.rb → prepared_statement.rb} +103 -0
  10. data/lib/cql/protocol.rb +1 -2
  11. data/lib/cql/protocol/cql_byte_buffer.rb +285 -0
  12. data/lib/cql/protocol/cql_protocol_handler.rb +3 -3
  13. data/lib/cql/protocol/frame_decoder.rb +3 -3
  14. data/lib/cql/protocol/frame_encoder.rb +2 -2
  15. data/lib/cql/protocol/request.rb +0 -2
  16. data/lib/cql/protocol/requests/auth_response_request.rb +2 -2
  17. data/lib/cql/protocol/requests/batch_request.rb +10 -10
  18. data/lib/cql/protocol/requests/credentials_request.rb +2 -2
  19. data/lib/cql/protocol/requests/execute_request.rb +13 -13
  20. data/lib/cql/protocol/requests/options_request.rb +2 -2
  21. data/lib/cql/protocol/requests/prepare_request.rb +2 -2
  22. data/lib/cql/protocol/requests/query_request.rb +13 -13
  23. data/lib/cql/protocol/requests/register_request.rb +2 -2
  24. data/lib/cql/protocol/requests/startup_request.rb +2 -2
  25. data/lib/cql/protocol/response.rb +2 -4
  26. data/lib/cql/protocol/responses/auth_challenge_response.rb +2 -2
  27. data/lib/cql/protocol/responses/auth_success_response.rb +2 -2
  28. data/lib/cql/protocol/responses/authenticate_response.rb +2 -2
  29. data/lib/cql/protocol/responses/detailed_error_response.rb +15 -15
  30. data/lib/cql/protocol/responses/error_response.rb +4 -4
  31. data/lib/cql/protocol/responses/event_response.rb +3 -3
  32. data/lib/cql/protocol/responses/prepared_result_response.rb +4 -4
  33. data/lib/cql/protocol/responses/raw_rows_result_response.rb +1 -1
  34. data/lib/cql/protocol/responses/ready_response.rb +1 -1
  35. data/lib/cql/protocol/responses/result_response.rb +3 -3
  36. data/lib/cql/protocol/responses/rows_result_response.rb +22 -22
  37. data/lib/cql/protocol/responses/schema_change_event_response.rb +2 -2
  38. data/lib/cql/protocol/responses/schema_change_result_response.rb +2 -2
  39. data/lib/cql/protocol/responses/set_keyspace_result_response.rb +2 -2
  40. data/lib/cql/protocol/responses/status_change_event_response.rb +2 -2
  41. data/lib/cql/protocol/responses/supported_response.rb +2 -2
  42. data/lib/cql/protocol/responses/void_result_response.rb +1 -1
  43. data/lib/cql/protocol/type_converter.rb +78 -81
  44. data/lib/cql/time_uuid.rb +6 -0
  45. data/lib/cql/uuid.rb +2 -1
  46. data/lib/cql/version.rb +1 -1
  47. data/spec/cql/client/batch_spec.rb +8 -8
  48. data/spec/cql/client/{asynchronous_client_spec.rb → client_spec.rb} +162 -0
  49. data/spec/cql/client/connector_spec.rb +13 -3
  50. data/spec/cql/client/{asynchronous_prepared_statement_spec.rb → prepared_statement_spec.rb} +148 -1
  51. data/spec/cql/client/request_runner_spec.rb +2 -2
  52. data/spec/cql/protocol/cql_byte_buffer_spec.rb +895 -0
  53. data/spec/cql/protocol/cql_protocol_handler_spec.rb +1 -1
  54. data/spec/cql/protocol/frame_decoder_spec.rb +14 -14
  55. data/spec/cql/protocol/frame_encoder_spec.rb +7 -7
  56. data/spec/cql/protocol/requests/auth_response_request_spec.rb +4 -4
  57. data/spec/cql/protocol/requests/batch_request_spec.rb +21 -21
  58. data/spec/cql/protocol/requests/credentials_request_spec.rb +2 -2
  59. data/spec/cql/protocol/requests/execute_request_spec.rb +13 -13
  60. data/spec/cql/protocol/requests/options_request_spec.rb +1 -1
  61. data/spec/cql/protocol/requests/prepare_request_spec.rb +2 -2
  62. data/spec/cql/protocol/requests/query_request_spec.rb +13 -13
  63. data/spec/cql/protocol/requests/register_request_spec.rb +2 -2
  64. data/spec/cql/protocol/requests/startup_request_spec.rb +4 -4
  65. data/spec/cql/protocol/responses/auth_challenge_response_spec.rb +5 -5
  66. data/spec/cql/protocol/responses/auth_success_response_spec.rb +5 -5
  67. data/spec/cql/protocol/responses/authenticate_response_spec.rb +3 -3
  68. data/spec/cql/protocol/responses/detailed_error_response_spec.rb +15 -15
  69. data/spec/cql/protocol/responses/error_response_spec.rb +5 -5
  70. data/spec/cql/protocol/responses/event_response_spec.rb +8 -8
  71. data/spec/cql/protocol/responses/prepared_result_response_spec.rb +7 -7
  72. data/spec/cql/protocol/responses/raw_rows_result_response_spec.rb +1 -1
  73. data/spec/cql/protocol/responses/ready_response_spec.rb +2 -2
  74. data/spec/cql/protocol/responses/result_response_spec.rb +16 -16
  75. data/spec/cql/protocol/responses/rows_result_response_spec.rb +21 -21
  76. data/spec/cql/protocol/responses/schema_change_event_response_spec.rb +3 -3
  77. data/spec/cql/protocol/responses/schema_change_result_response_spec.rb +3 -3
  78. data/spec/cql/protocol/responses/set_keyspace_result_response_spec.rb +2 -2
  79. data/spec/cql/protocol/responses/status_change_event_response_spec.rb +3 -3
  80. data/spec/cql/protocol/responses/supported_response_spec.rb +3 -3
  81. data/spec/cql/protocol/responses/topology_change_event_response_spec.rb +3 -3
  82. data/spec/cql/protocol/responses/void_result_response_spec.rb +2 -2
  83. data/spec/cql/protocol/type_converter_spec.rb +25 -13
  84. data/spec/cql/time_uuid_spec.rb +17 -4
  85. data/spec/cql/uuid_spec.rb +5 -1
  86. data/spec/integration/protocol_spec.rb +48 -42
  87. data/spec/spec_helper.rb +0 -1
  88. metadata +27 -39
  89. data/lib/cql/byte_buffer.rb +0 -177
  90. data/lib/cql/client/synchronous_client.rb +0 -79
  91. data/lib/cql/client/synchronous_prepared_statement.rb +0 -63
  92. data/lib/cql/future.rb +0 -515
  93. data/lib/cql/io.rb +0 -15
  94. data/lib/cql/io/connection.rb +0 -220
  95. data/lib/cql/io/io_reactor.rb +0 -349
  96. data/lib/cql/protocol/decoding.rb +0 -187
  97. data/lib/cql/protocol/encoding.rb +0 -114
  98. data/spec/cql/byte_buffer_spec.rb +0 -337
  99. data/spec/cql/client/synchronous_client_spec.rb +0 -170
  100. data/spec/cql/client/synchronous_prepared_statement_spec.rb +0 -155
  101. data/spec/cql/future_spec.rb +0 -737
  102. data/spec/cql/io/connection_spec.rb +0 -484
  103. data/spec/cql/io/io_reactor_spec.rb +0 -402
  104. data/spec/cql/protocol/decoding_spec.rb +0 -547
  105. data/spec/cql/protocol/encoding_spec.rb +0 -386
  106. data/spec/integration/io_spec.rb +0 -283
  107. data/spec/support/fake_server.rb +0 -106
data/lib/cql/io.rb DELETED
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Cql
4
- IoError = Class.new(CqlError)
5
- CancelledError = Class.new(CqlError)
6
-
7
- module Io
8
- ConnectionError = Class.new(IoError)
9
- ConnectionClosedError = Class.new(ConnectionError)
10
- ConnectionTimeoutError = Class.new(ConnectionError)
11
- end
12
- end
13
-
14
- require 'cql/io/io_reactor'
15
- require 'cql/io/connection'
@@ -1,220 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'socket'
4
-
5
-
6
- module Cql
7
- module Io
8
- # A wrapper around a socket. Handles connecting to the remote host, reading
9
- # from and writing to the socket.
10
- #
11
- # @private
12
- class Connection
13
- attr_reader :host, :port, :connection_timeout
14
-
15
- # @private
16
- def initialize(host, port, connection_timeout, unblocker, clock, socket_impl=Socket)
17
- @host = host
18
- @port = port
19
- @connection_timeout = connection_timeout
20
- @unblocker = unblocker
21
- @clock = clock
22
- @socket_impl = socket_impl
23
- @lock = Mutex.new
24
- @connected = false
25
- @write_buffer = ByteBuffer.new
26
- @connected_promise = Promise.new
27
- end
28
-
29
- # @private
30
- def connect
31
- begin
32
- unless @addrinfos
33
- @connection_started_at = @clock.now
34
- @addrinfos = @socket_impl.getaddrinfo(@host, @port, nil, Socket::SOCK_STREAM)
35
- end
36
- unless @io
37
- _, port, _, ip, address_family, socket_type = @addrinfos.shift
38
- @sockaddr = @socket_impl.sockaddr_in(port, ip)
39
- @io = @socket_impl.new(address_family, socket_type, 0)
40
- end
41
- unless connected?
42
- @io.connect_nonblock(@sockaddr)
43
- @connected = true
44
- @connected_promise.fulfill(self)
45
- end
46
- rescue Errno::EISCONN
47
- @connected = true
48
- @connected_promise.fulfill(self)
49
- rescue Errno::EINPROGRESS, Errno::EALREADY
50
- if @clock.now - @connection_started_at > @connection_timeout
51
- close(ConnectionTimeoutError.new("Could not connect to #{@host}:#{@port} within #{@connection_timeout}s"))
52
- end
53
- rescue Errno::EINVAL, Errno::ECONNREFUSED => e
54
- if @addrinfos.empty?
55
- close(e)
56
- else
57
- @io = nil
58
- retry
59
- end
60
- rescue SystemCallError => e
61
- close(e)
62
- rescue SocketError => e
63
- close(e) || closed!(e)
64
- end
65
- @connected_promise.future
66
- end
67
-
68
- # Closes the connection
69
- def close(cause=nil)
70
- return false unless @io
71
- begin
72
- @io.close
73
- rescue SystemCallError, IOError
74
- # nothing to do, the socket was most likely already closed
75
- end
76
- closed!(cause)
77
- true
78
- end
79
-
80
- # @private
81
- def connecting?
82
- !(closed? || connected?)
83
- end
84
-
85
- # Returns true if the connection is connected
86
- def connected?
87
- @connected
88
- end
89
-
90
- # Returns true if the connection is closed
91
- def closed?
92
- @io.nil?
93
- end
94
-
95
- # @private
96
- def writable?
97
- empty_buffer = @lock.synchronize do
98
- @write_buffer.empty?
99
- end
100
- !(closed? || empty_buffer)
101
- end
102
-
103
- # Register to receive notifications when new data is read from the socket.
104
- #
105
- # You should only call this method in your protocol handler constructor.
106
- #
107
- # Only one callback can be registered, if you register multiple times only
108
- # the last one will receive notifications. This is not meant as a general
109
- # event system, it's just for protocol handlers to receive data from their
110
- # connection. If you want multiple listeners you need to implement that
111
- # yourself in your protocol handler.
112
- #
113
- # It is very important that you don't do any heavy lifting in the callback
114
- # since it is called from the IO reactor thread, and as long as the
115
- # callback is working the reactor can't handle any IO and no other
116
- # callbacks can be called.
117
- #
118
- # Errors raised by the callback will be ignored.
119
- #
120
- # @yield [String] the new data
121
- #
122
- def on_data(&listener)
123
- @data_listener = listener
124
- end
125
-
126
- # Register to receive a notification when the socket is closed, both for
127
- # expected and unexpected reasons.
128
- #
129
- # You shoud only call this method in your protocol handler constructor.
130
- #
131
- # Only one callback can be registered, if you register multiple times only
132
- # the last one will receive notifications. This is not meant as a general
133
- # event system, it's just for protocol handlers to be notified of the
134
- # connection closing. If you want multiple listeners you need to implement
135
- # that yourself in your protocol handler.
136
- #
137
- # Errors raised by the callback will be ignored.
138
- #
139
- # @yield [error, nil] the error that caused the socket to close, or nil if
140
- # the socket closed with #close
141
- #
142
- def on_closed(&listener)
143
- @closed_listener = listener
144
- end
145
-
146
- # Write bytes to the socket.
147
- #
148
- # You can either pass in bytes (as a string or as a `ByteBuffer`), or you
149
- # can use the block form of this method to get access to the connection's
150
- # internal buffer.
151
- #
152
- # @yieldparam buffer [Cql::ByteBuffer] the connection's internal buffer
153
- # @param bytes [String, Cql::ByteBuffer] the data to write to the socket
154
- #
155
- def write(bytes=nil)
156
- @lock.synchronize do
157
- if block_given?
158
- yield @write_buffer
159
- elsif bytes
160
- @write_buffer.append(bytes)
161
- end
162
- end
163
- @unblocker.unblock!
164
- end
165
-
166
- # @private
167
- def flush
168
- if writable?
169
- @lock.synchronize do
170
- bytes_written = @io.write_nonblock(@write_buffer.cheap_peek)
171
- @write_buffer.discard(bytes_written)
172
- end
173
- end
174
- rescue => e
175
- close(e)
176
- end
177
-
178
- # @private
179
- def read
180
- new_data = @io.read_nonblock(2**16)
181
- @data_listener.call(new_data) if @data_listener
182
- rescue => e
183
- close(e)
184
- end
185
-
186
- # @private
187
- def to_io
188
- @io
189
- end
190
-
191
- def to_s
192
- state = 'inconsistent'
193
- if connected?
194
- state = 'connected'
195
- elsif connecting?
196
- state = 'connecting'
197
- elsif closed?
198
- state = 'closed'
199
- end
200
- %(#<#{self.class.name} #{state} #{@host}:#{@port}>)
201
- end
202
-
203
- private
204
-
205
- def closed!(cause)
206
- @io = nil
207
- if cause && !cause.is_a?(IoError)
208
- cause = ConnectionError.new(cause.message)
209
- end
210
- unless connected?
211
- @connected_promise.fail(cause)
212
- end
213
- @connected = false
214
- if @closed_listener
215
- @closed_listener.call(cause)
216
- end
217
- end
218
- end
219
- end
220
- end
@@ -1,349 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Cql
4
- module Io
5
- ReactorError = Class.new(IoError)
6
-
7
- # An IO reactor takes care of all the IO for a client. It handles opening
8
- # new connections, and making sure that connections that have data to send
9
- # flush to the network, and connections that have data coming in read that
10
- # data and delegate it to their protocol handlers.
11
- #
12
- # All IO is done in a single background thread, regardless of how many
13
- # connections you open. There shouldn't be any problems handling hundreds of
14
- # connections if needed. All operations are thread safe, but you should take
15
- # great care when in your protocol handlers to make sure that they don't
16
- # do too much work in their data handling callbacks, since those will be
17
- # run in the reactor thread, and every cycle you use there is a cycle which
18
- # can't be used to handle IO.
19
- #
20
- # The IO reactor is completely protocol agnostic, and it's up to the
21
- # specified protocol handler factory to create objects that can interpret
22
- # the bytes received from remote hosts, and to send the correct commands
23
- # back. The way this works is that when you create an IO reactor you provide
24
- # a factory that can create protocol handler objects (this factory is most
25
- # of the time just class, but it could potentially be any object that
26
- # responds to #new). When you #connect a new protocol handler instance is
27
- # created and passed a connection. The protocol handler can then register to
28
- # receive data that arrives over the socket, and it can write data to the
29
- # socket. It can also register to be notified when the socket is closed, or
30
- # it can itself close the socket.
31
- #
32
- # @example A protocol handler that processes whole lines
33
- #
34
- # class LineProtocolHandler
35
- # def initialize(connection, scheduler)
36
- # @connection = connection
37
- # # register a listener method for new data, this must be done in the
38
- # # in the constructor, and only one listener can be registered
39
- # @connection.on_data(&method(:process_data))
40
- # @buffer = ''
41
- # end
42
- #
43
- # def process_data(new_data)
44
- # # in this fictional protocol we want to process whole lines, so we
45
- # # append new data to our buffer and then loop as long as there is
46
- # # a newline in the buffer, everything up until a newline is a
47
- # # complete line
48
- # @buffer << new_data
49
- # while newline_index = @buffer.index("\n")
50
- # line = @buffer.slice!(0, newline_index + 1)
51
- # line.chomp!
52
- # # Now do something interesting with the line, but remember that
53
- # # while you're in the data listener method you're executing in the
54
- # # IO reactor thread so you're blocking the reactor from doing
55
- # # other IO work. You should not do any heavy lifting here, but
56
- # # instead hand off the data to your application's other threads.
57
- # # One way of doing that is to create a Cql::Future in the method
58
- # # that sends the request, and then complete the future in this
59
- # # method. How you keep track of which future belongs to which
60
- # # reply is very protocol dependent so you'll have to figure that
61
- # # out yourself.
62
- # end
63
- # end
64
- #
65
- # def send_request(command_string)
66
- # # This example primarily shows how to implement a data listener
67
- # # method, but this is how you write data to the connection. The
68
- # # method can be called anything, it doesn't have to be #send_request
69
- # @connection.write(command_string)
70
- # # The connection object itself is threadsafe, but to create any
71
- # # interesting protocol you probably need to set up some state for
72
- # # each request so that you know which request to complete when you
73
- # # get data back.
74
- # end
75
- # end
76
- #
77
- # See {Cql::Protocol::CqlProtocolHandler} for an example of how the CQL
78
- # protocol is implemented, and there is an integration tests that implements
79
- # the Redis protocol that you can look at too.
80
- #
81
- # @private
82
- #
83
- class IoReactor
84
- # Initializes a new IO reactor.
85
- #
86
- # @param protocol_handler_factory [Proc, Class] a Proc or class that
87
- # will be used create the protocol handler objects returned by
88
- # {#connect}
89
- # @param options [Hash] only used to inject behaviour during tests
90
- #
91
- def initialize(protocol_handler_factory, options={})
92
- if protocol_handler_factory.respond_to?(:new)
93
- @protocol_handler_factory = protocol_handler_factory.method(:new)
94
- else
95
- @protocol_handler_factory = protocol_handler_factory
96
- end
97
- @clock = options[:clock] || Time
98
- @unblocker = Unblocker.new
99
- @io_loop = IoLoopBody.new(options)
100
- @io_loop.add_socket(@unblocker)
101
- @running = false
102
- @stopped = false
103
- @started_promise = Promise.new
104
- @stopped_promise = Promise.new
105
- @lock = Mutex.new
106
- end
107
-
108
- # Register to receive notifications when the reactor shuts down because
109
- # on an irrecoverable error.
110
- #
111
- # The listener block will be called in the reactor thread. Any errors that
112
- # it raises will be ignored.
113
- #
114
- # @yield [error] the error that cause the reactor to stop
115
- #
116
- def on_error(&listener)
117
- @stopped_promise.future.on_failure(&listener)
118
- end
119
-
120
- # Returns true as long as the reactor is running. It will be true even
121
- # after #stop has been called, but false when the future returned by
122
- # #stop completes.
123
- #
124
- def running?
125
- @running
126
- end
127
-
128
- # Starts the reactor. This will spawn a background thread that will manage
129
- # all connections.
130
- #
131
- # This method is asynchronous and returns a future which completes when
132
- # the reactor has started.
133
- #
134
- # @return [Cql::Future] a future that will resolve to the reactor itself
135
- def start
136
- @lock.synchronize do
137
- raise ReactorError, 'Cannot start a stopped IO reactor' if @stopped
138
- return @started_promise.future if @running
139
- @running = true
140
- end
141
- Thread.start do
142
- @started_promise.fulfill(self)
143
- begin
144
- @io_loop.tick until @stopped
145
- ensure
146
- @io_loop.close_sockets
147
- @io_loop.cancel_timers
148
- @running = false
149
- if $!
150
- @stopped_promise.fail($!)
151
- else
152
- @stopped_promise.fulfill(self)
153
- end
154
- end
155
- end
156
- @started_promise.future
157
- end
158
-
159
- # Stops the reactor.
160
- #
161
- # This method is asynchronous and returns a future which completes when
162
- # the reactor has completely stopped, or fails with an error if the reactor
163
- # stops or has already stopped because of a failure.
164
- #
165
- # @return [Cql::Future] a future that will resolve to the reactor itself
166
- #
167
- def stop
168
- @stopped = true
169
- @stopped_promise.future
170
- end
171
-
172
- # Opens a connection to the specified host and port.
173
- #
174
- # This method is asynchronous and returns a future which completes when
175
- # the connection has been established, or fails if the connection cannot
176
- # be established for some reason (the connection takes longer than the
177
- # specified timeout, the remote host cannot be found, etc.).
178
- #
179
- # The object returned in the future will be an instance of the protocol
180
- # handler class you passed to {#initialize}.
181
- #
182
- # @param host [String] the host to connect to
183
- # @param port [Integer] the port to connect to
184
- # @param timeout [Numeric] the number of seconds to wait for a connection
185
- # before failing
186
- # @return [Cql::Future] a future that will resolve to a protocol handler
187
- # object that will be your interface to interact with the connection
188
- #
189
- def connect(host, port, timeout)
190
- connection = Connection.new(host, port, timeout, @unblocker, @clock)
191
- f = connection.connect
192
- protocol_handler = @protocol_handler_factory.call(connection, self)
193
- @io_loop.add_socket(connection)
194
- @unblocker.unblock!
195
- f.map(protocol_handler)
196
- end
197
-
198
- # Returns a future that completes after the specified number of seconds.
199
- #
200
- # @param timeout [Float] the number of seconds to wait until the returned
201
- # future is completed
202
- # @return [Cql::Future] a future that completes when the timer expires
203
- #
204
- def schedule_timer(timeout)
205
- @io_loop.schedule_timer(timeout)
206
- end
207
-
208
- def to_s
209
- @io_loop.to_s
210
- end
211
- end
212
-
213
- # @private
214
- class Unblocker
215
- def initialize
216
- @out, @in = IO.pipe
217
- @lock = Mutex.new
218
- end
219
-
220
- def connected?
221
- true
222
- end
223
-
224
- def connecting?
225
- false
226
- end
227
-
228
- def writable?
229
- false
230
- end
231
-
232
- def closed?
233
- @in.nil?
234
- end
235
-
236
- def unblock!
237
- @lock.synchronize do
238
- @in.write(PING_BYTE)
239
- end
240
- end
241
-
242
- def read
243
- @out.read_nonblock(2**16)
244
- end
245
-
246
- def close
247
- @in.close
248
- @out.close
249
- @in = nil
250
- @out = nil
251
- end
252
-
253
- def to_io
254
- @out
255
- end
256
-
257
- def to_s
258
- %(#<#{self.class.name}>)
259
- end
260
-
261
- private
262
-
263
- PING_BYTE = "\0".freeze
264
- end
265
-
266
- # @private
267
- class IoLoopBody
268
- def initialize(options={})
269
- @selector = options[:selector] || IO
270
- @clock = options[:clock] || Time
271
- @lock = Mutex.new
272
- @sockets = []
273
- @timers = []
274
- end
275
-
276
- def add_socket(socket)
277
- @lock.synchronize do
278
- sockets = @sockets.reject { |s| s.closed? }
279
- sockets << socket
280
- @sockets = sockets
281
- end
282
- end
283
-
284
- def schedule_timer(timeout, promise=Promise.new)
285
- @lock.synchronize do
286
- timers = @timers.reject { |pair| pair[1].nil? }
287
- timers << [@clock.now + timeout, promise]
288
- @timers = timers
289
- end
290
- promise.future
291
- end
292
-
293
- def close_sockets
294
- @sockets.each do |s|
295
- begin
296
- s.close unless s.closed?
297
- rescue
298
- # the socket had most likely already closed due to an error
299
- end
300
- end
301
- end
302
-
303
- def cancel_timers
304
- @timers.each do |pair|
305
- if pair[1]
306
- pair[1].fail(CancelledError.new)
307
- pair[1] = nil
308
- end
309
- end
310
- end
311
-
312
- def tick(timeout=1)
313
- check_sockets!(timeout)
314
- check_timers!
315
- end
316
-
317
- def to_s
318
- %(#<#{IoReactor.name} @connections=[#{@sockets.map(&:to_s).join(', ')}]>)
319
- end
320
-
321
- private
322
-
323
- def check_sockets!(timeout)
324
- readables, writables, connecting = [], [], []
325
- sockets = @sockets
326
- sockets.each do |s|
327
- next if s.closed?
328
- readables << s if s.connected?
329
- writables << s if s.connecting? || s.writable?
330
- connecting << s if s.connecting?
331
- end
332
- r, w, _ = @selector.select(readables, writables, nil, timeout)
333
- connecting.each(&:connect)
334
- r && r.each(&:read)
335
- w && w.each(&:flush)
336
- end
337
-
338
- def check_timers!
339
- timers = @timers
340
- timers.each do |pair|
341
- if pair[1] && pair[0] <= @clock.now
342
- pair[1].fulfill
343
- pair[1] = nil
344
- end
345
- end
346
- end
347
- end
348
- end
349
- end