ione 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b16fd5d35a6cd0dd75c20ea9a3febd681f5a37b
4
- data.tar.gz: 5aff84c71ae8a849858789063b528ed59b45c87c
3
+ metadata.gz: e616ec4a5f533a25efb171aa4e6ede4b1ca5de6f
4
+ data.tar.gz: 433284b5a259cb2db15f8ac95882d13d1e63507a
5
5
  SHA512:
6
- metadata.gz: b6e57d6dc85d7b329353e8d7ff2cb8ba606ff2431377fb7f1e7ca1badf6e0b1ccc7e3971d03cf28387798b307c85cbb32de4c0dbc2851664e096447b190b7215
7
- data.tar.gz: c6825f4358471a8c344f39f3473dc6c11d8f3367886d25953de255c84ebf53f214098f3deeb46471a323ef1a5b628c72e271a910d6930db5d146bba885ba29e6
6
+ metadata.gz: f80b6f25ac0192d10eac99cc8e2dd15b373944bb89e3125f378ff17df4a7a07caf0f35955e5772b322911560a8dff3cc42704c4c25dc67c952cd8c15269e5c8b
7
+ data.tar.gz: 885562d9eb7bb0cd1e6499a0b975fb2d82dee2298918fef4887ca66b5b9d4959c4bdacdd8c2aa2deb2a8e0f44187017dcc44dd9b801a5432bf0888caa720cac9
data/README.md CHANGED
@@ -27,7 +27,7 @@ Networking usually means pushing lots of bytes around and in Ruby it's easy to m
27
27
  The [examples](https://github.com/iconara/ione/tree/master/examples) directory has some examples of what you can do with Ione, for example:
28
28
 
29
29
  * [redis_client](https://github.com/iconara/ione/tree/master/examples/redis_client) is a more or less full featured Redis client that uses most of Ione's features.
30
- * [http_client](https://github.com/iconara/ione/tree/master/examples/http_client) is a simplistic HTTP client that uses Ione and [http_parser.rb](http://rubygems.org/gems/http_parser.rb) to make HTTP GET request.
30
+ * [http_client](https://github.com/iconara/ione/tree/master/examples/http_client) is a simplistic HTTP client that uses Ione and [http_parser.rb](http://rubygems.org/gems/http_parser.rb) to make HTTP GET request. It also shows how to make TLS connections.
31
31
  * [cql-rb](https://github.com/iconara/cql-rb) is a high performance Cassandra driver and where Ione was originally developed.
32
32
  * [cassandra-driver](https://github.com/datastax/ruby-driver) is the successor to cql-rb.
33
33
  * [ione-rpc](https://github.com/iconara/ione-rpc) is a RPC framework built on Ione. It makes it reasonably easy to build networked applications without having to reinvent the wheel.
@@ -14,6 +14,8 @@ module Ione
14
14
  # buffer and one is the write buffer. Writes go to the write buffer only,
15
15
  # and reads read from the read buffer until it is empty, then a new write
16
16
  # buffer is created and the old write buffer becomes the new read buffer.
17
+ #
18
+ # @since v1.0.0
17
19
  class ByteBuffer
18
20
  def initialize(initial_bytes=nil)
19
21
  @read_buffer = ''
data/lib/ione/future.rb CHANGED
@@ -11,6 +11,7 @@ module Ione
11
11
  # A promise is the write end of a Promise/Future pair. It can be fulfilled
12
12
  # with a value or failed with an error. The value can be read through the
13
13
  # future returned by {#future}.
14
+ # @since v1.0.0
14
15
  class Promise
15
16
  attr_reader :future
16
17
 
@@ -104,7 +105,7 @@ module Ione
104
105
  #
105
106
  # @example Creating a future for a blocking operation
106
107
  # def find_my_ip
107
- # promise = Promse.new
108
+ # promise = Promise.new
108
109
  # Thread.start do
109
110
  # begin
110
111
  # data = JSON.load(open('http://jsonip.org/').read)
@@ -178,7 +179,13 @@ module Ione
178
179
  # @see Ione::Future::FutureCallbacks
179
180
  # @see Ione::Future::FutureCombinators
180
181
  # @see Ione::Future::FutureFactories
182
+ # @since v1.0.0
181
183
  class Future
184
+ PENDING_STATE = 0
185
+ RESOLVED_STATE = 1
186
+ FAILED_STATE = 2
187
+
188
+ # @since v1.0.0
182
189
  module Factories
183
190
  # Combines multiple futures into a new future which resolves when all
184
191
  # constituent futures complete, or fails when one or more of them fails.
@@ -207,6 +214,33 @@ module Ione
207
214
  end
208
215
  end
209
216
 
217
+ # Combines multiple futures into a new future which resolves when all
218
+ # constituent futures complete, or fails when one or more of them fails.
219
+ #
220
+ # The resulting future has no value.
221
+ #
222
+ # @example
223
+ # future = Future.after(delete_thing(1), delete_thing(2))
224
+ # future.value # => nil
225
+ #
226
+ # @param [Array<Ione::Future>] futures the futures to combine (this argument
227
+ # can be a splatted array or a regular array passed as sole argument)
228
+ # @return [Ione::Future] with a nil value once all futures have succeeded
229
+ # @since v1.3.0
230
+ def after(*futures)
231
+ if futures.size == 1 && (fs = futures.first).is_a?(Enumerable)
232
+ *futures = *fs
233
+ end
234
+ if futures.count == 0
235
+ ResolvedFuture::NIL
236
+ elsif futures.count == 1
237
+ futures.first.map(nil)
238
+ else
239
+ CombinedNilFuture.new(futures)
240
+ end
241
+ end
242
+
243
+
210
244
  # Returns a future which will be resolved with the value of the first
211
245
  # (resolved) of the specified futures. If all of the futures fail, the
212
246
  # returned future will also fail (with the error of the last failed future).
@@ -249,6 +283,7 @@ module Ione
249
283
  # @yieldreturn [Ione::Future] a future
250
284
  # @return [Ione::Future] a future that will resolve to an array of the values
251
285
  # of the futures returned by the block
286
+ # @since v1.2.0
252
287
  def traverse(values, &block)
253
288
  all(values.map(&block))
254
289
  rescue => e
@@ -286,7 +321,8 @@ module Ione
286
321
  #
287
322
  # @param [Array<Ione::Future>] futures an array of futures whose values
288
323
  # should be reduced
289
- # @param [Object] initial_value the initial value of the accumulator
324
+ # @param [Object] initial_value the initial value of the accumulator. When
325
+ # nil (the default) the value of the first future will be used instead.
290
326
  # @param [Hash] options
291
327
  # @option options [Boolean] :ordered (true) whether or not to respect the
292
328
  # order of the input when reducing – when true the block will be called
@@ -302,6 +338,7 @@ module Ione
302
338
  # @return [Ione::Future] a future that will resolve to the value returned
303
339
  # from the last invocation of the block, or nil when the list of futures
304
340
  # is empty.
341
+ # @since v1.2.0
305
342
  def reduce(futures, initial_value=nil, options=nil, &reducer)
306
343
  if options && options[:ordered] == false
307
344
  UnorderedReducingFuture.new(futures, initial_value, reducer)
@@ -328,6 +365,7 @@ module Ione
328
365
  end
329
366
  end
330
367
 
368
+ # @since v1.0.0
331
369
  module Combinators
332
370
  # Returns a new future representing a transformation of this future's value.
333
371
  #
@@ -411,6 +449,7 @@ module Ione
411
449
  # @yieldreturn [Object, Ione::Future] the transformed value, or a future
412
450
  # that will resolve to the transformed value.
413
451
  # @return [Ione::Future] a new future representing the transformed value
452
+ # @since v1.2.0
414
453
  def then(&block)
415
454
  f = CompletableFuture.new
416
455
  on_complete do |v, e|
@@ -519,6 +558,7 @@ module Ione
519
558
  end
520
559
  end
521
560
 
561
+ # @since v1.0.0
522
562
  module Callbacks
523
563
  # Registers a listener that will be called when this future becomes
524
564
  # resolved. The listener will be called with the value of the future as
@@ -549,9 +589,10 @@ module Ione
549
589
  include Combinators
550
590
  include Callbacks
551
591
 
592
+ # @private
552
593
  def initialize
553
594
  @lock = Mutex.new
554
- @state = :pending
595
+ @state = PENDING_STATE
555
596
  @listeners = []
556
597
  end
557
598
 
@@ -595,12 +636,12 @@ module Ione
595
636
  # @see Callbacks#on_failure
596
637
  def on_complete(&listener)
597
638
  run_immediately = false
598
- if @state != :pending
639
+ if @state != PENDING_STATE
599
640
  run_immediately = true
600
641
  else
601
642
  @lock.lock
602
643
  begin
603
- if @state == :pending
644
+ if @state == PENDING_STATE
604
645
  @listeners << listener
605
646
  else
606
647
  run_immediately = true
@@ -634,13 +675,13 @@ module Ione
634
675
  # @see Callbacks#on_failure
635
676
  # @see Callbacks#on_complete
636
677
  def value
637
- raise @error if @state == :failed
638
- return @value if @state == :resolved
678
+ raise @error if @state == FAILED_STATE
679
+ return @value if @state == RESOLVED_STATE
639
680
  semaphore = nil
640
681
  @lock.lock
641
682
  begin
642
- raise @error if @state == :failed
643
- return @value if @state == :resolved
683
+ raise @error if @state == FAILED_STATE
684
+ return @value if @state == RESOLVED_STATE
644
685
  semaphore = Queue.new
645
686
  u = proc { semaphore << :unblock }
646
687
  @listeners << u
@@ -650,8 +691,8 @@ module Ione
650
691
  while true
651
692
  @lock.lock
652
693
  begin
653
- raise @error if @state == :failed
654
- return @value if @state == :resolved
694
+ raise @error if @state == FAILED_STATE
695
+ return @value if @state == RESOLVED_STATE
655
696
  ensure
656
697
  @lock.unlock
657
698
  end
@@ -662,10 +703,10 @@ module Ione
662
703
 
663
704
  # Returns true if this future is resolved or failed
664
705
  def completed?
665
- return true unless @state == :pending
706
+ return true unless @state == PENDING_STATE
666
707
  @lock.lock
667
708
  begin
668
- @state != :pending
709
+ @state != PENDING_STATE
669
710
  ensure
670
711
  @lock.unlock
671
712
  end
@@ -673,10 +714,10 @@ module Ione
673
714
 
674
715
  # Returns true if this future is resolved
675
716
  def resolved?
676
- return @state == :resolved unless @state == :pending
717
+ return @state == RESOLVED_STATE unless @state == PENDING_STATE
677
718
  @lock.lock
678
719
  begin
679
- @state == :resolved
720
+ @state == RESOLVED_STATE
680
721
  ensure
681
722
  @lock.unlock
682
723
  end
@@ -684,10 +725,10 @@ module Ione
684
725
 
685
726
  # Returns true if this future has failed
686
727
  def failed?
687
- return @state == :failed unless @state == :pending
728
+ return @state == FAILED_STATE unless @state == PENDING_STATE
688
729
  @lock.lock
689
730
  begin
690
- @state == :failed
731
+ @state == FAILED_STATE
691
732
  ensure
692
733
  @lock.unlock
693
734
  end
@@ -731,9 +772,9 @@ module Ione
731
772
  listeners = nil
732
773
  @lock.lock
733
774
  begin
734
- raise FutureError, 'Future already completed' unless @state == :pending
775
+ raise FutureError, 'Future already completed' unless @state == PENDING_STATE
735
776
  @value = v
736
- @state = :resolved
777
+ @state = RESOLVED_STATE
737
778
  listeners = @listeners
738
779
  @listeners = nil
739
780
  ensure
@@ -749,9 +790,9 @@ module Ione
749
790
  listeners = nil
750
791
  @lock.lock
751
792
  begin
752
- raise FutureError, 'Future already completed' unless @state == :pending
793
+ raise FutureError, 'Future already completed' unless @state == PENDING_STATE
753
794
  @error = error
754
- @state = :failed
795
+ @state = FAILED_STATE
755
796
  listeners = @listeners
756
797
  @listeners = nil
757
798
  ensure
@@ -793,14 +834,37 @@ module Ione
793
834
  end
794
835
  end
795
836
 
837
+ # @private
838
+ class CombinedNilFuture < CompletableFuture
839
+ def initialize(futures)
840
+ super()
841
+ @futures = futures
842
+ await_next(nil, nil)
843
+ end
844
+
845
+ def await_next(v, e)
846
+ if e
847
+ @futures = nil
848
+ fail(e)
849
+ elsif @futures.empty?
850
+ @futures = nil
851
+ resolve
852
+ else
853
+ @futures.pop.on_complete(&method(:await_next))
854
+ end
855
+ end
856
+ end
857
+
796
858
  # @private
797
859
  class ReducingFuture < CompletableFuture
860
+ NO_INITIAL_VALUE = Object.new
861
+
798
862
  def initialize(futures, initial_value, reducer)
799
863
  super()
800
864
  @futures = Array(futures)
801
865
  @remaining = @futures.size
802
866
  @initial_value = initial_value
803
- @accumulator = initial_value
867
+ @accumulator = initial_value.nil? ? NO_INITIAL_VALUE : initial_value
804
868
  @reducer = reducer
805
869
  end
806
870
 
@@ -810,10 +874,10 @@ module Ione
810
874
  unless failed?
811
875
  @lock.lock
812
876
  begin
813
- if @accumulator
814
- @accumulator = @reducer.call(@accumulator, value)
815
- else
877
+ if @accumulator.equal?(NO_INITIAL_VALUE)
816
878
  @accumulator = value
879
+ else
880
+ @accumulator = @reducer.call(@accumulator, value)
817
881
  end
818
882
  @remaining -= 1
819
883
  rescue => e
@@ -905,7 +969,7 @@ module Ione
905
969
  # @private
906
970
  class ResolvedFuture < Future
907
971
  def initialize(value=nil)
908
- @state = :resolved
972
+ @state = RESOLVED_STATE
909
973
  @value = value
910
974
  @error = nil
911
975
  end
@@ -943,7 +1007,7 @@ module Ione
943
1007
  # @private
944
1008
  class FailedFuture < Future
945
1009
  def initialize(error)
946
- @state = :failed
1010
+ @state = FAILED_STATE
947
1011
  @value = nil
948
1012
  @error = error
949
1013
  end
@@ -3,11 +3,19 @@
3
3
 
4
4
  module Ione
5
5
  module Io
6
+ # An acceptor wraps a server socket and accepts client connections.
7
+ # @since v1.1.0
6
8
  class Acceptor
9
+ # @private
7
10
  ServerSocket = RUBY_ENGINE == 'jruby' ? ::ServerSocket : Socket
8
11
 
12
+ BINDING_STATE = 0
13
+ CONNECTED_STATE = 1
14
+ CLOSED_STATE = 2
15
+
9
16
  attr_reader :backlog
10
17
 
18
+ # @private
11
19
  def initialize(host, port, backlog, unblocker, reactor, socket_impl=nil)
12
20
  @host = host
13
21
  @port = port
@@ -17,15 +25,19 @@ module Ione
17
25
  @socket_impl = socket_impl || ServerSocket
18
26
  @accept_listeners = []
19
27
  @lock = Mutex.new
20
- @state = :binding
28
+ @state = BINDING_STATE
21
29
  end
22
30
 
31
+ # Register a listener to be notified when client connections are accepted
32
+ #
33
+ # @yieldparam [Ione::Io::ServerConnection] the connection to the client
23
34
  def on_accept(&listener)
24
35
  @lock.synchronize do
25
36
  @accept_listeners << listener
26
37
  end
27
38
  end
28
39
 
40
+ # @private
29
41
  def bind
30
42
  addrinfos = @socket_impl.getaddrinfo(@host, @port, nil, Socket::SOCK_STREAM)
31
43
  begin
@@ -39,17 +51,18 @@ module Ione
39
51
  retry
40
52
  end
41
53
  end
42
- @state = :connected
54
+ @state = CONNECTED_STATE
43
55
  Future.resolved(self)
44
56
  rescue => e
45
57
  close
46
58
  Future.failed(e)
47
59
  end
48
60
 
61
+ # Stop accepting connections
49
62
  def close
50
63
  @lock.synchronize do
51
- return false if @state == :closed
52
- @state = :closed
64
+ return false if @state == CLOSED_STATE
65
+ @state = CLOSED_STATE
53
66
  end
54
67
  if @io
55
68
  begin
@@ -63,26 +76,32 @@ module Ione
63
76
  true
64
77
  end
65
78
 
79
+ # @private
66
80
  def to_io
67
81
  @io
68
82
  end
69
83
 
84
+ # Returns true if the acceptor has stopped accepting connections
70
85
  def closed?
71
- @state == :closed
86
+ @state == CLOSED_STATE
72
87
  end
73
88
 
89
+ # Returns true if the acceptor is accepting connections
74
90
  def connected?
75
- @state != :closed
91
+ @state != CLOSED_STATE
76
92
  end
77
93
 
94
+ # @private
78
95
  def connecting?
79
96
  false
80
97
  end
81
98
 
99
+ # @private
82
100
  def writable?
83
101
  false
84
102
  end
85
103
 
104
+ # @private
86
105
  def read
87
106
  client_socket, host, port = accept
88
107
  connection = ServerConnection.new(client_socket, host, port, @unblocker)
@@ -91,10 +110,12 @@ module Ione
91
110
  end
92
111
 
93
112
  if RUBY_ENGINE == 'jruby'
113
+ # @private
94
114
  def bind_socket(socket, addr, backlog)
95
115
  socket.bind(addr, backlog)
96
116
  end
97
117
  else
118
+ # @private
98
119
  def bind_socket(socket, addr, backlog)
99
120
  socket.bind(addr)
100
121
  socket.listen(backlog)
@@ -2,14 +2,21 @@
2
2
 
3
3
  module Ione
4
4
  module Io
5
+ # @since v1.0.0
5
6
  class BaseConnection
7
+ CONNECTING_STATE = 0
8
+ CONNECTED_STATE = 1
9
+ DRAINING_STATE = 2
10
+ CLOSED_STATE = 3
11
+
6
12
  attr_reader :host, :port
7
13
 
14
+ # @private
8
15
  def initialize(host, port, unblocker)
9
16
  @host = host
10
17
  @port = port
11
18
  @unblocker = unblocker
12
- @state = :connecting
19
+ @state = CONNECTING_STATE
13
20
  @writable = false
14
21
  @lock = Mutex.new
15
22
  @write_buffer = ByteBuffer.new
@@ -21,8 +28,8 @@ module Ione
21
28
  # @return [true, false] returns false if the connection was already closed
22
29
  def close(cause=nil)
23
30
  @lock.synchronize do
24
- return false if @state == :closed
25
- @state = :closed
31
+ return false if @state == CLOSED_STATE
32
+ @state = CLOSED_STATE
26
33
  @writable = false
27
34
  end
28
35
  if @io
@@ -50,30 +57,31 @@ module Ione
50
57
  #
51
58
  # @return [Ione::Future] a future that resolves to the connection when it
52
59
  # has closed
60
+ # @since v1.1.0
53
61
  def drain
54
- @state = :draining
62
+ @state = DRAINING_STATE
55
63
  close unless @writable
56
64
  @closed_promise.future
57
65
  end
58
66
 
59
67
  # @private
60
68
  def connecting?
61
- @state == :connecting
69
+ @state == CONNECTING_STATE
62
70
  end
63
71
 
64
72
  # Returns true if the connection is connected
65
73
  def connected?
66
- @state == :connected
74
+ @state == CONNECTED_STATE
67
75
  end
68
76
 
69
77
  # Returns true if the connection is closed
70
78
  def closed?
71
- @state == :closed
79
+ @state == CLOSED_STATE
72
80
  end
73
81
 
74
82
  # @private
75
83
  def writable?
76
- @writable && @state != :closed
84
+ @writable && @state != CLOSED_STATE
77
85
  end
78
86
 
79
87
  # Register to receive notifications when new data is read from the socket.
@@ -119,7 +127,7 @@ module Ione
119
127
  # @yieldparam buffer [Ione::ByteBuffer] the connection's internal buffer
120
128
  # @param bytes [String, Ione::ByteBuffer] the data to write to the socket
121
129
  def write(bytes=nil)
122
- if @state == :connected || @state == :connecting
130
+ if @state == CONNECTED_STATE || @state == CONNECTING_STATE
123
131
  @lock.lock
124
132
  begin
125
133
  if block_given?
@@ -137,7 +145,7 @@ module Ione
137
145
 
138
146
  # @private
139
147
  def flush
140
- if @state == :connected || @state == :draining
148
+ if @state == CONNECTED_STATE || @state == DRAINING_STATE
141
149
  @lock.lock
142
150
  begin
143
151
  if @writable
@@ -145,7 +153,7 @@ module Ione
145
153
  @write_buffer.discard(bytes_written)
146
154
  end
147
155
  @writable = !@write_buffer.empty?
148
- if @state == :draining && !@writable
156
+ if @state == DRAINING_STATE && !@writable
149
157
  close
150
158
  end
151
159
  ensure
@@ -158,7 +166,7 @@ module Ione
158
166
 
159
167
  # @private
160
168
  def read
161
- new_data = @io.read_nonblock(2**16)
169
+ new_data = @io.read_nonblock(65536)
162
170
  @data_listener.call(new_data) if @data_listener
163
171
  rescue => e
164
172
  close(e)
@@ -170,7 +178,11 @@ module Ione
170
178
  end
171
179
 
172
180
  def to_s
173
- %(#<#{self.class.name} #{@state} #{@host}:#{@port}>)
181
+ state_constant_name = self.class.constants.find do |name|
182
+ name.to_s.end_with?('_STATE') && self.class.const_get(name) == @state
183
+ end
184
+ state = state_constant_name.to_s.rpartition('_').first
185
+ %(#<#{self.class.name} #{state} #{@host}:#{@port}>)
174
186
  end
175
187
  end
176
188
  end