mt-libuv 4.1.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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +24 -0
  8. data/README.md +195 -0
  9. data/Rakefile +31 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +28 -0
  12. data/lib/mt-libuv/async.rb +51 -0
  13. data/lib/mt-libuv/check.rb +59 -0
  14. data/lib/mt-libuv/coroutines.rb +79 -0
  15. data/lib/mt-libuv/dns.rb +98 -0
  16. data/lib/mt-libuv/error.rb +88 -0
  17. data/lib/mt-libuv/ext/ext.rb +322 -0
  18. data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
  19. data/lib/mt-libuv/ext/platform/unix.rb +69 -0
  20. data/lib/mt-libuv/ext/platform/windows.rb +83 -0
  21. data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
  22. data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
  23. data/lib/mt-libuv/ext/tasks/win.rb +29 -0
  24. data/lib/mt-libuv/ext/tasks.rb +27 -0
  25. data/lib/mt-libuv/ext/types.rb +253 -0
  26. data/lib/mt-libuv/fiber_pool.rb +83 -0
  27. data/lib/mt-libuv/file.rb +309 -0
  28. data/lib/mt-libuv/filesystem.rb +263 -0
  29. data/lib/mt-libuv/fs_event.rb +37 -0
  30. data/lib/mt-libuv/handle.rb +108 -0
  31. data/lib/mt-libuv/idle.rb +59 -0
  32. data/lib/mt-libuv/mixins/accessors.rb +41 -0
  33. data/lib/mt-libuv/mixins/assertions.rb +25 -0
  34. data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
  35. data/lib/mt-libuv/mixins/listener.rb +69 -0
  36. data/lib/mt-libuv/mixins/net.rb +42 -0
  37. data/lib/mt-libuv/mixins/resource.rb +30 -0
  38. data/lib/mt-libuv/mixins/stream.rb +276 -0
  39. data/lib/mt-libuv/pipe.rb +217 -0
  40. data/lib/mt-libuv/prepare.rb +59 -0
  41. data/lib/mt-libuv/q.rb +475 -0
  42. data/lib/mt-libuv/reactor.rb +567 -0
  43. data/lib/mt-libuv/signal.rb +62 -0
  44. data/lib/mt-libuv/spawn.rb +113 -0
  45. data/lib/mt-libuv/tcp.rb +465 -0
  46. data/lib/mt-libuv/timer.rb +107 -0
  47. data/lib/mt-libuv/tty.rb +42 -0
  48. data/lib/mt-libuv/udp.rb +302 -0
  49. data/lib/mt-libuv/version.rb +5 -0
  50. data/lib/mt-libuv/work.rb +86 -0
  51. data/lib/mt-libuv.rb +80 -0
  52. data/mt-libuv.gemspec +62 -0
  53. data/spec/async_spec.rb +67 -0
  54. data/spec/coroutines_spec.rb +121 -0
  55. data/spec/cpu_spec.rb +10 -0
  56. data/spec/defer_spec.rb +906 -0
  57. data/spec/dns_spec.rb +110 -0
  58. data/spec/dsl_spec.rb +43 -0
  59. data/spec/filesystem_spec.rb +270 -0
  60. data/spec/idle_spec.rb +44 -0
  61. data/spec/pipe_spec.rb +151 -0
  62. data/spec/spawn_spec.rb +119 -0
  63. data/spec/tcp_spec.rb +272 -0
  64. data/spec/test.sh +4 -0
  65. data/spec/test_fail.sh +3 -0
  66. data/spec/test_read.sh +3 -0
  67. data/spec/timer_spec.rb +14 -0
  68. data/spec/udp_spec.rb +73 -0
  69. data/spec/zen_spec.rb +34 -0
  70. metadata +196 -0
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class TTY < Handle
5
+ include Stream
6
+
7
+
8
+ def initialize(reactor, fileno, readable)
9
+ @reactor = reactor
10
+
11
+ tty_ptr = ::MTLibuv::Ext.allocate_handle_tty
12
+ error = check_result(::MTLibuv::Ext.tty_init(reactor.handle, tty_ptr, fileno, readable ? 1 : 0))
13
+
14
+ super(tty_ptr, error)
15
+ end
16
+
17
+ def enable_raw_mode
18
+ return if @closed
19
+ check_result ::MTLibuv::Ext.tty_set_mode(handle, 1)
20
+ self
21
+ end
22
+
23
+ def disable_raw_mode
24
+ return if @closed
25
+ check_result ::MTLibuv::Ext.tty_set_mode(handle, 0)
26
+ self
27
+ end
28
+
29
+ def reset_mode
30
+ ::MTLibuv::Ext.tty_reset_mode
31
+ self
32
+ end
33
+
34
+ def winsize
35
+ return [] if @closed
36
+ width = FFI::MemoryPointer.new(:int)
37
+ height = FFI::MemoryPointer.new(:int)
38
+ ::MTLibuv::Ext.tty_get_winsize(handle, width, height)
39
+ [width.get_int(0), height.get_int(0)]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,302 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ipaddr'
4
+
5
+
6
+ module MTLibuv
7
+ class UDP < Handle
8
+ include Net
9
+
10
+
11
+ define_callback function: :on_allocate, params: [:pointer, :size_t, Ext::UvBuf.by_ref]
12
+ define_callback function: :on_recv, params: [:pointer, :ssize_t, Ext::UvBuf.by_ref, Ext::Sockaddr.by_ref, :uint]
13
+ define_callback function: :send_complete, params: [:pointer, :int]
14
+
15
+
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"
21
+
22
+
23
+ def initialize(reactor, progress: nil, flags: nil)
24
+ @reactor = reactor
25
+ @progress = progress
26
+
27
+ udp_ptr = ::MTLibuv::Ext.allocate_handle_udp
28
+ error = if flags
29
+ check_result(::MTLibuv::Ext.udp_init_ex(reactor.handle, udp_ptr, flags))
30
+ else
31
+ check_result(::MTLibuv::Ext.udp_init(reactor.handle, udp_ptr))
32
+ end
33
+ @request_refs = {}
34
+
35
+ super(udp_ptr, error)
36
+ end
37
+
38
+ def bind(ip, port)
39
+ return if @closed
40
+ assert_type(String, ip, IP_ARGUMENT_ERROR)
41
+ assert_type(Integer, port, PORT_ARGUMENT_ERROR)
42
+
43
+ sockaddr = create_sockaddr(ip, port)
44
+ error = check_result ::MTLibuv::Ext.udp_bind(handle, sockaddr, 0)
45
+ reject(error) if error
46
+
47
+ self
48
+ end
49
+
50
+ def open(fd, binding = true)
51
+ return if @closed
52
+ error = check_result ::MTLibuv::Ext.udp_open(handle, fd)
53
+ reject(error) if error
54
+
55
+ self
56
+ end
57
+
58
+ def sockname
59
+ return [] if @closed
60
+ sockaddr, len = get_sockaddr_and_len
61
+ check_result! ::MTLibuv::Ext.udp_getsockname(handle, sockaddr, len)
62
+ get_ip_and_port(::MTLibuv::Ext::Sockaddr.new(sockaddr), len.get_int(0))
63
+ end
64
+
65
+ def join(multicast_address, interface_address)
66
+ return if @closed
67
+ assert_type(String, multicast_address, MULTICAST_ARGUMENT_ERROR)
68
+ assert_type(String, interface_address, INTERFACE_ARGUMENT_ERROR)
69
+
70
+ error = check_result ::MTLibuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_join_group)
71
+ reject(error) if error
72
+ self
73
+ end
74
+
75
+ def leave(multicast_address, interface_address)
76
+ return if @closed
77
+ assert_type(String, multicast_address, MULTICAST_ARGUMENT_ERROR)
78
+ assert_type(String, interface_address, INTERFACE_ARGUMENT_ERROR)
79
+
80
+ error = check_result ::MTLibuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_leave_group)
81
+ reject(error) if error
82
+ self
83
+ end
84
+
85
+ # Starts reading from the handle
86
+ # Renamed to match Stream
87
+ def start_read
88
+ return if @closed
89
+ error = check_result ::MTLibuv::Ext.udp_recv_start(handle, callback(:on_allocate), callback(:on_recv))
90
+ reject(error) if error
91
+ self
92
+ end
93
+
94
+ # Stops reading from the handle
95
+ # Renamed to match Stream
96
+ def stop_read
97
+ return if @closed
98
+ error = check_result ::MTLibuv::Ext.udp_recv_stop(handle)
99
+ reject(error) if error
100
+ self
101
+ end
102
+
103
+ def try_send(ip, port, data)
104
+ assert_type(String, ip, IP_ARGUMENT_ERROR)
105
+ assert_type(Integer, port, PORT_ARGUMENT_ERROR)
106
+ assert_type(String, data, SEND_DATA_ERROR)
107
+
108
+ sockaddr = create_sockaddr(ip, port)
109
+
110
+ buffer1 = ::FFI::MemoryPointer.from_string(data)
111
+ buffer = ::MTLibuv::Ext.buf_init(buffer1, data.respond_to?(:bytesize) ? data.bytesize : data.size)
112
+
113
+ result = ::MTLibuv::Ext.udp_try_send(
114
+ handle,
115
+ buffer,
116
+ 1,
117
+ sockaddr
118
+ )
119
+ buffer1.free
120
+
121
+ error = check_result result
122
+ raise error if error
123
+ return result
124
+ end
125
+
126
+ def send(ip, port, data, wait: false)
127
+ # NOTE:: Similar to stream.rb -> write
128
+ deferred = @reactor.defer
129
+ if !@closed
130
+ begin
131
+ assert_type(String, ip, IP_ARGUMENT_ERROR)
132
+ assert_type(Integer, port, PORT_ARGUMENT_ERROR)
133
+ assert_type(String, data, SEND_DATA_ERROR)
134
+
135
+ sockaddr = create_sockaddr(ip, port)
136
+
137
+ # Save a reference to this request
138
+ req = send_req
139
+ buffer1 = ::FFI::MemoryPointer.from_string(data)
140
+ buffer = ::MTLibuv::Ext.buf_init(buffer1, data.respond_to?(:bytesize) ? data.bytesize : data.size)
141
+ @request_refs[req.address] = [deferred, buffer1]
142
+
143
+ # Save the callback and return the promise
144
+ error = check_result ::MTLibuv::Ext.udp_send(
145
+ req,
146
+ handle,
147
+ buffer,
148
+ 1,
149
+ sockaddr,
150
+ callback(:send_complete, req.address)
151
+ )
152
+ if error
153
+ @request_refs.delete req.address
154
+ cleanup_callbacks req.address
155
+ ::MTLibuv::Ext.free(req)
156
+ buffer1.free
157
+ deferred.reject(error)
158
+ reject(error) # close the handle
159
+ end
160
+ rescue StandardError => e
161
+ deferred.reject(e)
162
+ end
163
+ else
164
+ deferred.reject(RuntimeError.new(HANDLE_CLOSED_ERROR))
165
+ end
166
+ deferred.promise
167
+
168
+ if wait
169
+ return deferred.promise if wait == :promise
170
+ deferred.promise.value
171
+ end
172
+
173
+ self
174
+ end
175
+
176
+ def enable_multicast_reactor
177
+ return if @closed
178
+ error = check_result ::MTLibuv::Ext.udp_set_multicast_reactor(handle, 1)
179
+ reject(error) if error
180
+ self
181
+ end
182
+
183
+ def disable_multicast_reactor
184
+ return if @closed
185
+ error = check_result ::MTLibuv::Ext.udp_set_multicast_reactor(handle, 0)
186
+ reject(error) if error
187
+ self
188
+ end
189
+
190
+ def multicast_ttl=(ttl)
191
+ return if @closed
192
+ assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
193
+ error = check_result ::MTLibuv::Ext.udp_set_multicast_ttl(handle, ttl)
194
+ reject(error) if error
195
+ self
196
+ end
197
+
198
+ def enable_broadcast
199
+ return if @closed
200
+ error = check_result ::MTLibuv::Ext.udp_set_broadcast(handle, 1)
201
+ reject(error) if error
202
+ self
203
+ end
204
+
205
+ def disable_broadcast
206
+ return if @closed
207
+ error = check_result ::MTLibuv::Ext.udp_set_broadcast(handle, 0)
208
+ reject(error) if error
209
+ self
210
+ end
211
+
212
+ def ttl=(ttl)
213
+ return if @closed
214
+ assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
215
+ error = check_result ::MTLibuv::Ext.udp_set_ttl(handle, Integer(ttl))
216
+ reject(error) if error
217
+ self
218
+ end
219
+
220
+ def progress(&callback)
221
+ @progress = callback
222
+ self
223
+ end
224
+
225
+
226
+ private
227
+
228
+
229
+ def send_req
230
+ ::MTLibuv::Ext.allocate_request_udp_send
231
+ end
232
+
233
+ def create_sockaddr(ip, port)
234
+ ips = IPAddr.new(ip)
235
+ if ips.ipv4?
236
+ addr = Ext::SockaddrIn.new
237
+ check_result! ::MTLibuv::Ext.ip4_addr(ip, port, addr)
238
+ addr
239
+ else
240
+ addr = Ext::SockaddrIn6.new
241
+ check_result! ::MTLibuv::Ext.ip6_addr(ip, port, addr)
242
+ addr
243
+ end
244
+ end
245
+
246
+
247
+ def on_close(pointer)
248
+ if @receive_buff
249
+ ::MTLibuv::Ext.free(@receive_buff)
250
+ @receive_buff = nil
251
+ @receive_size = nil
252
+ end
253
+
254
+ super(pointer)
255
+ end
256
+
257
+ def on_allocate(client, suggested_size, buffer)
258
+ if @receive_buff.nil?
259
+ @receive_buff = ::MTLibuv::Ext.malloc(suggested_size)
260
+ @receive_size = suggested_size
261
+ end
262
+
263
+ buffer[:base] = @receive_buff
264
+ buffer[:len] = @receive_size
265
+ end
266
+
267
+ def on_recv(handle, nread, buf, sockaddr, flags)
268
+ e = check_result(nread)
269
+
270
+ if e
271
+ @reactor.exec { reject(e) } # Will call close
272
+ elsif nread > 0
273
+ data = @receive_buff.read_string(nread)
274
+ unless sockaddr.null?
275
+ ip, port = get_ip_and_port(sockaddr)
276
+ end
277
+
278
+ @reactor.exec do
279
+ begin
280
+ @progress.call data, ip, port, self
281
+ rescue Exception => e
282
+ @reactor.log e, 'performing UDP data received callback'
283
+ end
284
+ end
285
+ else
286
+ ::MTLibuv::Ext.free(@receive_buff)
287
+ @receive_buff = nil
288
+ @receive_size = nil
289
+ end
290
+ end
291
+
292
+ def send_complete(req, status)
293
+ deferred, buffer1 = @request_refs.delete req.address
294
+ cleanup_callbacks req.address
295
+
296
+ ::MTLibuv::Ext.free(req)
297
+ buffer1.free
298
+
299
+ @reactor.exec { resolve(deferred, status) }
300
+ end
301
+ end
302
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ VERSION = '4.1.0'
5
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class Work < Q::DeferredPromise
5
+ include Resource, Listener
6
+
7
+
8
+ attr_reader :error
9
+ attr_reader :result
10
+
11
+
12
+ define_callback function: :on_work
13
+ define_callback function: :on_complete, params: [:pointer, :int]
14
+
15
+
16
+ # @param thread [::MTLibuv::Reactor] thread this work request will be associated
17
+ # @param work [Proc] callback to be called in the thread pool
18
+ def initialize(thread, &work)
19
+ super(thread, thread.defer)
20
+
21
+ @work = work
22
+ @complete = false
23
+ @pointer = ::MTLibuv::Ext.allocate_request_work
24
+ @error = nil # error in callback
25
+
26
+ @instance_id = @pointer.address
27
+
28
+ error = check_result ::MTLibuv::Ext.queue_work(@reactor, @pointer, callback(:on_work), callback(:on_complete))
29
+ if error
30
+ ::MTLibuv::Ext.free(@pointer)
31
+ @complete = true
32
+ @defer.reject(error)
33
+ end
34
+ end
35
+
36
+ # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
37
+ #
38
+ # @return [true, false]
39
+ def cancel
40
+ if not @complete
41
+ @complete = ::MTLibuv::Ext.cancel(@pointer) >= 0
42
+ end
43
+ @complete
44
+ end
45
+
46
+ # Indicates is the work has completed yet or not.
47
+ #
48
+ # @return [true, false]
49
+ def completed?
50
+ return @complete
51
+ end
52
+
53
+
54
+ private
55
+
56
+
57
+ def on_complete(req, status)
58
+ @complete = true
59
+ ::MTLibuv::Ext.free(req)
60
+
61
+ @reactor.exec do
62
+ e = check_result(status)
63
+ if e
64
+ @defer.reject(e)
65
+ else
66
+ if @error
67
+ @defer.reject(@error)
68
+ else
69
+ @defer.resolve(@result)
70
+ end
71
+ end
72
+ end
73
+
74
+ # Clean up references
75
+ cleanup_callbacks @instance_id
76
+ end
77
+
78
+ def on_work(req)
79
+ begin
80
+ @result = @work.call
81
+ rescue Exception => e
82
+ @error = e # Catch errors for promise resolution
83
+ end
84
+ end
85
+ end
86
+ end
data/lib/mt-libuv.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+ require 'thread'
5
+ require 'ffi'
6
+
7
+ module MTLibuv
8
+ DefaultThread = Thread.current
9
+
10
+ require 'mt-libuv/ext/ext' # The libuv ffi ext
11
+ require 'mt-libuv/error' # List of errors (matching those in uv.h)
12
+ require 'mt-libuv/q' # The promise library
13
+
14
+ # -- The classes required for a reactor instance --
15
+ require 'mt-libuv/mixins/assertions' # Common code to check arguments
16
+ require 'mt-libuv/mixins/accessors' # Helper methods for accessing reactor functions
17
+ require 'mt-libuv/mixins/resource' # Common code to check for errors
18
+ require 'mt-libuv/mixins/listener' # Common callback code
19
+
20
+ require 'mt-libuv/handle' # Base class for most libuv functionality
21
+ require 'mt-libuv/prepare' # Called at the end of a reactor cycle
22
+ require 'mt-libuv/async' # Provide a threadsafe way to signal the event reactor
23
+ require 'mt-libuv/timer' # High resolution timer
24
+ require 'mt-libuv/reactor' # The libuv reactor or event reactor
25
+ require 'mt-libuv/coroutines' # Pause program execution until a result is returned
26
+ require 'mt-libuv/fiber_pool' # Fibers on jRuby and Rubinius are threads and expensive to re-create
27
+ # --
28
+
29
+ autoload :FsChecks, 'mt-libuv/mixins/fs_checks' # Common code to check file system results
30
+ autoload :Stream, 'mt-libuv/mixins/stream' # For all libuv streams (tcp, pipes, tty)
31
+ autoload :Net, 'mt-libuv/mixins/net' # Common functions for tcp and udp
32
+
33
+ autoload :Filesystem, 'mt-libuv/filesystem' # Async directory manipulation
34
+ autoload :FSEvent, 'mt-libuv/fs_event' # Notifies of changes to files and folders as they occur
35
+ autoload :Signal, 'mt-libuv/signal' # Used to handle OS signals
36
+ autoload :Spawn, 'mt-libuv/spawn' # Executes a child process
37
+ autoload :Check, 'mt-libuv/check' # Called before processing events on the reactor
38
+ autoload :File, 'mt-libuv/file' # Async file reading and writing
39
+ autoload :Idle, 'mt-libuv/idle' # Called when there are no events to process
40
+ autoload :Work, 'mt-libuv/work' # Provide work to be completed on another thread (thread pool)
41
+ autoload :UDP, 'mt-libuv/udp' # Communicate over UDP
42
+ autoload :Dns, 'mt-libuv/dns' # Async DNS lookup
43
+
44
+ # Streams
45
+ autoload :Pipe, 'mt-libuv/pipe' # Communicate over Pipes
46
+ autoload :TCP, 'mt-libuv/tcp' # Communicate over TCP
47
+ autoload :TTY, 'mt-libuv/tty' # Terminal output
48
+
49
+
50
+ # Returns the number of CPU cores on the host platform
51
+ #
52
+ # @return [Integer, nil] representing the number of CPU cores or nil if failed
53
+ def self.cpu_count
54
+ cpu_info = FFI::MemoryPointer.new(:pointer)
55
+ cpu_count = FFI::MemoryPointer.new(:int)
56
+ if ::MTLibuv::Ext.cpu_info(cpu_info, cpu_count) >= 0
57
+ count = cpu_count.read_int
58
+ ::MTLibuv::Ext.free_cpu_info(cpu_info.read_pointer, count)
59
+ return count
60
+ else
61
+ return nil
62
+ end
63
+ end
64
+
65
+ # Include all the accessors at this level
66
+ extend Accessors
67
+ end
68
+
69
+
70
+ class Object
71
+ private
72
+
73
+ def reactor
74
+ if block_given?
75
+ MTLibuv.reactor { |thread| yield(thread) }
76
+ else
77
+ MTLibuv.reactor
78
+ end
79
+ end
80
+ end
data/mt-libuv.gemspec ADDED
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path("../lib/mt-libuv/version", __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "mt-libuv"
7
+ gem.version = MTLibuv::VERSION
8
+ gem.license = 'MIT'
9
+ gem.authors = ["Giallombardo Nathan"]
10
+ gem.email = ["nathan.giallombardo@mapotempo.com"]
11
+ gem.homepage = "https://github.com/Mapotempo/mt-libuv"
12
+ gem.summary = "mt-libuv bindings for Ruby"
13
+ gem.description = "An opinionated wrapper around mt-libuv for Ruby"
14
+
15
+ gem.extensions << "ext/Rakefile"
16
+
17
+ gem.required_ruby_version = '>= 2.0.0'
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_runtime_dependency 'ffi', '~> 1.9'
21
+ gem.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
22
+ gem.add_runtime_dependency 'mt-ruby-tls', '~> 2.1'
23
+
24
+ gem.add_development_dependency 'rspec', '~> 3.5'
25
+ gem.add_development_dependency 'rake', '~> 11.2'
26
+ gem.add_development_dependency 'yard', '~> 0.9'
27
+
28
+ gem.files = `git ls-files`.split("\n")
29
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+
31
+ if File.exist? 'ext/libuv.dll'
32
+ gem.files << 'ext/libuv.dll'
33
+ end
34
+
35
+ # Add the submodule to the gem
36
+ # relative_path = File.expand_path("../", __FILE__) + '/'
37
+ # `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
38
+
39
+ # if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
40
+ # # Detect if cygwin path is being used by git
41
+ # submodule_path = submodule_path[1..-1]
42
+ # submodule_path.insert(1, ':')
43
+ # end
44
+
45
+ # # for each submodule, change working directory to that submodule
46
+ # Dir.chdir(submodule_path) do
47
+ # # Make the submodule path relative
48
+ # submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
49
+
50
+ # # issue git ls-files in submodule's directory
51
+ # submodule_files = `git ls-files`.split($\)
52
+
53
+ # # prepend the submodule path to create relative file paths
54
+ # submodule_files_paths = submodule_files.map do |filename|
55
+ # File.join(submodule_path, filename)
56
+ # end
57
+
58
+ # # add relative paths to gem.files
59
+ # gem.files += submodule_files_paths
60
+ # end
61
+ # end
62
+ end
@@ -0,0 +1,67 @@
1
+ require 'mt-libuv'
2
+
3
+
4
+ describe MTLibuv::Async do
5
+ before :each do
6
+ @log = []
7
+ @general_failure = []
8
+
9
+ @reactor = MTLibuv::Reactor.default
10
+ @call = @reactor.pipe
11
+ @timeout = @reactor.timer do
12
+ @reactor.stop
13
+ @general_failure << "test timed out"
14
+ end
15
+ @timeout.start(5000)
16
+
17
+ @reactor.all(@server, @client, @timeout).catch do |reason|
18
+ @general_failure << reason.inspect
19
+ puts "Failed with: #{reason.message}\n#{reason.backtrace.join("\n")}\n"
20
+ end
21
+
22
+ @reactor.notifier do |error, context|
23
+ begin
24
+ puts "Log called: #{context}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
25
+ rescue Exception
26
+ puts 'error in logger'
27
+ end
28
+ end
29
+ end
30
+
31
+ after :each do
32
+ @reactor.notifier
33
+ end
34
+
35
+ it "Should call the async function from the thread pool stopping the counter" do
36
+ @reactor.run { |reactor|
37
+
38
+ @count = 0
39
+
40
+ timer = @reactor.timer do
41
+ @count += 1
42
+ end
43
+ timer.start(0, 200)
44
+
45
+ callback = @reactor.async do
46
+ stopper = @reactor.timer do
47
+ timer.close
48
+ callback.close
49
+ stopper.close
50
+ @timeout.close
51
+ @reactor.stop
52
+ end
53
+ stopper.start(1000)
54
+ callback.close
55
+ end
56
+
57
+ @reactor.work {
58
+ callback.call
59
+ }.catch do |err|
60
+ @general_failure << err
61
+ end
62
+ }
63
+
64
+ expect(@general_failure).to eq([])
65
+ expect(@count < 7 && @count > 3).to eq(true)
66
+ end
67
+ end