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/signal.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
4
  class Signal < Handle
3
5
 
@@ -10,6 +12,8 @@ module Libuv
10
12
  :SIGHUP => 1,
11
13
  :INT => 2,
12
14
  :SIGINT => 2,
15
+ :TERM => 15,
16
+ :SIGTERM => 15,
13
17
  :BREAK => 21,
14
18
  :SIGBREAK => 21,
15
19
  :WINCH => 28,
@@ -17,13 +21,13 @@ module Libuv
17
21
  }
18
22
 
19
23
 
20
- # @param loop [::Libuv::Loop] loop this signal handler will be associated
24
+ # @param reactor [::Libuv::Reactor] reactor this signal handler will be associated
21
25
  # @param callback [Proc] callback to be called when the signal is triggered
22
- def initialize(loop)
23
- @loop = loop
26
+ def initialize(reactor)
27
+ @reactor = reactor
24
28
 
25
29
  signal_ptr = ::Libuv::Ext.allocate_handle_signal
26
- error = check_result(::Libuv::Ext.signal_init(loop.handle, signal_ptr))
30
+ error = check_result(::Libuv::Ext.signal_init(reactor.handle, signal_ptr))
27
31
 
28
32
  super(signal_ptr, error)
29
33
  end
@@ -34,6 +38,7 @@ module Libuv
34
38
  signal = SIGNALS[signal] if signal.is_a? Symbol
35
39
  error = check_result ::Libuv::Ext.signal_start(handle, callback(:on_sig), signal)
36
40
  reject(error) if error
41
+ self
37
42
  end
38
43
 
39
44
  # Disables the signal handler.
@@ -41,6 +46,7 @@ module Libuv
41
46
  return if @closed
42
47
  error = check_result ::Libuv::Ext.signal_stop(handle)
43
48
  reject(error) if error
49
+ self
44
50
  end
45
51
 
46
52
 
@@ -48,7 +54,9 @@ module Libuv
48
54
 
49
55
 
50
56
  def on_sig(handle, signal)
51
- defer.notify(signal) # notify of a call
57
+ ::Fiber.new {
58
+ defer.notify(signal) # notify of a call
59
+ }.resume
52
60
  end
53
61
  end
54
62
  end
data/lib/libuv/tcp.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ipaddr'
2
4
  require 'ruby-tls'
3
5
 
@@ -20,11 +22,12 @@ module Libuv
20
22
  def tls?; !@tls.nil?; end
21
23
 
22
24
 
23
- def initialize(loop, acceptor = nil)
24
- @loop = loop
25
+ def initialize(reactor, acceptor = nil, progress: nil)
26
+ @reactor = reactor
27
+ @progress = progress
25
28
 
26
29
  tcp_ptr = ::Libuv::Ext.allocate_handle_tcp
27
- error = check_result(::Libuv::Ext.tcp_init(loop.handle, tcp_ptr))
30
+ error = check_result(::Libuv::Ext.tcp_init(reactor.handle, tcp_ptr))
28
31
 
29
32
  if acceptor && error.nil?
30
33
  error = check_result(::Libuv::Ext.accept(acceptor, tcp_ptr))
@@ -42,7 +45,7 @@ module Libuv
42
45
  # --------------------------------------
43
46
  #
44
47
  def start_tls(args = {})
45
- return unless @connected && @tls.nil?
48
+ return self unless @connected && @tls.nil?
46
49
 
47
50
  args[:verify_peer] = true if @on_verify
48
51
 
@@ -50,6 +53,7 @@ module Libuv
50
53
  @pending_writes = []
51
54
  @tls = ::RubyTls::SSL::Box.new(args[:server], self, args)
52
55
  @tls.start
56
+ self
53
57
  end
54
58
 
55
59
  # Push through any pending writes when handshake has completed
@@ -67,13 +71,14 @@ module Libuv
67
71
  begin
68
72
  @on_handshake.call(self, protocol) if @on_handshake
69
73
  rescue => e
70
- @loop.log :warn, :tls_handshake_callback_error, e
74
+ @reactor.log e, 'performing TLS handshake callback'
71
75
  end
72
76
  end
73
77
 
74
78
  # Provide a callback once the TLS handshake has completed
75
79
  def on_handshake(callback = nil, &blk)
76
80
  @on_handshake = callback || blk
81
+ self
77
82
  end
78
83
 
79
84
  # This is clear text data that has been decrypted
@@ -82,7 +87,7 @@ module Libuv
82
87
  begin
83
88
  @progress.call data, self
84
89
  rescue Exception => e
85
- @loop.log :error, :stream_progress_cb, e
90
+ @reactor.log e, 'performing TLS read data callback'
86
91
  end
87
92
  end
88
93
 
@@ -113,7 +118,7 @@ module Libuv
113
118
  begin
114
119
  return @on_verify.call cert
115
120
  rescue => e
116
- @loop.log :warn, :tls_verify_callback_failed, e
121
+ @reactor.log e, 'performing TLS verify callback'
117
122
  return false
118
123
  end
119
124
  end
@@ -124,12 +129,12 @@ module Libuv
124
129
  # overwrite the default close to ensure
125
130
  # pending writes are rejected
126
131
  def close
127
- return if @closed
132
+ return self if @closed
128
133
 
129
134
  # Free tls memory
130
135
  # Next tick as may recieve data after closing
131
136
  if @tls
132
- @loop.next_tick do
137
+ @reactor.next_tick do
133
138
  @tls.cleanup
134
139
  end
135
140
  end
@@ -148,12 +153,13 @@ module Libuv
148
153
  # Verify peers will be called for each cert in the chain
149
154
  def verify_peer(callback = nil, &blk)
150
155
  @on_verify = callback || blk
156
+ self
151
157
  end
152
158
 
153
159
  alias_method :direct_write, :write
154
- def write(data)
160
+ def write(data, wait: false)
155
161
  if @tls
156
- deferred = @loop.defer
162
+ deferred = @reactor.defer
157
163
 
158
164
  if @handshake
159
165
  @pending_write = deferred
@@ -162,9 +168,14 @@ module Libuv
162
168
  @pending_writes << [deferred, data]
163
169
  end
164
170
 
165
- deferred.promise
171
+ if wait
172
+ return deferred.promise if wait == :promise
173
+ co deferred.promise
174
+ end
175
+
176
+ self
166
177
  else
167
- direct_write(data)
178
+ direct_write(data, wait: wait)
168
179
  end
169
180
  end
170
181
 
@@ -175,6 +186,7 @@ module Libuv
175
186
  else
176
187
  do_shutdown
177
188
  end
189
+ self
178
190
  end
179
191
  #
180
192
  # END TLS Abstraction ------------------
@@ -182,7 +194,8 @@ module Libuv
182
194
  #
183
195
 
184
196
  def bind(ip, port, callback = nil, &blk)
185
- return if @closed
197
+ return self if @closed
198
+
186
199
  @on_accept = callback || blk
187
200
  @on_listen = method(:accept)
188
201
 
@@ -195,22 +208,30 @@ module Libuv
195
208
  rescue Exception => e
196
209
  reject(e)
197
210
  end
211
+
212
+ self
198
213
  end
199
214
 
200
215
  def open(fd, binding = true, callback = nil, &blk)
201
- return if @closed
216
+ return self if @closed
217
+
202
218
  if binding
203
219
  @on_listen = method(:accept)
204
220
  @on_accept = callback || blk
205
221
  else
206
222
  @callback = callback || blk
223
+ @coroutine = @reactor.defer if @callback.nil?
207
224
  end
208
225
  error = check_result UV.tcp_open(handle, fd)
209
226
  reject(error) if error
227
+ co @coroutine.promise if @coroutine
228
+
229
+ self
210
230
  end
211
231
 
212
232
  def connect(ip, port, callback = nil, &blk)
213
- return if @closed
233
+ return self if @closed
234
+
214
235
  @callback = callback || blk
215
236
  assert_type(String, ip, IP_ARGUMENT_ERROR)
216
237
  assert_type(Integer, port, PORT_ARGUMENT_ERROR)
@@ -221,6 +242,13 @@ module Libuv
221
242
  rescue Exception => e
222
243
  reject(e)
223
244
  end
245
+
246
+ if @callback.nil?
247
+ @coroutine = @reactor.defer
248
+ co @coroutine.promise
249
+ end
250
+
251
+ self
224
252
  end
225
253
 
226
254
  def sockname
@@ -238,33 +266,39 @@ module Libuv
238
266
  end
239
267
 
240
268
  def enable_nodelay
241
- return if @closed
269
+ return self if @closed
242
270
  check_result ::Libuv::Ext.tcp_nodelay(handle, 1)
271
+ self
243
272
  end
244
273
 
245
274
  def disable_nodelay
246
- return if @closed
275
+ return self if @closed
247
276
  check_result ::Libuv::Ext.tcp_nodelay(handle, 0)
277
+ self
248
278
  end
249
279
 
250
280
  def enable_keepalive(delay)
251
- return if @closed # The to_i asserts integer
281
+ return self if @closed # The to_i asserts integer
252
282
  check_result ::Libuv::Ext.tcp_keepalive(handle, 1, delay.to_i)
283
+ self
253
284
  end
254
285
 
255
286
  def disable_keepalive
256
- return if @closed
287
+ return self if @closed
257
288
  check_result ::Libuv::Ext.tcp_keepalive(handle, 0, 0)
289
+ self
258
290
  end
259
291
 
260
292
  def enable_simultaneous_accepts
261
- return if @closed
293
+ return self if @closed
262
294
  check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 1)
295
+ self
263
296
  end
264
297
 
265
298
  def disable_simultaneous_accepts
266
- return if @closed
299
+ return self if @closed
267
300
  check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 0)
301
+ self
268
302
  end
269
303
 
270
304
 
@@ -273,9 +307,9 @@ module Libuv
273
307
 
274
308
  def create_socket(ip, port)
275
309
  if ip.ipv4?
276
- Socket4.new(loop, handle, ip.to_s, port)
310
+ Socket4.new(reactor, handle, ip.to_s, port)
277
311
  else
278
- Socket6.new(loop, handle, ip.to_s, port)
312
+ Socket6.new(reactor, handle, ip.to_s, port)
279
313
  end
280
314
  end
281
315
 
@@ -284,30 +318,43 @@ module Libuv
284
318
  ::Libuv::Ext.free(req)
285
319
  e = check_result(status)
286
320
 
287
- if e
288
- reject(e)
289
- else
290
- @connected = true
291
-
292
- begin
293
- @callback.call(self)
294
- rescue Exception => e
295
- @loop.log :error, :connect_cb, e
321
+ ::Fiber.new {
322
+ if e
323
+ reject(e)
324
+ else
325
+ @connected = true
326
+
327
+ begin
328
+ if @callback
329
+ @callback.call(self)
330
+ @callback = nil
331
+ elsif @coroutine
332
+ @coroutine.resolve(nil)
333
+ @coroutine = nil
334
+ else
335
+ raise ArgumentError, 'no callback provided'
336
+ end
337
+ rescue Exception => e
338
+ @reactor.log e, 'performing TCP connection callback'
339
+ end
296
340
  end
297
- end
341
+ }.resume
298
342
  end
299
343
 
300
344
  def accept(_)
301
345
  begin
302
346
  raise RuntimeError, CLOSED_HANDLE_ERROR if @closed
303
- tcp = TCP.new(loop, handle)
304
- begin
305
- @on_accept.call(tcp)
306
- rescue Exception => e
307
- @loop.log :error, :tcp_accept_cb, e
308
- end
347
+ tcp = TCP.new(reactor, handle)
348
+
349
+ ::Fiber.new {
350
+ begin
351
+ @on_accept.call(tcp)
352
+ rescue Exception => e
353
+ @reactor.log e, 'performing TCP accept callback'
354
+ end
355
+ }.resume
309
356
  rescue Exception => e
310
- @loop.log :info, :tcp_accept_failed, e
357
+ @reactor.log e, 'failed to accept TCP connection'
311
358
  end
312
359
  end
313
360
 
@@ -315,21 +362,24 @@ module Libuv
315
362
  class SocketBase
316
363
  include Resource
317
364
 
318
- def initialize(loop, tcp, ip, port)
319
- @tcp, @sockaddr = tcp, ip_addr(ip, port)
320
- @loop = loop
365
+ def initialize(reactor, tcp, ip, port)
366
+ @ip = ip
367
+ @port = port
368
+ @tcp = tcp
369
+ @reactor = reactor
370
+ @req = ::Libuv::Ext.allocate_request_connect
321
371
  end
322
372
 
323
373
  def bind
324
- check_result!(tcp_bind)
374
+ check_result! ::Libuv::Ext.tcp_bind(@tcp, ip_addr, 0)
325
375
  end
326
376
 
327
377
  def connect(callback)
328
- check_result!(tcp_connect(callback))
378
+ @callback = callback
379
+ check_result!(tcp_connect)
329
380
  end
330
381
 
331
382
  def connect_req
332
- @req ||= ::Libuv::Ext.allocate_request_connect
333
383
  @req
334
384
  end
335
385
 
@@ -337,18 +387,14 @@ module Libuv
337
387
  protected
338
388
 
339
389
 
340
- def tcp_connect(callback)
390
+ def tcp_connect
341
391
  ::Libuv::Ext.tcp_connect(
342
- connect_req,
392
+ @req,
343
393
  @tcp,
344
- @sockaddr,
345
- callback
394
+ ip_addr,
395
+ @callback
346
396
  )
347
397
  end
348
-
349
- def tcp_bind
350
- ::Libuv::Ext.tcp_bind(@tcp, @sockaddr, 0)
351
- end
352
398
  end
353
399
 
354
400
 
@@ -356,10 +402,10 @@ module Libuv
356
402
  protected
357
403
 
358
404
 
359
- def ip_addr(ip, port)
360
- addr = Ext::SockaddrIn.new
361
- check_result! ::Libuv::Ext.ip4_addr(ip, port, addr)
362
- addr
405
+ def ip_addr
406
+ @sockaddr = Ext::SockaddrIn.new
407
+ check_result! ::Libuv::Ext.ip4_addr(@ip, @port, @sockaddr)
408
+ @sockaddr
363
409
  end
364
410
  end
365
411
 
@@ -368,10 +414,10 @@ module Libuv
368
414
  protected
369
415
 
370
416
 
371
- def ip_addr(ip, port)
372
- addr = Ext::SockaddrIn6.new
373
- check_result! ::Libuv::Ext.ip6_addr(ip, port, addr)
374
- addr
417
+ def ip_addr
418
+ @sockaddr = Ext::SockaddrIn6.new
419
+ check_result! ::Libuv::Ext.ip6_addr(@ip, @port, @sockaddr)
420
+ @sockaddr
375
421
  end
376
422
  end
377
423
  end
data/lib/libuv/timer.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
4
  class Timer < Handle
3
5
 
@@ -5,13 +7,14 @@ module Libuv
5
7
  define_callback function: :on_timer
6
8
 
7
9
 
8
- # @param loop [::Libuv::Loop] loop this timer will be associated
10
+ # @param reactor [::Libuv::Reactor] reactor this timer will be associated
9
11
  # @param callback [Proc] callback to be called when the timer is triggered
10
- def initialize(loop, callback = nil)
11
- @loop, @callback = loop, callback
12
+ def initialize(reactor, callback = nil, &blk)
13
+ @reactor = reactor
14
+ @callback = callback || blk
12
15
 
13
16
  timer_ptr = ::Libuv::Ext.allocate_handle_timer
14
- error = check_result(::Libuv::Ext.timer_init(loop.handle, timer_ptr))
17
+ error = check_result(::Libuv::Ext.timer_init(reactor.handle, timer_ptr))
15
18
  @stopped = true
16
19
 
17
20
  super(timer_ptr, error)
@@ -19,22 +22,21 @@ module Libuv
19
22
 
20
23
  # Enables the timer. A repeat of 0 means no repeat
21
24
  #
22
- # @param timeout [Fixnum] time in milliseconds before the timer callback is triggered the first time
23
- # @param repeat [Fixnum] time in milliseconds between repeated callbacks after the first
25
+ # @param timeout [Integer|Fixnum] time in milliseconds before the timer callback is triggered the first time
26
+ # @param repeat [Integer|Fixnum] time in milliseconds between repeated callbacks after the first
24
27
  def start(timeout, repeat = 0)
25
28
  return if @closed
26
29
  @stopped = false
27
30
 
28
31
  # prevent timeouts less than 0 (very long time otherwise as cast to an unsigned)
29
32
  # and you probably don't want to wait a few lifetimes
30
- timeout = 0 if timeout < 0
31
-
32
33
  timeout = timeout.to_i
33
- repeat = repeat.to_i
34
+ timeout = 0 if timeout < 0
34
35
 
35
- @loop.update_time
36
- error = check_result ::Libuv::Ext.timer_start(handle, callback(:on_timer), timeout, repeat)
36
+ error = check_result ::Libuv::Ext.timer_start(handle, callback(:on_timer), timeout, repeat.to_i)
37
37
  reject(error) if error
38
+
39
+ self
38
40
  end
39
41
 
40
42
  # Disables the timer.
@@ -43,28 +45,42 @@ module Libuv
43
45
  @stopped = true
44
46
  error = check_result ::Libuv::Ext.timer_stop(handle)
45
47
  reject(error) if error
48
+
49
+ self
46
50
  end
47
51
 
48
52
  # Resets the current repeat
49
53
  def again
50
54
  return if @closed
51
- @loop.update_time
52
55
  error = check_result ::Libuv::Ext.timer_again(handle)
53
56
  reject(error) if error
57
+
58
+ self
54
59
  end
55
60
 
56
- # Updates the repeat timeout
57
- def repeat=(repeat)
61
+ # Set the current repeat timeout
62
+ # Repeat is the time in milliseconds between repeated callbacks after the initial timeout fires
63
+ #
64
+ # @param time [Integer|Fixnum] time in milliseconds between repeated callbacks after the first
65
+ def repeat=(time)
58
66
  return if @closed
59
- repeat = repeat.to_i
60
- error = check_result ::Libuv::Ext.timer_set_repeat(handle, repeat)
67
+ error = check_result ::Libuv::Ext.timer_set_repeat(handle, time.to_i)
61
68
  reject(error) if error
69
+ time
62
70
  end
63
71
 
64
- # Returns the current repeat timeout
65
- def repeat
72
+ # Set or gets the current repeat timeout
73
+ # Repeat is the time in milliseconds between repeated callbacks after the initial timeout fires
74
+ #
75
+ # @param times [Integer|Fixnum] time in milliseconds between repeated callbacks after the first
76
+ def repeat(time = nil)
66
77
  return if @closed
67
- ::Libuv::Ext.timer_get_repeat(handle)
78
+ if time.nil?
79
+ ::Libuv::Ext.timer_get_repeat(handle)
80
+ else
81
+ self.repeat = time
82
+ self
83
+ end
68
84
  end
69
85
 
70
86
  # Used to update the callback to be triggered by the timer
@@ -72,6 +88,8 @@ module Libuv
72
88
  # @param callback [Proc] the callback to be called by the timer
73
89
  def progress(callback = nil, &blk)
74
90
  @callback = callback || blk
91
+
92
+ self
75
93
  end
76
94
 
77
95
 
@@ -79,11 +97,13 @@ module Libuv
79
97
 
80
98
 
81
99
  def on_timer(handle)
82
- begin
83
- @callback.call
84
- rescue Exception => e
85
- @loop.log :error, :timer_cb, e
86
- end
100
+ ::Fiber.new {
101
+ begin
102
+ @callback.call
103
+ rescue Exception => e
104
+ @reactor.log e, 'performing timer callback'
105
+ end
106
+ }.resume
87
107
  end
88
108
  end
89
109
  end