libuv 0.10.0

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