cql-rb 2.0.0.pre0 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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