libuv 0.10.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 (49) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +16 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +24 -0
  8. data/README.md +73 -0
  9. data/Rakefile +31 -0
  10. data/lib/libuv.rb +34 -0
  11. data/lib/libuv/assertions.rb +23 -0
  12. data/lib/libuv/async.rb +33 -0
  13. data/lib/libuv/check.rb +49 -0
  14. data/lib/libuv/error.rb +70 -0
  15. data/lib/libuv/ext/ext.rb +257 -0
  16. data/lib/libuv/ext/platform/darwin_x64.rb +12 -0
  17. data/lib/libuv/ext/platform/linux.rb +8 -0
  18. data/lib/libuv/ext/platform/unix.rb +14 -0
  19. data/lib/libuv/ext/platform/windows.rb +27 -0
  20. data/lib/libuv/ext/tasks.rb +27 -0
  21. data/lib/libuv/ext/tasks/mac.rb +23 -0
  22. data/lib/libuv/ext/tasks/unix.rb +23 -0
  23. data/lib/libuv/ext/tasks/win.rb +11 -0
  24. data/lib/libuv/ext/types.rb +230 -0
  25. data/lib/libuv/fs_event.rb +31 -0
  26. data/lib/libuv/handle.rb +82 -0
  27. data/lib/libuv/idle.rb +49 -0
  28. data/lib/libuv/listener.rb +34 -0
  29. data/lib/libuv/loop.rb +310 -0
  30. data/lib/libuv/net.rb +38 -0
  31. data/lib/libuv/pipe.rb +97 -0
  32. data/lib/libuv/prepare.rb +49 -0
  33. data/lib/libuv/q.rb +429 -0
  34. data/lib/libuv/resource.rb +28 -0
  35. data/lib/libuv/simple_async.rb +28 -0
  36. data/lib/libuv/stream.rb +124 -0
  37. data/lib/libuv/tcp.rb +194 -0
  38. data/lib/libuv/timer.rb +75 -0
  39. data/lib/libuv/tty.rb +34 -0
  40. data/lib/libuv/udp.rb +256 -0
  41. data/lib/libuv/version.rb +3 -0
  42. data/lib/libuv/work.rb +62 -0
  43. data/libuv.gemspec +54 -0
  44. data/spec/async_spec.rb +60 -0
  45. data/spec/defer_spec.rb +980 -0
  46. data/spec/idle_spec.rb +56 -0
  47. data/spec/pipe_spec.rb +148 -0
  48. data/spec/tcp_spec.rb +188 -0
  49. metadata +382 -0
data/lib/libuv/tty.rb ADDED
@@ -0,0 +1,34 @@
1
+ module Libuv
2
+ class TTY < Handle
3
+ include Stream
4
+
5
+
6
+ def initialize(loop, fileno, readable)
7
+ @loop = loop
8
+
9
+ tty_ptr = ::Libuv::Ext.create_handle(:uv_tty)
10
+ error = check_result(::Libuv::Ext.tty_init(loop.handle, tty_ptr, fileno, readable ? 1 : 0))
11
+
12
+ super(tty_ptr, error)
13
+ end
14
+
15
+ def enable_raw_mode
16
+ check_result ::Libuv::Ext.tty_set_mode(handle, 1)
17
+ end
18
+
19
+ def disable_raw_mode
20
+ check_result ::Libuv::Ext.tty_set_mode(handle, 0)
21
+ end
22
+
23
+ def reset_mode
24
+ ::Libuv::Ext.tty_reset_mode
25
+ end
26
+
27
+ def winsize
28
+ width = FFI::MemoryPointer.new(:int)
29
+ height = FFI::MemoryPointer.new(:int)
30
+ ::Libuv::Ext.tty_get_winsize(handle, width, height)
31
+ [width.get_int(0), height.get_int(0)]
32
+ end
33
+ end
34
+ end
data/lib/libuv/udp.rb ADDED
@@ -0,0 +1,256 @@
1
+ module Libuv
2
+ class UDP < Handle
3
+ include Net
4
+
5
+
6
+ SEND_DATA_ERROR = "data must be a String".freeze
7
+ TTL_ARGUMENT_ERROR = "ttl must be an Integer".freeze
8
+ MULTICAST_ARGUMENT_ERROR = "multicast_address must be a String".freeze
9
+ INTERFACE_ARGUMENT_ERROR = "interface_address must be a String".freeze
10
+
11
+
12
+ def initialize(loop)
13
+ @loop = loop
14
+
15
+ udp_ptr = ::Libuv::Ext.create_handle(:uv_udp)
16
+ error = check_result(::Libuv::Ext.udp_init(loop.handle, udp_ptr))
17
+
18
+ super(udp_ptr, error)
19
+ end
20
+
21
+ def bind(ip, port, ipv6_only = false)
22
+ assert_type(String, ip, IP_ARGUMENT_ERROR)
23
+ assert_type(Integer, port, PORT_ARGUMENT_ERROR)
24
+
25
+ begin
26
+ @udp_socket = create_socket(IPAddr.new(ip), port)
27
+ @udp_socket.bind(ipv6_only)
28
+ rescue Exception => e
29
+ reject(e)
30
+ end
31
+ end
32
+
33
+ def sockname
34
+ sockaddr, len = get_sockaddr_and_len
35
+ check_result! ::Libuv::Ext.udp_getsockname(handle, sockaddr, len)
36
+ get_ip_and_port(UV::Sockaddr.new(sockaddr), len.get_int(0))
37
+ end
38
+
39
+ def join(multicast_address, interface_address)
40
+ assert_type(String, multicast_address, MULTICAST_ARGUMENT_ERROR)
41
+ assert_type(String, interface_address, INTERFACE_ARGUMENT_ERROR)
42
+
43
+ error = check_result ::Libuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_join_group)
44
+ reject(error) if error
45
+ end
46
+
47
+ def leave(multicast_address, interface_address)
48
+ assert_type(String, multicast_address, MULTICAST_ARGUMENT_ERROR)
49
+ assert_type(String, interface_address, INTERFACE_ARGUMENT_ERROR)
50
+
51
+ error = check_result ::Libuv::Ext.udp_set_membership(handle, multicast_address, interface_address, :uv_leave_group)
52
+ reject(error) if error
53
+ end
54
+
55
+ def start_recv
56
+ error = check_result ::Libuv::Ext.udp_recv_start(handle, callback(:on_allocate), callback(:on_recv))
57
+ reject(error) if error
58
+ end
59
+
60
+ def stop_recv
61
+ error = check_result ::Libuv::Ext.udp_recv_stop(handle)
62
+ reject(error) if error
63
+ end
64
+
65
+ def send(ip, port, data)
66
+ deferred = @loop.defer
67
+ begin
68
+ assert_type(String, ip, IP_ARGUMENT_ERROR)
69
+ assert_type(Integer, port, PORT_ARGUMENT_ERROR)
70
+ assert_type(String, data, SEND_DATA_ERROR)
71
+
72
+ @udp_socket = create_socket(IPAddr.new(ip), port)
73
+
74
+ # local as this variable will be avaliable until the handle is closed
75
+ @sent_callbacks = @sent_callbacks || []
76
+
77
+ #
78
+ # create the curried callback
79
+ #
80
+ callback = FFI::Function.new(:void, [:pointer, :int]) do |req, status|
81
+ ::Libuv::Ext.free(req)
82
+ # remove the callback from the array
83
+ # assumes sends are done in order
84
+ promise = @sent_callbacks.shift[0]
85
+ resolve promise, status
86
+ end
87
+
88
+ #
89
+ # Save the callback and return the promise
90
+ #
91
+ begin
92
+ @sent_callbacks << [deferred, callback]
93
+ @udp_socket.send(data, callback)
94
+ rescue Exception => e
95
+ @sent_callbacks.pop
96
+ deferred.reject(e)
97
+
98
+ reject(e) # close the handle
99
+ end
100
+ rescue Exception => e
101
+ deferred.reject(e)
102
+ end
103
+ deferred.promise
104
+ end
105
+
106
+ def enable_multicast_loop
107
+ error = check_result ::Libuv::Ext.udp_set_multicast_loop(handle, 1)
108
+ reject(error) if error
109
+ end
110
+
111
+ def disable_multicast_loop
112
+ error = check_result ::Libuv::Ext.udp_set_multicast_loop(handle, 0)
113
+ reject(error) if error
114
+ end
115
+
116
+ def multicast_ttl=(ttl)
117
+ assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
118
+ error = check_result ::Libuv::Ext.udp_set_multicast_ttl(handle, ttl)
119
+ reject(error) if error
120
+ end
121
+
122
+ def enable_broadcast
123
+ error = check_result ::Libuv::Ext.udp_set_broadcast(handle, 1)
124
+ reject(error) if error
125
+ end
126
+
127
+ def disable_broadcast
128
+ error = check_result ::Libuv::Ext.udp_set_broadcast(handle, 0)
129
+ reject(error) if error
130
+ end
131
+
132
+ def ttl=(ttl)
133
+ assert_type(Integer, ttl, TTL_ARGUMENT_ERROR)
134
+ error = check_result ::Libuv::Ext.udp_set_ttl(handle, Integer(ttl))
135
+ reject(error) if error
136
+ end
137
+
138
+
139
+ private
140
+
141
+
142
+ def on_allocate(client, suggested_size)
143
+ ::Libuv::Ext.buf_init(::Libuv::Ext.malloc(suggested_size), suggested_size)
144
+ end
145
+
146
+ def on_recv(handle, nread, buf, sockaddr, flags)
147
+ e = check_result(nread)
148
+ base = buf[:base]
149
+
150
+ if e
151
+ ::Libuv::Ext.free(base)
152
+ reject(e)
153
+ else
154
+ data = base.read_string(nread)
155
+ ::Libuv::Ext.free(base)
156
+ unless sockaddr.null?
157
+ ip, port = get_ip_and_port(UV::Sockaddr.new(sockaddr))
158
+ end
159
+ defer.notify(data, ip, port) # stream the data
160
+ end
161
+ end
162
+
163
+ def create_socket(ip, port)
164
+ if ip.ipv4?
165
+ Socket4.new(@loop, handle, ip, port)
166
+ else
167
+ Socket6.new(@loop, handle, ip, port)
168
+ end
169
+ end
170
+
171
+
172
+ module SocketMethods
173
+ include Resource
174
+
175
+ def initialize(loop, udp, ip, port)
176
+ @loop, @udp, @sockaddr = loop, udp, ip_addr(ip.to_s, port)
177
+ end
178
+
179
+ def bind(ipv6_only = false)
180
+ check_result! udp_bind(ipv6_only)
181
+ end
182
+
183
+ def send(data, callback)
184
+ check_result! udp_send(data, callback)
185
+ end
186
+
187
+
188
+ private
189
+
190
+
191
+ def send_req
192
+ ::Libuv::Ext.create_request(:uv_udp_send)
193
+ end
194
+
195
+ def buf_init(data)
196
+ ::Libuv::Ext.buf_init(FFI::MemoryPointer.from_string(data), data.respond_to?(:bytesize) ? data.bytesize : data.size)
197
+ end
198
+ end
199
+
200
+
201
+ class Socket4
202
+ include SocketMethods
203
+
204
+
205
+ private
206
+
207
+
208
+ def ip_addr(ip, port)
209
+ ::Libuv::Ext.ip4_addr(ip, port)
210
+ end
211
+
212
+ def udp_bind(ipv6_only)
213
+ ::Libuv::Ext.udp_bind(@udp, @sockaddr, 0)
214
+ end
215
+
216
+ def udp_send(data, callback)
217
+ ::Libuv::Ext.udp_send(
218
+ send_req,
219
+ @udp,
220
+ buf_init(data),
221
+ 1,
222
+ @sockaddr,
223
+ callback
224
+ )
225
+ end
226
+ end
227
+
228
+
229
+ class Socket6 < Socket
230
+ include SocketMethods
231
+
232
+
233
+ private
234
+
235
+
236
+ def ip_addr(ip, port)
237
+ ::Libuv::Ext.ip6_addr(ip, port)
238
+ end
239
+
240
+ def udp_bind(ipv6_only)
241
+ ::Libuv::Ext.udp_bind6(@udp, @sockaddr, ipv6_only ? 1 : 0)
242
+ end
243
+
244
+ def udp_send(data, callback)
245
+ ::Libuv::Ext.udp_send6(
246
+ send_req,
247
+ @udp,
248
+ buf_init(data),
249
+ 1,
250
+ @sockaddr,
251
+ callback
252
+ )
253
+ end
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,3 @@
1
+ module Libuv
2
+ VERSION = '0.10.0'
3
+ end
data/lib/libuv/work.rb ADDED
@@ -0,0 +1,62 @@
1
+ module Libuv
2
+ class Work < Q::DeferredPromise
3
+ include Resource, Listener
4
+
5
+
6
+ def initialize(loop, work)
7
+ super(loop, loop.defer)
8
+
9
+ @work = work
10
+ @complete = false
11
+ @pointer = ::Libuv::Ext.create_request(:uv_work)
12
+ @error = nil # error in callback
13
+
14
+ error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
15
+ if error
16
+ ::Libuv::Ext.free(@pointer)
17
+ @complete = true
18
+ @defer.reject(error)
19
+ end
20
+ end
21
+
22
+ # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
23
+ #
24
+ # @return [true, false]
25
+ def cancel
26
+ if not @complete
27
+ @complete = ::Libuv::Ext.cancel(@pointer) >= 0
28
+ end
29
+ @complete
30
+ end
31
+
32
+ # Indicates is the work has completed yet or not.
33
+ #
34
+ # @return [true, false]
35
+ def completed?
36
+ return @complete
37
+ end
38
+
39
+
40
+ private
41
+
42
+
43
+ def on_complete(req, status)
44
+ @complete = true
45
+ ::Libuv::Ext.free(req)
46
+
47
+ if @error
48
+ @defer.reject(@error)
49
+ else
50
+ resolve @defer, status
51
+ end
52
+ end
53
+
54
+ def on_work(req)
55
+ begin
56
+ @work.call
57
+ rescue Exception => e
58
+ @error = e # Catch errors for promise resolution
59
+ end
60
+ end
61
+ end
62
+ end
data/libuv.gemspec ADDED
@@ -0,0 +1,54 @@
1
+ require File.expand_path("../lib/libuv/version", __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "libuv"
5
+ gem.version = Libuv::VERSION
6
+ gem.license = 'MIT'
7
+ gem.authors = ["Bulat Shakirzyanov", "Stephen von Takach"]
8
+ gem.email = ["mallluhuct@gmail.com", "steve@cotag.me"]
9
+ gem.homepage = "https://github.com/cotag/libuv"
10
+ gem.summary = "libuv bindings for Ruby"
11
+ gem.description = "An opinionated wrapper around libuv for Ruby"
12
+
13
+ gem.extensions << "ext/Rakefile"
14
+
15
+ gem.required_ruby_version = '>= 1.9.2'
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_runtime_dependency 'ffi', '>= 1.9'
19
+ gem.add_runtime_dependency 'thread_safe'
20
+ gem.add_development_dependency 'rspec', '>= 2.14'
21
+ gem.add_development_dependency 'rake', '>= 10.1'
22
+ gem.add_development_dependency 'yard'
23
+
24
+ gem.files = `git ls-files`.split("\n")
25
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+
27
+ # Add the submodule to the gem
28
+ relative_path = File.expand_path("../", __FILE__) + '/'
29
+ `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
30
+
31
+ if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
32
+ # Detect if cygwin path is being used by git
33
+ submodule_path = submodule_path[1..-1]
34
+ submodule_path.insert(1, ':')
35
+ end
36
+
37
+ # for each submodule, change working directory to that submodule
38
+ Dir.chdir(submodule_path) do
39
+ # Make the submodule path relative
40
+ submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
41
+
42
+ # issue git ls-files in submodule's directory
43
+ submodule_files = `git ls-files`.split($\)
44
+
45
+ # prepend the submodule path to create relative file paths
46
+ submodule_files_paths = submodule_files.map do |filename|
47
+ File.join(submodule_path, filename)
48
+ end
49
+
50
+ # add relative paths to gem.files
51
+ gem.files += submodule_files_paths
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,60 @@
1
+ require 'libuv'
2
+
3
+
4
+ describe Libuv::Async do
5
+ before :each do
6
+ @log = []
7
+ @general_failure = []
8
+
9
+ @loop = Libuv::Loop.new
10
+ @call = @loop.pipe
11
+ @timeout = @loop.timer do
12
+ @loop.stop
13
+ @general_failure << "test timed out"
14
+ end
15
+ @timeout.start(5000)
16
+
17
+ @loop.all(@server, @client, @timeout).catch do |reason|
18
+ @general_failure << reason.inspect
19
+ p "Failed with: #{reason.message}\n#{reason.backtrace.join("\n")}\n"
20
+ end
21
+ end
22
+
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|
26
+ begin
27
+ p "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
28
+ rescue Exception
29
+ p 'error in logger'
30
+ end
31
+ end
32
+
33
+ @count = 0
34
+
35
+ timer = @loop.timer do
36
+ @count += 1
37
+ end
38
+ timer.start(0, 200)
39
+
40
+ callback = @loop.async do
41
+ stopper = @loop.timer do
42
+ timer.close
43
+ callback.close
44
+ stopper.close
45
+ @loop.stop
46
+ end
47
+ stopper.start(1000)
48
+ end
49
+
50
+ @loop.work(proc {
51
+ callback.call
52
+ }).catch do |err|
53
+ @general_failure << err
54
+ end
55
+ }
56
+
57
+ @general_failure.should == []
58
+ (@count < 7 && @count > 3).should == true
59
+ end
60
+ end