libuv 2.0.12 → 3.0.0

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 (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