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/tty.rb CHANGED
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
4
  class TTY < Handle
3
5
  include Stream
4
6
 
5
7
 
6
- def initialize(loop, fileno, readable)
7
- @loop = loop
8
+ def initialize(reactor, fileno, readable)
9
+ @reactor = reactor
8
10
 
9
11
  tty_ptr = ::Libuv::Ext.allocate_handle_tty
10
- error = check_result(::Libuv::Ext.tty_init(loop.handle, tty_ptr, fileno, readable ? 1 : 0))
12
+ error = check_result(::Libuv::Ext.tty_init(reactor.handle, tty_ptr, fileno, readable ? 1 : 0))
11
13
 
12
14
  super(tty_ptr, error)
13
15
  end
@@ -15,15 +17,18 @@ module Libuv
15
17
  def enable_raw_mode
16
18
  return if @closed
17
19
  check_result ::Libuv::Ext.tty_set_mode(handle, 1)
20
+ self
18
21
  end
19
22
 
20
23
  def disable_raw_mode
21
24
  return if @closed
22
25
  check_result ::Libuv::Ext.tty_set_mode(handle, 0)
26
+ self
23
27
  end
24
28
 
25
29
  def reset_mode
26
30
  ::Libuv::Ext.tty_reset_mode
31
+ self
27
32
  end
28
33
 
29
34
  def winsize
data/lib/libuv/udp.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ipaddr'
2
4
 
3
5
 
@@ -11,18 +13,19 @@ module Libuv
11
13
  define_callback function: :send_complete, params: [:pointer, :int]
12
14
 
13
15
 
14
- SEND_DATA_ERROR = "data must be a String".freeze
15
- TTL_ARGUMENT_ERROR = "ttl must be an Integer".freeze
16
- MULTICAST_ARGUMENT_ERROR = "multicast_address must be a String".freeze
17
- INTERFACE_ARGUMENT_ERROR = "interface_address must be a String".freeze
18
- HANDLE_CLOSED_ERROR = "unable to send as handle closed".freeze
16
+ SEND_DATA_ERROR = "data must be a String"
17
+ TTL_ARGUMENT_ERROR = "ttl must be an Integer"
18
+ MULTICAST_ARGUMENT_ERROR = "multicast_address must be a String"
19
+ INTERFACE_ARGUMENT_ERROR = "interface_address must be a String"
20
+ HANDLE_CLOSED_ERROR = "unable to send as handle closed"
19
21
 
20
22
 
21
- def initialize(loop)
22
- @loop = loop
23
+ def initialize(reactor, progress: nil)
24
+ @reactor = reactor
25
+ @progress = progress
23
26
 
24
27
  udp_ptr = ::Libuv::Ext.allocate_handle_udp
25
- error = check_result(::Libuv::Ext.udp_init(loop.handle, udp_ptr))
28
+ error = check_result(::Libuv::Ext.udp_init(reactor.handle, udp_ptr))
26
29
  @request_refs = {}
27
30
 
28
31
  super(udp_ptr, error)
@@ -36,12 +39,16 @@ module Libuv
36
39
  sockaddr = create_sockaddr(ip, port)
37
40
  error = check_result ::Libuv::Ext.udp_bind(handle, sockaddr, 0)
38
41
  reject(error) if error
42
+
43
+ self
39
44
  end
40
45
 
41
46
  def open(fd, binding = true, callback = nil, &blk)
42
47
  return if @closed
43
48
  error = check_result UV.udp_open(handle, fd)
44
49
  reject(error) if error
50
+
51
+ self
45
52
  end
46
53
 
47
54
  def sockname
@@ -58,6 +65,7 @@ module Libuv
58
65
 
59
66
  error = check_result ::Libuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_join_group)
60
67
  reject(error) if error
68
+ self
61
69
  end
62
70
 
63
71
  def leave(multicast_address, interface_address)
@@ -67,6 +75,7 @@ module Libuv
67
75
 
68
76
  error = check_result ::Libuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_leave_group)
69
77
  reject(error) if error
78
+ self
70
79
  end
71
80
 
72
81
  # Starts reading from the handle
@@ -75,6 +84,7 @@ module Libuv
75
84
  return if @closed
76
85
  error = check_result ::Libuv::Ext.udp_recv_start(handle, callback(:on_allocate), callback(:on_recv))
77
86
  reject(error) if error
87
+ self
78
88
  end
79
89
 
80
90
  # Stops reading from the handle
@@ -83,6 +93,7 @@ module Libuv
83
93
  return if @closed
84
94
  error = check_result ::Libuv::Ext.udp_recv_stop(handle)
85
95
  reject(error) if error
96
+ self
86
97
  end
87
98
 
88
99
  def try_send(ip, port, data)
@@ -108,9 +119,9 @@ module Libuv
108
119
  return result
109
120
  end
110
121
 
111
- def send(ip, port, data)
122
+ def send(ip, port, data, wait: false)
112
123
  # NOTE:: Similar to stream.rb -> write
113
- deferred = @loop.defer
124
+ deferred = @reactor.defer
114
125
  if !@closed
115
126
  begin
116
127
  assert_type(String, ip, IP_ARGUMENT_ERROR)
@@ -149,18 +160,27 @@ module Libuv
149
160
  deferred.reject(RuntimeError.new(HANDLE_CLOSED_ERROR))
150
161
  end
151
162
  deferred.promise
163
+
164
+ if wait
165
+ return deferred.promise if wait == :promise
166
+ co deferred.promise
167
+ end
168
+
169
+ self
152
170
  end
153
171
 
154
- def enable_multicast_loop
172
+ def enable_multicast_reactor
155
173
  return if @closed
156
- error = check_result ::Libuv::Ext.udp_set_multicast_loop(handle, 1)
174
+ error = check_result ::Libuv::Ext.udp_set_multicast_reactor(handle, 1)
157
175
  reject(error) if error
176
+ self
158
177
  end
159
178
 
160
- def disable_multicast_loop
179
+ def disable_multicast_reactor
161
180
  return if @closed
162
- error = check_result ::Libuv::Ext.udp_set_multicast_loop(handle, 0)
181
+ error = check_result ::Libuv::Ext.udp_set_multicast_reactor(handle, 0)
163
182
  reject(error) if error
183
+ self
164
184
  end
165
185
 
166
186
  def multicast_ttl=(ttl)
@@ -168,18 +188,21 @@ module Libuv
168
188
  assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
169
189
  error = check_result ::Libuv::Ext.udp_set_multicast_ttl(handle, ttl)
170
190
  reject(error) if error
191
+ self
171
192
  end
172
193
 
173
194
  def enable_broadcast
174
195
  return if @closed
175
196
  error = check_result ::Libuv::Ext.udp_set_broadcast(handle, 1)
176
197
  reject(error) if error
198
+ self
177
199
  end
178
200
 
179
201
  def disable_broadcast
180
202
  return if @closed
181
203
  error = check_result ::Libuv::Ext.udp_set_broadcast(handle, 0)
182
204
  reject(error) if error
205
+ self
183
206
  end
184
207
 
185
208
  def ttl=(ttl)
@@ -187,10 +210,12 @@ module Libuv
187
210
  assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
188
211
  error = check_result ::Libuv::Ext.udp_set_ttl(handle, Integer(ttl))
189
212
  reject(error) if error
213
+ self
190
214
  end
191
215
 
192
216
  def progress(callback = nil, &blk)
193
217
  @progress = callback || blk
218
+ self
194
219
  end
195
220
 
196
221
 
@@ -239,18 +264,20 @@ module Libuv
239
264
  e = check_result(nread)
240
265
 
241
266
  if e
242
- reject(e) # Will call close
267
+ ::Fiber.new { reject(e) }.resume # Will call close
243
268
  elsif nread > 0
244
269
  data = @receive_buff.read_string(nread)
245
270
  unless sockaddr.null?
246
271
  ip, port = get_ip_and_port(sockaddr)
247
272
  end
248
-
249
- begin
250
- @progress.call data, ip, port, self
251
- rescue Exception => e
252
- @loop.log :error, :udp_progress_cb, e
253
- end
273
+
274
+ ::Fiber.new {
275
+ begin
276
+ @progress.call data, ip, port, self
277
+ rescue Exception => e
278
+ @reactor.log e, 'performing UDP data received callback'
279
+ end
280
+ }.resume
254
281
  else
255
282
  ::Libuv::Ext.free(@receive_buff)
256
283
  @receive_buff = nil
@@ -265,7 +292,7 @@ module Libuv
265
292
  ::Libuv::Ext.free(req)
266
293
  buffer1.free
267
294
 
268
- resolve deferred, status
295
+ ::Fiber.new { resolve deferred, status }.resume
269
296
  end
270
297
  end
271
298
  end
data/lib/libuv/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
- VERSION = '2.0.12'
4
+ VERSION = '3.0.0'
3
5
  end
data/lib/libuv/work.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Libuv
2
4
  class Work < Q::DeferredPromise
3
5
  include Resource, Listener
@@ -11,7 +13,7 @@ module Libuv
11
13
  define_callback function: :on_complete, params: [:pointer, :int]
12
14
 
13
15
 
14
- # @param thread [::Libuv::Loop] thread this work request will be associated
16
+ # @param thread [::Libuv::Reactor] thread this work request will be associated
15
17
  # @param work [Proc] callback to be called in the thread pool
16
18
  def initialize(thread, work)
17
19
  super(thread, thread.defer)
@@ -23,7 +25,7 @@ module Libuv
23
25
 
24
26
  @instance_id = @pointer.address
25
27
 
26
- error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
28
+ error = check_result ::Libuv::Ext.queue_work(@reactor, @pointer, callback(:on_work), callback(:on_complete))
27
29
  if error
28
30
  ::Libuv::Ext.free(@pointer)
29
31
  @complete = true
@@ -56,16 +58,18 @@ module Libuv
56
58
  @complete = true
57
59
  ::Libuv::Ext.free(req)
58
60
 
59
- e = check_result(status)
60
- if e
61
- @defer.reject(e)
62
- else
63
- if @error
64
- @defer.reject(@error)
61
+ ::Fiber.new {
62
+ e = check_result(status)
63
+ if e
64
+ @defer.reject(e)
65
65
  else
66
- @defer.resolve(@result)
66
+ if @error
67
+ @defer.reject(@error)
68
+ else
69
+ @defer.resolve(@result)
70
+ end
67
71
  end
68
- end
72
+ }.resume
69
73
 
70
74
  # Clean up references
71
75
  cleanup_callbacks @instance_id
data/libuv.gemspec CHANGED
@@ -1,27 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path("../lib/libuv/version", __FILE__)
2
4
 
3
5
  Gem::Specification.new do |gem|
4
6
  gem.name = "libuv"
5
7
  gem.version = Libuv::VERSION
6
8
  gem.license = 'MIT'
7
- gem.authors = ["Bulat Shakirzyanov", "Stephen von Takach"]
8
- gem.email = ["mallluhuct@gmail.com", "steve@cotag.me"]
9
+ gem.authors = ["Stephen von Takach"]
10
+ gem.email = ["steve@cotag.me"]
9
11
  gem.homepage = "https://github.com/cotag/libuv"
10
12
  gem.summary = "libuv bindings for Ruby"
11
13
  gem.description = "An opinionated wrapper around libuv for Ruby"
12
14
 
13
15
  gem.extensions << "ext/Rakefile"
14
16
 
15
- gem.required_ruby_version = '>= 1.9.2'
17
+ gem.required_ruby_version = '>= 2.0.0'
16
18
  gem.require_paths = ["lib"]
17
19
 
18
- gem.add_runtime_dependency 'ffi', '>= 1.9'
19
- gem.add_runtime_dependency 'thread_safe'
20
- gem.add_runtime_dependency 'ruby-tls', '>= 2.0.0'
20
+ gem.add_runtime_dependency 'ffi', '~> 1.9'
21
+ gem.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
22
+ gem.add_runtime_dependency 'ruby-tls', '~> 2.1'
21
23
 
22
- gem.add_development_dependency 'rspec', '>= 2.14'
23
- gem.add_development_dependency 'rake', '>= 10.1'
24
- gem.add_development_dependency 'yard'
24
+ gem.add_development_dependency 'rspec', '~> 3.5'
25
+ gem.add_development_dependency 'rake', '~> 11.2'
26
+ gem.add_development_dependency 'yard', '~> 0.9'
25
27
 
26
28
  gem.files = `git ls-files`.split("\n")
27
29
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
data/spec/async_spec.rb CHANGED
@@ -6,25 +6,25 @@ describe Libuv::Async do
6
6
  @log = []
7
7
  @general_failure = []
8
8
 
9
- @loop = Libuv::Loop.default
10
- @call = @loop.pipe
11
- @timeout = @loop.timer do
12
- @loop.stop
9
+ @reactor = Libuv::Reactor.default
10
+ @call = @reactor.pipe
11
+ @timeout = @reactor.timer do
12
+ @reactor.stop
13
13
  @general_failure << "test timed out"
14
14
  end
15
15
  @timeout.start(5000)
16
16
 
17
- @loop.all(@server, @client, @timeout).catch do |reason|
17
+ @reactor.all(@server, @client, @timeout).catch do |reason|
18
18
  @general_failure << reason.inspect
19
19
  p "Failed with: #{reason.message}\n#{reason.backtrace.join("\n")}\n"
20
20
  end
21
21
  end
22
22
 
23
23
  it "Should call the async function from the thread pool stopping the counter" do
24
- @loop.run { |logger|
25
- logger.progress do |level, errorid, error|
24
+ @reactor.run { |reactor|
25
+ reactor.notifier do |error, context|
26
26
  begin
27
- p "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
27
+ p "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
28
28
  rescue Exception
29
29
  p 'error in logger'
30
30
  end
@@ -32,24 +32,24 @@ describe Libuv::Async do
32
32
 
33
33
  @count = 0
34
34
 
35
- timer = @loop.timer do
35
+ timer = @reactor.timer do
36
36
  @count += 1
37
37
  end
38
38
  timer.start(0, 200)
39
39
 
40
- callback = @loop.async do
41
- stopper = @loop.timer do
40
+ callback = @reactor.async do
41
+ stopper = @reactor.timer do
42
42
  timer.close
43
43
  callback.close
44
44
  stopper.close
45
45
  @timeout.close
46
- @loop.stop
46
+ @reactor.stop
47
47
  end
48
48
  stopper.start(1000)
49
49
  callback.close
50
50
  end
51
51
 
52
- @loop.work(proc {
52
+ @reactor.work(proc {
53
53
  callback.call
54
54
  }).catch do |err|
55
55
  @general_failure << err
@@ -10,10 +10,18 @@ if RUBY_PLATFORM != 'java'
10
10
  @log = []
11
11
  @general_failure = []
12
12
 
13
- @loop = Libuv::Loop.default
14
- @timeout = @loop.timer do
13
+ @reactor = Libuv::Reactor.default
14
+ @reactor.notifier do |error, context|
15
+ begin
16
+ @general_failure << "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
17
+ rescue Exception => e
18
+ @general_failure << "error in logger #{e.inspect}"
19
+ end
20
+ end
21
+
22
+ @timeout = @reactor.timer do
15
23
  @timeout.close
16
- @loop.stop
24
+ @reactor.stop
17
25
  @general_failure << "test timed out"
18
26
  end
19
27
  @timeout.start(5000)
@@ -21,24 +29,15 @@ if RUBY_PLATFORM != 'java'
21
29
 
22
30
  describe 'serial execution' do
23
31
  it "should wait for work to complete and return the result" do
24
- @loop.run { |logger|
25
- logger.progress do |level, errorid, error|
26
- begin
27
- @general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
28
- rescue Exception => e
29
- @general_failure << "error in logger #{e.inspect}"
30
- end
31
- end
32
+ @reactor.run { |reactor|
32
33
 
33
-
34
- @log << co(@loop.work(proc {
34
+ @log << co(@reactor.work(proc {
35
35
  sleep 1
36
36
  'work done'
37
37
  }))
38
38
  @log << 'after work'
39
39
 
40
40
  @timeout.close
41
- @loop.stop
42
41
  }
43
42
 
44
43
  expect(@general_failure).to eq([])
@@ -46,17 +45,9 @@ if RUBY_PLATFORM != 'java'
46
45
  end
47
46
 
48
47
  it "should raise an error if the promise is rejected" do
49
- @loop.run { |logger|
50
- logger.progress do |level, errorid, error|
51
- begin
52
- @general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
53
- rescue Exception => e
54
- @general_failure << "error in logger #{e.inspect}"
55
- end
56
- end
57
-
48
+ @reactor.run { |reactor|
58
49
  begin
59
- @log << co(@loop.work(proc {
50
+ @log << co(@reactor.work(proc {
60
51
  raise 'rejected'
61
52
  }))
62
53
  @log << 'after work'
@@ -65,7 +56,6 @@ if RUBY_PLATFORM != 'java'
65
56
  end
66
57
 
67
58
  @timeout.close
68
- @loop.stop
69
59
  }
70
60
 
71
61
  expect(@general_failure).to eq([])
@@ -73,22 +63,13 @@ if RUBY_PLATFORM != 'java'
73
63
  end
74
64
 
75
65
  it "should return the results of multiple promises" do
76
- @loop.run { |logger|
77
- logger.progress do |level, errorid, error|
78
- begin
79
- @general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
80
- rescue Exception => e
81
- @general_failure << "error in logger #{e.inspect}"
82
- end
83
- end
84
-
85
-
86
- job1 = @loop.work(proc {
66
+ @reactor.run { |reactor|
67
+ job1 = @reactor.work(proc {
87
68
  sleep 1
88
69
  'job1'
89
70
  })
90
71
 
91
- job2 = @loop.work(proc {
72
+ job2 = @reactor.work(proc {
92
73
  sleep 1
93
74
  'job2'
94
75
  })
@@ -101,7 +82,6 @@ if RUBY_PLATFORM != 'java'
101
82
  @log << 'after work'
102
83
 
103
84
  @timeout.close
104
- @loop.stop
105
85
  }
106
86
 
107
87
  expect(@general_failure).to eq([])
@@ -110,16 +90,8 @@ if RUBY_PLATFORM != 'java'
110
90
 
111
91
 
112
92
  it "should provide a callback option for progress events" do
113
- @loop.run { |logger|
114
- logger.progress do |level, errorid, error|
115
- begin
116
- @general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n") if error.backtrace}\n"
117
- rescue Exception => e
118
- @general_failure << "error in logger #{e.inspect}"
119
- end
120
- end
121
-
122
- timer = @loop.timer
93
+ @reactor.run { |reactor|
94
+ timer = @reactor.timer
123
95
  timer.start(0)
124
96
  co(timer) do
125
97
  @log << 'in timer'
@@ -127,9 +99,7 @@ if RUBY_PLATFORM != 'java'
127
99
  end
128
100
 
129
101
  @log << 'after timer'
130
-
131
102
  @timeout.close
132
- @loop.stop
133
103
  }
134
104
 
135
105
  expect(@log).to eq(['in timer', 'after timer'])