ione 1.2.0.pre1 → 1.2.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ione/future.rb +44 -24
- data/lib/ione/io.rb +3 -0
- data/lib/ione/io/acceptor.rb +25 -11
- data/lib/ione/io/base_connection.rb +4 -1
- data/lib/ione/io/connection.rb +1 -4
- data/lib/ione/io/io_reactor.rb +46 -5
- data/lib/ione/io/server_connection.rb +1 -4
- data/lib/ione/io/ssl_acceptor.rb +21 -0
- data/lib/ione/io/ssl_connection.rb +79 -0
- data/lib/ione/io/ssl_server_connection.rb +43 -0
- data/lib/ione/version.rb +1 -1
- data/spec/integration/ssl_spec.rb +97 -0
- data/spec/ione/future_spec.rb +145 -30
- data/spec/ione/io/acceptor_spec.rb +7 -0
- data/spec/ione/io/connection_common.rb +28 -26
- data/spec/ione/io/io_reactor_spec.rb +50 -2
- data/spec/ione/io/ssl_acceptor_spec.rb +116 -0
- data/spec/ione/io/ssl_connection_spec.rb +165 -0
- data/spec/ione/io/ssl_server_connection_spec.rb +108 -0
- metadata +13 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 571332add4f394d8de9adbe6b371de13c84e3a09
|
4
|
+
data.tar.gz: 006892c0ffe2f9fdb489ba5848d28be6e45ad27c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f41e94213226b72a09487b4ff615ab01b3be84ffe351f5dcd78ef2e350a0bcc17b117395fdcf35944d8ab78f4ae9383821140fa43cfb15866f9e78af9cc970ec
|
7
|
+
data.tar.gz: 91778d76c5ef9fdf87ec0d51a29abb495056d0e3843badaec6ca6eeb86683f4aa82948a6e0a68d93ddf0dc012e54eafe4d84ba91d4d38224de3eb658297f1c2e
|
data/lib/ione/future.rb
CHANGED
@@ -44,7 +44,7 @@ module Ione
|
|
44
44
|
#
|
45
45
|
# @param [Ione::Future] future the future to observe
|
46
46
|
def observe(future)
|
47
|
-
future.on_complete do |
|
47
|
+
future.on_complete do |v, e|
|
48
48
|
if e
|
49
49
|
fail(e)
|
50
50
|
else
|
@@ -215,7 +215,7 @@ module Ione
|
|
215
215
|
# @return [Ione::Future] a new future representing the transformed value
|
216
216
|
def map(value=nil, &block)
|
217
217
|
f = CompletableFuture.new
|
218
|
-
on_complete do |
|
218
|
+
on_complete do |v, e|
|
219
219
|
if e
|
220
220
|
f.fail(e)
|
221
221
|
else
|
@@ -242,13 +242,13 @@ module Ione
|
|
242
242
|
# @return [Ione::Future] a new future representing the transformed value
|
243
243
|
def flat_map(&block)
|
244
244
|
f = CompletableFuture.new
|
245
|
-
on_complete do |
|
245
|
+
on_complete do |v, e|
|
246
246
|
if e
|
247
247
|
f.fail(e)
|
248
248
|
else
|
249
249
|
begin
|
250
250
|
ff = block.call(v)
|
251
|
-
ff.on_complete do |
|
251
|
+
ff.on_complete do |vv, ee|
|
252
252
|
if ee
|
253
253
|
f.fail(ee)
|
254
254
|
else
|
@@ -288,14 +288,14 @@ module Ione
|
|
288
288
|
# @return [Ione::Future] a new future representing the transformed value
|
289
289
|
def then(&block)
|
290
290
|
f = CompletableFuture.new
|
291
|
-
on_complete do |
|
291
|
+
on_complete do |v, e|
|
292
292
|
if e
|
293
293
|
f.fail(e)
|
294
294
|
else
|
295
295
|
begin
|
296
296
|
fv = block.call(v)
|
297
297
|
if fv.respond_to?(:on_complete)
|
298
|
-
fv.on_complete do |
|
298
|
+
fv.on_complete do |vv, ee|
|
299
299
|
if ee
|
300
300
|
f.fail(ee)
|
301
301
|
else
|
@@ -334,7 +334,7 @@ module Ione
|
|
334
334
|
# @return [Ione::Future] a new future representing a value recovered from the error
|
335
335
|
def recover(value=nil, &block)
|
336
336
|
f = CompletableFuture.new
|
337
|
-
on_complete do |
|
337
|
+
on_complete do |v, e|
|
338
338
|
if e
|
339
339
|
begin
|
340
340
|
f.resolve(block ? block.call(e) : value)
|
@@ -372,11 +372,11 @@ module Ione
|
|
372
372
|
# error
|
373
373
|
def fallback(&block)
|
374
374
|
f = CompletableFuture.new
|
375
|
-
on_complete do |
|
375
|
+
on_complete do |v, e|
|
376
376
|
if e
|
377
377
|
begin
|
378
378
|
ff = block.call(e)
|
379
|
-
ff.on_complete do |
|
379
|
+
ff.on_complete do |vv, ee|
|
380
380
|
if ee
|
381
381
|
f.fail(ee)
|
382
382
|
else
|
@@ -401,8 +401,8 @@ module Ione
|
|
401
401
|
#
|
402
402
|
# @yieldparam [Object] value the value of the resolved future
|
403
403
|
def on_value(&listener)
|
404
|
-
on_complete do |
|
405
|
-
listener.call(value)
|
404
|
+
on_complete do |value, error|
|
405
|
+
listener.call(value) unless error
|
406
406
|
end
|
407
407
|
nil
|
408
408
|
end
|
@@ -413,8 +413,8 @@ module Ione
|
|
413
413
|
#
|
414
414
|
# @yieldparam [Error] error the error that failed the future
|
415
415
|
def on_failure(&listener)
|
416
|
-
on_complete do |
|
417
|
-
listener.call(error) if
|
416
|
+
on_complete do |_, error|
|
417
|
+
listener.call(error) if error
|
418
418
|
end
|
419
419
|
nil
|
420
420
|
end
|
@@ -456,7 +456,7 @@ module Ione
|
|
456
456
|
end
|
457
457
|
end
|
458
458
|
if run_immediately
|
459
|
-
listener
|
459
|
+
call_listener(listener)
|
460
460
|
end
|
461
461
|
nil
|
462
462
|
end
|
@@ -493,6 +493,7 @@ module Ione
|
|
493
493
|
semaphore.pop
|
494
494
|
end
|
495
495
|
end
|
496
|
+
alias_method :get, :value
|
496
497
|
|
497
498
|
# Returns true if this future is resolved or failed
|
498
499
|
def completed?
|
@@ -526,6 +527,25 @@ module Ione
|
|
526
527
|
@lock.unlock
|
527
528
|
end
|
528
529
|
end
|
530
|
+
|
531
|
+
private
|
532
|
+
|
533
|
+
def call_listener(listener)
|
534
|
+
begin
|
535
|
+
n = listener.arity
|
536
|
+
if n == 1
|
537
|
+
listener.call(self)
|
538
|
+
elsif n == 2 || n == -3
|
539
|
+
listener.call(@value, @error)
|
540
|
+
elsif n == 0
|
541
|
+
listener.call
|
542
|
+
else
|
543
|
+
listener.call(@value, @error, self)
|
544
|
+
end
|
545
|
+
rescue
|
546
|
+
# swallowed
|
547
|
+
end
|
548
|
+
end
|
529
549
|
end
|
530
550
|
|
531
551
|
# @private
|
@@ -543,7 +563,7 @@ module Ione
|
|
543
563
|
@lock.unlock
|
544
564
|
end
|
545
565
|
listeners.each do |listener|
|
546
|
-
listener
|
566
|
+
call_listener(listener)
|
547
567
|
end
|
548
568
|
nil
|
549
569
|
end
|
@@ -561,7 +581,7 @@ module Ione
|
|
561
581
|
@lock.unlock
|
562
582
|
end
|
563
583
|
listeners.each do |listener|
|
564
|
-
listener
|
584
|
+
call_listener(listener)
|
565
585
|
end
|
566
586
|
nil
|
567
587
|
end
|
@@ -574,7 +594,7 @@ module Ione
|
|
574
594
|
remaining = futures.count
|
575
595
|
values = Array.new(remaining)
|
576
596
|
futures.each_with_index do |f, i|
|
577
|
-
f.on_complete do |
|
597
|
+
f.on_complete do |v, e|
|
578
598
|
unless failed?
|
579
599
|
if e
|
580
600
|
fail(e)
|
@@ -651,7 +671,7 @@ module Ione
|
|
651
671
|
private
|
652
672
|
|
653
673
|
def reduce_next(i)
|
654
|
-
@futures[i].on_complete do |
|
674
|
+
@futures[i].on_complete do |v, e|
|
655
675
|
unless failed?
|
656
676
|
if e
|
657
677
|
fail(e)
|
@@ -669,7 +689,7 @@ module Ione
|
|
669
689
|
super
|
670
690
|
if @remaining > 0
|
671
691
|
futures.each do |f|
|
672
|
-
f.on_complete do |
|
692
|
+
f.on_complete do |v, e|
|
673
693
|
unless failed?
|
674
694
|
if e
|
675
695
|
fail(e)
|
@@ -690,7 +710,7 @@ module Ione
|
|
690
710
|
def initialize(futures)
|
691
711
|
super()
|
692
712
|
futures.each do |f|
|
693
|
-
f.on_complete do |
|
713
|
+
f.on_complete do |v, e|
|
694
714
|
unless completed?
|
695
715
|
if e
|
696
716
|
if futures.all?(&:failed?)
|
@@ -721,7 +741,7 @@ module Ione
|
|
721
741
|
true
|
722
742
|
end
|
723
743
|
|
724
|
-
def
|
744
|
+
def resolvesd?
|
725
745
|
true
|
726
746
|
end
|
727
747
|
|
@@ -730,7 +750,7 @@ module Ione
|
|
730
750
|
end
|
731
751
|
|
732
752
|
def on_complete(&listener)
|
733
|
-
listener
|
753
|
+
call_listener(listener)
|
734
754
|
end
|
735
755
|
|
736
756
|
def on_value(&listener)
|
@@ -768,7 +788,7 @@ module Ione
|
|
768
788
|
end
|
769
789
|
|
770
790
|
def on_complete(&listener)
|
771
|
-
listener
|
791
|
+
call_listener(listener)
|
772
792
|
end
|
773
793
|
|
774
794
|
def on_value
|
@@ -778,4 +798,4 @@ module Ione
|
|
778
798
|
listener.call(@error) rescue nil
|
779
799
|
end
|
780
800
|
end
|
781
|
-
end
|
801
|
+
end
|
data/lib/ione/io.rb
CHANGED
data/lib/ione/io/acceptor.rb
CHANGED
@@ -6,6 +6,8 @@ module Ione
|
|
6
6
|
class Acceptor
|
7
7
|
ServerSocket = RUBY_ENGINE == 'jruby' ? ::ServerSocket : Socket
|
8
8
|
|
9
|
+
attr_reader :backlog
|
10
|
+
|
9
11
|
def initialize(host, port, backlog, unblocker, reactor, socket_impl=nil)
|
10
12
|
@host = host
|
11
13
|
@port = port
|
@@ -27,8 +29,8 @@ module Ione
|
|
27
29
|
addrinfos = @socket_impl.getaddrinfo(@host, @port, nil, Socket::SOCK_STREAM)
|
28
30
|
begin
|
29
31
|
_, port, _, ip, address_family, socket_type = addrinfos.shift
|
30
|
-
@
|
31
|
-
bind_socket(@
|
32
|
+
@io = @socket_impl.new(address_family, socket_type, 0)
|
33
|
+
bind_socket(@io, @socket_impl.sockaddr_in(port, ip), @backlog)
|
32
34
|
rescue Errno::EADDRNOTAVAIL => e
|
33
35
|
if addrinfos.empty?
|
34
36
|
raise
|
@@ -38,26 +40,27 @@ module Ione
|
|
38
40
|
end
|
39
41
|
Future.resolved(self)
|
40
42
|
rescue => e
|
43
|
+
close
|
41
44
|
Future.failed(e)
|
42
45
|
end
|
43
46
|
|
44
47
|
def close
|
45
|
-
return false unless @
|
48
|
+
return false unless @io
|
46
49
|
begin
|
47
|
-
@
|
50
|
+
@io.close
|
48
51
|
rescue SystemCallError, IOError
|
49
52
|
# nothing to do, the socket was most likely already closed
|
50
53
|
end
|
51
|
-
@
|
54
|
+
@io = nil
|
52
55
|
true
|
53
56
|
end
|
54
57
|
|
55
58
|
def to_io
|
56
|
-
@
|
59
|
+
@io
|
57
60
|
end
|
58
61
|
|
59
62
|
def closed?
|
60
|
-
@
|
63
|
+
@io.nil?
|
61
64
|
end
|
62
65
|
|
63
66
|
def connected?
|
@@ -73,12 +76,10 @@ module Ione
|
|
73
76
|
end
|
74
77
|
|
75
78
|
def read
|
76
|
-
client_socket,
|
77
|
-
port, host = @socket_impl.unpack_sockaddr_in(client_sockaddr)
|
79
|
+
client_socket, host, port = accept
|
78
80
|
connection = ServerConnection.new(client_socket, host, port, @unblocker)
|
79
81
|
@reactor.accept(connection)
|
80
|
-
|
81
|
-
listeners.each { |l| l.call(connection) rescue nil }
|
82
|
+
notify_accept_listeners(connection)
|
82
83
|
end
|
83
84
|
|
84
85
|
if RUBY_ENGINE == 'jruby'
|
@@ -91,6 +92,19 @@ module Ione
|
|
91
92
|
socket.listen(backlog)
|
92
93
|
end
|
93
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def accept
|
99
|
+
client_socket, client_sockaddr = @io.accept_nonblock
|
100
|
+
port, host = @socket_impl.unpack_sockaddr_in(client_sockaddr)
|
101
|
+
return client_socket, host, port
|
102
|
+
end
|
103
|
+
|
104
|
+
def notify_accept_listeners(connection)
|
105
|
+
listeners = @lock.synchronize { @accept_listeners }
|
106
|
+
listeners.each { |l| l.call(connection) rescue nil }
|
107
|
+
end
|
94
108
|
end
|
95
109
|
end
|
96
110
|
end
|
@@ -5,10 +5,13 @@ module Ione
|
|
5
5
|
class BaseConnection
|
6
6
|
attr_reader :host, :port
|
7
7
|
|
8
|
-
def initialize(host, port)
|
8
|
+
def initialize(host, port, unblocker)
|
9
9
|
@host = host
|
10
10
|
@port = port
|
11
|
+
@unblocker = unblocker
|
11
12
|
@state = :connecting
|
13
|
+
@lock = Mutex.new
|
14
|
+
@write_buffer = ByteBuffer.new
|
12
15
|
@closed_promise = Promise.new
|
13
16
|
end
|
14
17
|
|
data/lib/ione/io/connection.rb
CHANGED
@@ -9,13 +9,10 @@ module Ione
|
|
9
9
|
|
10
10
|
# @private
|
11
11
|
def initialize(host, port, connection_timeout, unblocker, clock, socket_impl=Socket)
|
12
|
-
super(host, port)
|
12
|
+
super(host, port, unblocker)
|
13
13
|
@connection_timeout = connection_timeout
|
14
|
-
@unblocker = unblocker
|
15
14
|
@clock = clock
|
16
15
|
@socket_impl = socket_impl
|
17
|
-
@lock = Mutex.new
|
18
|
-
@write_buffer = ByteBuffer.new
|
19
16
|
@connected_promise = Promise.new
|
20
17
|
on_closed(&method(:cleanup_on_close))
|
21
18
|
end
|
data/lib/ione/io/io_reactor.rb
CHANGED
@@ -156,23 +156,57 @@ module Ione
|
|
156
156
|
#
|
157
157
|
# @param host [String] the host to connect to
|
158
158
|
# @param port [Integer] the port to connect to
|
159
|
-
# @param
|
160
|
-
#
|
159
|
+
# @param options_or_timeout [Hash, Numeric] a hash of options (see below)
|
160
|
+
# or the connection timeout (equivalent to using the `:timeout` option).
|
161
|
+
# @option options_or_timeout [Numeric] :timeout (5) the number of seconds
|
162
|
+
# to wait for a connection before failing
|
163
|
+
# @option options_or_timeout [Boolean, OpenSSL::SSL::SSLContext] :ssl (false)
|
164
|
+
# pass an `OpenSSL::SSL::SSLContext` to upgrade the connection to SSL,
|
165
|
+
# or true to upgrade the connection and create a new context.
|
161
166
|
# @yieldparam [Ione::Io::Connection] connection the newly opened connection
|
162
167
|
# @return [Ione::Future] a future that will resolve when the connection is
|
163
168
|
# open. The value will be the connection, or when a block is given to
|
164
169
|
# what the block returns
|
165
|
-
def connect(host, port,
|
170
|
+
def connect(host, port, options=nil, &block)
|
171
|
+
if options.is_a?(Numeric) || options.nil?
|
172
|
+
timeout = options || 5
|
173
|
+
ssl = false
|
174
|
+
elsif options
|
175
|
+
timeout = options[:timeout] || 5
|
176
|
+
ssl = options[:ssl]
|
177
|
+
end
|
166
178
|
connection = Connection.new(host, port, timeout, @unblocker, @clock)
|
167
179
|
f = connection.connect
|
168
180
|
@io_loop.add_socket(connection)
|
169
181
|
@unblocker.unblock!
|
182
|
+
if ssl
|
183
|
+
f = f.flat_map do
|
184
|
+
ssl_context = ssl == true ? nil : ssl
|
185
|
+
upgraded_connection = SslConnection.new(host, port, connection.to_io, @unblocker, ssl_context)
|
186
|
+
ff = upgraded_connection.connect
|
187
|
+
@io_loop.remove_socket(connection)
|
188
|
+
@io_loop.add_socket(upgraded_connection)
|
189
|
+
@unblocker.unblock!
|
190
|
+
ff
|
191
|
+
end
|
192
|
+
end
|
170
193
|
f = f.map(&block) if block_given?
|
171
194
|
f
|
172
195
|
end
|
173
196
|
|
174
|
-
def bind(host, port,
|
175
|
-
|
197
|
+
def bind(host, port, options=nil, &block)
|
198
|
+
if options.is_a?(Integer) || options.nil?
|
199
|
+
backlog = options || 5
|
200
|
+
ssl_context = nil
|
201
|
+
elsif options
|
202
|
+
backlog = options[:backlog] || 5
|
203
|
+
ssl_context = options[:ssl]
|
204
|
+
end
|
205
|
+
if ssl_context
|
206
|
+
server = SslAcceptor.new(host, port, backlog, @unblocker, self, ssl_context)
|
207
|
+
else
|
208
|
+
server = Acceptor.new(host, port, backlog, @unblocker, self)
|
209
|
+
end
|
176
210
|
f = server.bind
|
177
211
|
@io_loop.add_socket(server)
|
178
212
|
@unblocker.unblock!
|
@@ -261,6 +295,7 @@ module Ione
|
|
261
295
|
private
|
262
296
|
|
263
297
|
PING_BYTE = "\0".freeze
|
298
|
+
DEFAULT_CONNECT_OPTIONS = {:timeout => 5}.freeze
|
264
299
|
end
|
265
300
|
|
266
301
|
# @private
|
@@ -282,6 +317,12 @@ module Ione
|
|
282
317
|
@lock.unlock
|
283
318
|
end
|
284
319
|
|
320
|
+
def remove_socket(socket)
|
321
|
+
@lock.synchronize do
|
322
|
+
@sockets = @sockets.reject { |s| s == socket || s.closed? }
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
285
326
|
def schedule_timer(timeout, promise=Promise.new)
|
286
327
|
@lock.lock
|
287
328
|
timers = @timers.reject { |pair| pair[1].nil? }
|
@@ -5,11 +5,8 @@ module Ione
|
|
5
5
|
class ServerConnection < BaseConnection
|
6
6
|
# @private
|
7
7
|
def initialize(socket, host, port, unblocker)
|
8
|
-
super(host, port)
|
8
|
+
super(host, port, unblocker)
|
9
9
|
@io = socket
|
10
|
-
@unblocker = unblocker
|
11
|
-
@lock = Mutex.new
|
12
|
-
@write_buffer = ByteBuffer.new
|
13
10
|
@state = :connected
|
14
11
|
end
|
15
12
|
end
|