mt-libuv 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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