libuv 2.0.12 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +67 -34
  4. data/lib/libuv.rb +30 -5
  5. data/lib/libuv/async.rb +16 -10
  6. data/lib/libuv/check.rb +19 -12
  7. data/lib/libuv/coroutines.rb +39 -12
  8. data/lib/libuv/dns.rb +25 -18
  9. data/lib/libuv/error.rb +2 -0
  10. data/lib/libuv/ext/ext.rb +28 -36
  11. data/lib/libuv/ext/platform/darwin_x64.rb +2 -0
  12. data/lib/libuv/ext/platform/unix.rb +2 -0
  13. data/lib/libuv/ext/platform/windows.rb +2 -0
  14. data/lib/libuv/ext/tasks.rb +2 -0
  15. data/lib/libuv/ext/tasks/mac.rb +2 -0
  16. data/lib/libuv/ext/tasks/unix.rb +2 -0
  17. data/lib/libuv/ext/tasks/win.rb +2 -0
  18. data/lib/libuv/ext/types.rb +2 -1
  19. data/lib/libuv/file.rb +67 -50
  20. data/lib/libuv/filesystem.rb +63 -61
  21. data/lib/libuv/fs_event.rb +7 -4
  22. data/lib/libuv/handle.rb +30 -14
  23. data/lib/libuv/idle.rb +17 -10
  24. data/lib/libuv/mixins/accessors.rb +41 -0
  25. data/lib/libuv/mixins/assertions.rb +3 -1
  26. data/lib/libuv/mixins/fs_checks.rb +29 -6
  27. data/lib/libuv/mixins/listener.rb +4 -2
  28. data/lib/libuv/mixins/net.rb +4 -2
  29. data/lib/libuv/mixins/resource.rb +5 -3
  30. data/lib/libuv/mixins/stream.rb +128 -35
  31. data/lib/libuv/pipe.rb +54 -27
  32. data/lib/libuv/prepare.rb +19 -12
  33. data/lib/libuv/q.rb +109 -101
  34. data/lib/libuv/{loop.rb → reactor.rb} +163 -85
  35. data/lib/libuv/signal.rb +13 -5
  36. data/lib/libuv/tcp.rb +109 -63
  37. data/lib/libuv/timer.rb +44 -24
  38. data/lib/libuv/tty.rb +8 -3
  39. data/lib/libuv/udp.rb +49 -22
  40. data/lib/libuv/version.rb +3 -1
  41. data/lib/libuv/work.rb +14 -10
  42. data/libuv.gemspec +11 -9
  43. data/spec/async_spec.rb +13 -13
  44. data/spec/coroutines_spec.rb +20 -50
  45. data/spec/defer_spec.rb +182 -311
  46. data/spec/dns_spec.rb +51 -41
  47. data/spec/dsl_spec.rb +43 -0
  48. data/spec/filesystem_spec.rb +65 -87
  49. data/spec/idle_spec.rb +19 -33
  50. data/spec/pipe_spec.rb +25 -32
  51. data/spec/tcp_spec.rb +116 -53
  52. data/spec/timer_spec.rb +3 -3
  53. data/spec/udp_spec.rb +16 -17
  54. data/spec/zen_spec.rb +2 -3
  55. metadata +37 -30
data/lib/libuv/prepare.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
4
  class Prepare < Handle
3
5
 
@@ -5,14 +7,14 @@ module Libuv
5
7
  define_callback function: :on_prepare
6
8
 
7
9
 
8
- # @param loop [::Libuv::Loop] loop this prepare handle will be associated
9
- # @param callback [Proc] callback to be called on loop preparation
10
- def initialize(loop, callback = nil, &blk)
11
- @loop = loop
10
+ # @param reactor [::Libuv::Reactor] reactor this prepare handle will be associated
11
+ # @param callback [Proc] callback to be called on reactor preparation
12
+ def initialize(reactor, callback = nil, &blk)
13
+ @reactor = reactor
12
14
  @callback = callback || blk
13
15
 
14
16
  prepare_ptr = ::Libuv::Ext.allocate_handle_prepare
15
- error = check_result(::Libuv::Ext.prepare_init(loop.handle, prepare_ptr))
17
+ error = check_result(::Libuv::Ext.prepare_init(reactor.handle, prepare_ptr))
16
18
 
17
19
  super(prepare_ptr, error)
18
20
  end
@@ -22,6 +24,7 @@ module Libuv
22
24
  return if @closed
23
25
  error = check_result ::Libuv::Ext.prepare_start(handle, callback(:on_prepare))
24
26
  reject(error) if error
27
+ self
25
28
  end
26
29
 
27
30
  # Disables the prepare handler.
@@ -29,13 +32,15 @@ module Libuv
29
32
  return if @closed
30
33
  error = check_result ::Libuv::Ext.prepare_stop(handle)
31
34
  reject(error) if error
35
+ self
32
36
  end
33
37
 
34
- # Used to update the callback that will be triggered on loop prepare
38
+ # Used to update the callback that will be triggered on reactor prepare
35
39
  #
36
- # @param callback [Proc] the callback to be called on loop prepare
40
+ # @param callback [Proc] the callback to be called on reactor prepare
37
41
  def progress(callback = nil, &blk)
38
42
  @callback = callback || blk
43
+ self
39
44
  end
40
45
 
41
46
 
@@ -43,11 +48,13 @@ module Libuv
43
48
 
44
49
 
45
50
  def on_prepare(handle)
46
- begin
47
- @callback.call
48
- rescue Exception => e
49
- @loop.log :error, :prepare_cb, e
50
- end
51
+ ::Fiber.new {
52
+ begin
53
+ @callback.call
54
+ rescue Exception => e
55
+ @reactor.log e, 'performing prepare callback'
56
+ end
57
+ }.resume
51
58
  end
52
59
  end
53
60
  end
data/lib/libuv/q.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module Libuv
3
4
  module Q
@@ -9,10 +10,12 @@ module Libuv
9
10
  # This allows subclasses to make use of the catch feature
10
11
  alias_method :ruby_catch, :catch
11
12
 
13
+ # Allows a backtrace to be included in any errors
14
+ attr_accessor :trace
12
15
 
13
16
  # Used by finally method
14
- MAKE_PROMISE = proc { |value, resolved, loop|
15
- result = Q.defer(loop)
17
+ MAKE_PROMISE = proc { |value, resolved, reactor|
18
+ result = Q.defer(reactor)
16
19
  if (resolved)
17
20
  result.resolve(value)
18
21
  else
@@ -37,6 +40,10 @@ module Libuv
37
40
  self.then(nil, nil, callback || blk)
38
41
  end
39
42
 
43
+ # A future that provides the value or raises an error if a rejection occurs
44
+ def value
45
+ co self
46
+ end
40
47
 
41
48
  #
42
49
  # allows you to observe either the fulfillment or rejection of a promise, but to do so
@@ -53,18 +60,18 @@ module Libuv
53
60
  begin
54
61
  callbackOutput = callback.call
55
62
  rescue Exception => e
56
- @loop.log(:error, :q_finally_cb, e)
57
- return MAKE_PROMISE.call(e, false, @loop)
63
+ @reactor.log e, 'performing promise finally callback', @trace
64
+ return MAKE_PROMISE.call(e, false, @reactor)
58
65
  end
59
66
 
60
67
  if callbackOutput.is_a?(Promise)
61
68
  return callbackOutput.then(proc {
62
- MAKE_PROMISE.call(value, isResolved, @loop)
69
+ MAKE_PROMISE.call(value, isResolved, @reactor)
63
70
  }, proc { |err|
64
- MAKE_PROMISE.call(err, false, @loop)
71
+ MAKE_PROMISE.call(err, false, @reactor)
65
72
  })
66
73
  else
67
- return MAKE_PROMISE.call(value, isResolved, @loop)
74
+ return MAKE_PROMISE.call(value, isResolved, @reactor)
68
75
  end
69
76
  }
70
77
 
@@ -84,11 +91,11 @@ module Libuv
84
91
  class DeferredPromise < Promise
85
92
  public_class_method :new
86
93
 
87
- def initialize(loop, defer)
94
+ def initialize(reactor, defer)
88
95
  raise ArgumentError unless defer.is_a?(Deferred)
89
96
  super()
90
97
 
91
- @loop = loop
98
+ @reactor = reactor
92
99
  @defer = defer
93
100
  end
94
101
 
@@ -100,7 +107,7 @@ module Libuv
100
107
  # @param [Proc, Proc, Proc, &blk] callbacks error, success, progress, success_block
101
108
  # @return [Promise] Returns an unresolved promise for chaining
102
109
  def then(callback = nil, errback = nil, progback = nil, &blk)
103
- result = Q.defer(@loop)
110
+ result = Q.defer(@reactor)
104
111
 
105
112
  callback ||= blk
106
113
 
@@ -108,19 +115,17 @@ module Libuv
108
115
  begin
109
116
  result.resolve(callback.nil? ? val : callback.call(val))
110
117
  rescue Exception => e
111
- #warn "\nUnhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
112
118
  result.reject(e)
113
- @loop.log(:error, :q_resolve_cb, e)
119
+ @reactor.log e, 'performing promise resolution callback', @trace
114
120
  end
115
121
  }
116
122
 
117
123
  wrappedErrback = proc { |reason|
118
124
  begin
119
- result.resolve(errback.nil? ? Q.reject(@loop, reason) : errback.call(reason))
125
+ result.resolve(errback.nil? ? Q.reject(@reactor, reason) : errback.call(reason))
120
126
  rescue Exception => e
121
- #warn "Unhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
122
127
  result.reject(e)
123
- @loop.log(:error, :q_reject_cb, e)
128
+ @reactor.log e, 'performing promise rejection callback', @trace
124
129
  end
125
130
  }
126
131
 
@@ -128,8 +133,7 @@ module Libuv
128
133
  begin
129
134
  result.notify(progback.nil? ? progress : progback.call(*progress))
130
135
  rescue Exception => e
131
- #warn "Unhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
132
- @loop.log(:error, :q_progress_cb, e)
136
+ @reactor.log e, 'performing promise progress callback', @trace
133
137
  end
134
138
  }
135
139
 
@@ -137,11 +141,11 @@ module Libuv
137
141
  # Schedule as we are touching shared state
138
142
  # Everything else is locally scoped
139
143
  #
140
- @loop.schedule do
144
+ @reactor.schedule do
141
145
  pending_array = pending
142
146
 
143
147
  if pending_array.nil?
144
- value.then(wrappedCallback, wrappedErrback, wrappedProgback)
148
+ reference.then(wrappedCallback, wrappedErrback, wrappedProgback)
145
149
  else
146
150
  pending_array << [wrappedCallback, wrappedErrback, wrappedProgback]
147
151
  end
@@ -153,59 +157,57 @@ module Libuv
153
157
  def resolved?
154
158
  pending.nil?
155
159
  end
156
-
157
-
160
+
161
+
158
162
  private
159
-
160
-
163
+
164
+
161
165
  def pending
162
166
  @defer.pending
163
167
  end
164
168
 
165
- def value
166
- @defer.value
169
+ def reference
170
+ @defer.reference
167
171
  end
168
172
  end
169
-
170
-
171
-
173
+
174
+
175
+
172
176
  class ResolvedPromise < Promise
173
177
  public_class_method :new
174
-
175
- def initialize(loop, response, error = false)
178
+
179
+ def initialize(reactor, response, error = false)
176
180
  raise ArgumentError if error && response.is_a?(Promise)
177
181
  super()
178
-
179
- @loop = loop
182
+
183
+ @reactor = reactor
180
184
  @error = error
181
185
  @response = response
182
186
  end
183
-
187
+
184
188
  def then(callback = nil, errback = nil, progback = nil, &blk)
185
- result = Q.defer(@loop)
186
-
189
+ result = Q.defer(@reactor)
190
+
187
191
  callback ||= blk
188
-
189
- @loop.next_tick {
192
+
193
+ @reactor.next_tick {
190
194
  if @error
191
195
  begin
192
- result.resolve(errback.nil? ? Q.reject(@loop, @response) : errback.call(@response))
196
+ result.resolve(errback.nil? ? Q.reject(@reactor, @response) : errback.call(@response))
193
197
  rescue Exception => e
194
- #warn "Unhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
195
198
  result.reject(e)
196
- @loop.log(:error, :q_reject_cb, e)
199
+ @reactor.log e, 'performing promise rejection callback', @trace
197
200
  end
198
201
  else
199
202
  begin
200
203
  result.resolve(callback.nil? ? @response : callback.call(@response))
201
204
  rescue Exception => e
202
- #warn "\nUnhandled exception: #{e.message}\n#{e.backtrace.join("\n")}\n"
203
205
  result.reject(e)
204
- @loop.log(:error, :q_resolve_cb, e)
206
+ @reactor.log e, 'performing promise resolution callback', @trace
205
207
  end
206
208
  end
207
209
  }
208
-
210
+
209
211
  result.promise
210
212
  end
211
213
 
@@ -213,60 +215,61 @@ module Libuv
213
215
  true
214
216
  end
215
217
  end
216
-
217
-
218
+
219
+
218
220
  #
219
221
  # The purpose of the deferred object is to expose the associated Promise instance as well
220
222
  # as APIs that can be used for signalling the successful or unsuccessful completion of a task.
221
223
  #
222
224
  class Deferred
223
225
  include Q
224
-
225
- def initialize(loop)
226
+
227
+ def initialize(reactor)
226
228
  super()
227
-
229
+
228
230
  @pending = []
229
- @value = nil
230
- @loop = loop
231
+ @reference = nil
232
+ @reactor = reactor
231
233
  end
232
234
 
233
- attr_reader :pending, :value
234
-
235
+ attr_reader :pending, :reference
236
+
235
237
  #
236
238
  # resolves the derived promise with the value. If the value is a rejection constructed via
237
239
  # Q.reject, the promise will be rejected instead.
238
240
  #
239
241
  # @param [Object] val constant, message or an object representing the result.
240
242
  def resolve(val = nil)
241
- @loop.schedule do
243
+ @reactor.schedule do
242
244
  if not @pending.nil?
243
245
  callbacks = @pending
244
246
  @pending = nil
245
- @value = ref(@loop, val)
247
+ @reference = ref(@reactor, val)
246
248
 
247
249
  if callbacks.length > 0
248
250
  callbacks.each do |callback|
249
- @value.then(callback[0], callback[1], callback[2])
251
+ @reference.then(callback[0], callback[1], callback[2])
250
252
  end
251
253
  end
252
254
  end
253
255
  end
256
+ self
254
257
  end
255
-
258
+
256
259
  #
257
260
  # rejects the derived promise with the reason. This is equivalent to resolving it with a rejection
258
261
  # constructed via Q.reject.
259
262
  #
260
263
  # @param [Object] reason constant, message, exception or an object representing the rejection reason.
261
264
  def reject(reason = nil)
262
- resolve(Q.reject(@loop, reason))
265
+ resolve(Q.reject(@reactor, reason))
263
266
  end
264
-
267
+
265
268
  #
266
269
  # Creates a promise object associated with this deferred
267
270
  #
268
271
  def promise
269
- @promise ||= DeferredPromise.new(@loop, self)
272
+ @promise ||= DeferredPromise.new(@reactor, self)
270
273
  @promise # Should only ever be one per deferred
271
274
  end
272
275
 
@@ -275,46 +278,51 @@ module Libuv
275
278
  #
276
279
  # @param [*Object] data you would like to send down the promise chain.
277
280
  def notify(*args)
278
- @loop.schedule do # just in case we are on a different event loop
281
+ @reactor.schedule do # just in case we are on a different event reactor
279
282
  if @pending && @pending.length > 0
280
283
  callbacks = @pending
281
- @loop.next_tick do
284
+ @reactor.next_tick do
282
285
  callbacks.each do |callback|
283
286
  callback[2].call(*args)
284
287
  end
285
288
  end
286
289
  end
287
290
  end
291
+ self
288
292
  end
289
293
 
290
294
  def resolved?
291
295
  @pending.nil?
292
296
  end
293
297
 
298
+ def value
299
+ co self.promise
300
+ end
301
+
294
302
  # Overwrite to prevent inspecting errors hanging the VM
295
303
  def inspect
296
304
  if @pending.nil?
297
- "#<#{self.class}:0x#{self.__id__.to_s(16)} @loop=#{@loop.inspect} @value=#{@value.inspect}>"
305
+ "#<#{self.class}:0x#{self.__id__.to_s(16)} @reactor=#{@reactor.inspect} @reference=#{@reference.inspect}>"
298
306
  else
299
- "#<#{self.class}:0x#{self.__id__.to_s(16)} @loop=#{@loop.inspect} @pending.count=#{@pending.length}>"
307
+ "#<#{self.class}:0x#{self.__id__.to_s(16)} @reactor=#{@reactor.inspect} @pending.count=#{@pending.length}>"
300
308
  end
301
309
  end
302
310
  end
303
-
304
-
305
-
306
-
307
-
308
-
311
+
312
+
313
+
314
+
315
+
316
+
309
317
  #
310
318
  # Creates a Deferred object which represents a task which will finish in the future.
311
319
  #
312
320
  # @return [Deferred] Returns a new instance of Deferred
313
- def defer(loop)
314
- return Deferred.new(loop)
321
+ def defer(reactor)
322
+ return Deferred.new(reactor)
315
323
  end
316
-
317
-
324
+
325
+
318
326
  #
319
327
  # Creates a promise that is resolved as rejected with the specified reason. This api should be
320
328
  # used to forward rejection in a chain of promises. If you are dealing with the last promise in
@@ -340,7 +348,7 @@ module Libuv
340
348
  # # handle the error and recover
341
349
  # return newPromiseOrValue
342
350
  # end
343
- # return Q.reject(loop, reason)
351
+ # return Q.reject(reactor, reason)
344
352
  # }, lambda {|result|
345
353
  # # success: do something and resolve promiseB with the old or a new result
346
354
  # return result
@@ -348,10 +356,10 @@ module Libuv
348
356
  #
349
357
  # @param [Object] reason constant, message, exception or an object representing the rejection reason.
350
358
  # @return [Promise] Returns a promise that was already resolved as rejected with the reason
351
- def reject(loop, reason = nil)
352
- return ResolvedPromise.new(loop, reason, true) # A resolved failed promise
359
+ def reject(reactor, reason = nil)
360
+ return ResolvedPromise.new(reactor, reason, true) # A resolved failed promise
353
361
  end
354
-
362
+
355
363
  #
356
364
  # Combines multiple promises into a single promise that is resolved when all of the input
357
365
  # promises are resolved.
@@ -361,14 +369,14 @@ module Libuv
361
369
  # each value corresponding to the promise at the same index in the `promises` array. If any of
362
370
  # the promises is resolved with a rejection, this resulting promise will be resolved with the
363
371
  # same rejection.
364
- def all(loop, *promises)
365
- deferred = Q.defer(loop)
372
+ def all(reactor, *promises)
373
+ deferred = Q.defer(reactor)
366
374
  counter = promises.length
367
375
  results = []
368
-
376
+
369
377
  if counter > 0
370
378
  promises.each_index do |index|
371
- ref(loop, promises[index]).then(proc {|result|
379
+ ref(reactor, promises[index]).then(proc {|result|
372
380
  if results[index].nil?
373
381
  results[index] = result
374
382
  counter -= 1
@@ -379,13 +387,13 @@ module Libuv
379
387
  if results[index].nil?
380
388
  deferred.reject(reason)
381
389
  end
382
- Q.reject(@loop, reason) # Don't modify result
390
+ Q.reject(@reactor, reason) # Don't modify result
383
391
  })
384
392
  end
385
393
  else
386
394
  deferred.resolve(results)
387
395
  end
388
-
396
+
389
397
  return deferred.promise
390
398
  end
391
399
 
@@ -396,16 +404,16 @@ module Libuv
396
404
  #
397
405
  # @param [*Promise] Promises a number of promises that will be combined into a single promise
398
406
  # @return [Promise] Returns a single promise
399
- def any(loop, *promises)
400
- deferred = Q.defer(loop)
407
+ def any(reactor, *promises)
408
+ deferred = Q.defer(reactor)
401
409
  if promises.length > 0
402
410
  promises.each_index do |index|
403
- ref(loop, promises[index]).then(proc {|result|
411
+ ref(reactor, promises[index]).then(proc {|result|
404
412
  deferred.resolve(true)
405
413
  result
406
414
  }, proc {|reason|
407
415
  deferred.reject(false)
408
- Q.reject(@loop, reason) # Don't modify result
416
+ Q.reject(@reactor, reason) # Don't modify result
409
417
  })
410
418
  end
411
419
  else
@@ -421,14 +429,14 @@ module Libuv
421
429
  # @param [*Promise] Promises a number of promises that will be combined into a single promise
422
430
  # @return [Promise] Returns a single promise that will be resolved with an array of values,
423
431
  # each [result, wasResolved] value pair corresponding to a at the same index in the `promises` array.
424
- def self.finally(loop, *promises)
425
- deferred = Q.defer(loop)
432
+ def self.finally(reactor, *promises)
433
+ deferred = Q.defer(reactor)
426
434
  counter = promises.length
427
435
  results = []
428
-
436
+
429
437
  if counter > 0
430
438
  promises.each_index do |index|
431
- ref(loop, promises[index]).then(proc {|result|
439
+ ref(reactor, promises[index]).then(proc {|result|
432
440
  if results[index].nil?
433
441
  results[index] = [result, true]
434
442
  counter -= 1
@@ -441,26 +449,26 @@ module Libuv
441
449
  counter -= 1
442
450
  deferred.resolve(results) if counter <= 0
443
451
  end
444
- Q.reject(@loop, reason) # Don't modify result
452
+ Q.reject(@reactor, reason) # Don't modify result
445
453
  })
446
454
  end
447
455
  else
448
456
  deferred.resolve(results)
449
457
  end
450
-
458
+
451
459
  return deferred.promise
452
460
  end
453
-
454
-
461
+
462
+
455
463
  private
456
-
457
-
458
- def ref(loop, value)
464
+
465
+
466
+ def ref(reactor, value)
459
467
  return value if value.is_a?(Promise)
460
- return ResolvedPromise.new(loop, value) # A resolved success promise
468
+ return ResolvedPromise.new(reactor, value) # A resolved success promise
461
469
  end
462
-
463
-
470
+
471
+
464
472
  module_function :all, :reject, :defer, :ref, :any
465
473
  private_class_method :ref
466
474
  end