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.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/.rspec +1 -0
- data/.travis.yml +16 -0
- data/Gemfile +2 -0
- data/LICENSE +24 -0
- data/README.md +73 -0
- data/Rakefile +31 -0
- data/lib/libuv.rb +34 -0
- data/lib/libuv/assertions.rb +23 -0
- data/lib/libuv/async.rb +33 -0
- data/lib/libuv/check.rb +49 -0
- data/lib/libuv/error.rb +70 -0
- data/lib/libuv/ext/ext.rb +257 -0
- data/lib/libuv/ext/platform/darwin_x64.rb +12 -0
- data/lib/libuv/ext/platform/linux.rb +8 -0
- data/lib/libuv/ext/platform/unix.rb +14 -0
- data/lib/libuv/ext/platform/windows.rb +27 -0
- data/lib/libuv/ext/tasks.rb +27 -0
- data/lib/libuv/ext/tasks/mac.rb +23 -0
- data/lib/libuv/ext/tasks/unix.rb +23 -0
- data/lib/libuv/ext/tasks/win.rb +11 -0
- data/lib/libuv/ext/types.rb +230 -0
- data/lib/libuv/fs_event.rb +31 -0
- data/lib/libuv/handle.rb +82 -0
- data/lib/libuv/idle.rb +49 -0
- data/lib/libuv/listener.rb +34 -0
- data/lib/libuv/loop.rb +310 -0
- data/lib/libuv/net.rb +38 -0
- data/lib/libuv/pipe.rb +97 -0
- data/lib/libuv/prepare.rb +49 -0
- data/lib/libuv/q.rb +429 -0
- data/lib/libuv/resource.rb +28 -0
- data/lib/libuv/simple_async.rb +28 -0
- data/lib/libuv/stream.rb +124 -0
- data/lib/libuv/tcp.rb +194 -0
- data/lib/libuv/timer.rb +75 -0
- data/lib/libuv/tty.rb +34 -0
- data/lib/libuv/udp.rb +256 -0
- data/lib/libuv/version.rb +3 -0
- data/lib/libuv/work.rb +62 -0
- data/libuv.gemspec +54 -0
- data/spec/async_spec.rb +60 -0
- data/spec/defer_spec.rb +980 -0
- data/spec/idle_spec.rb +56 -0
- data/spec/pipe_spec.rb +148 -0
- data/spec/tcp_spec.rb +188 -0
- metadata +382 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module Libuv
|
2
|
+
module Resource
|
3
|
+
|
4
|
+
|
5
|
+
def resolve(deferred, rc)
|
6
|
+
if rc.nil? || rc >= 0
|
7
|
+
deferred.resolve(nil)
|
8
|
+
else
|
9
|
+
deferred.reject(@loop.lookup_error(rc))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_result!(rc)
|
14
|
+
e = @loop.lookup_error(rc) unless rc.nil? || rc >= 0
|
15
|
+
raise e if e
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_result(rc)
|
19
|
+
@loop.lookup_error(rc) unless rc.nil? || rc >= 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_ptr
|
23
|
+
@pointer
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Libuv
|
2
|
+
class SimpleAsync < Async
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(loop, callback = nil, &blk)
|
6
|
+
@callback = callback || blk
|
7
|
+
super(loop)
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
|
14
|
+
def on_async(handle, status)
|
15
|
+
e = check_result(status)
|
16
|
+
|
17
|
+
if e
|
18
|
+
reject(e)
|
19
|
+
else
|
20
|
+
begin
|
21
|
+
@callback.call
|
22
|
+
rescue Exception => e
|
23
|
+
@loop.log :error, :simple_async_cb, e
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/libuv/stream.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module Libuv
|
2
|
+
module Stream
|
3
|
+
|
4
|
+
|
5
|
+
BACKLOG_ERROR = "backlog must be an Integer".freeze
|
6
|
+
WRITE_ERROR = "data must be a String".freeze
|
7
|
+
|
8
|
+
|
9
|
+
def listen(backlog)
|
10
|
+
return if @closed
|
11
|
+
assert_type(Integer, backlog, BACKLOG_ERROR)
|
12
|
+
error = check_result ::Libuv::Ext.listen(handle, Integer(backlog), callback(:on_listen))
|
13
|
+
reject(error) if error
|
14
|
+
end
|
15
|
+
|
16
|
+
# Starts reading from the handle
|
17
|
+
def start_read
|
18
|
+
error = check_result ::Libuv::Ext.read_start(handle, callback(:on_allocate), callback(:on_read))
|
19
|
+
reject(error) if error
|
20
|
+
end
|
21
|
+
|
22
|
+
# Stops reading from the handle
|
23
|
+
def stop_read
|
24
|
+
error = check_result ::Libuv::Ext.read_stop(handle)
|
25
|
+
reject(error) if error
|
26
|
+
end
|
27
|
+
|
28
|
+
# Shutsdown the writes on the handle waiting until the last write is complete before triggering the callback
|
29
|
+
def shutdown
|
30
|
+
error = check_result ::Libuv::Ext.shutdown(::Libuv::Ext.create_request(:uv_shutdown), handle, callback(:on_shutdown))
|
31
|
+
reject(error) if error
|
32
|
+
end
|
33
|
+
|
34
|
+
def write(data)
|
35
|
+
deferred = @loop.defer
|
36
|
+
begin
|
37
|
+
assert_type(String, data, WRITE_ERROR)
|
38
|
+
|
39
|
+
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
40
|
+
buffer = ::Libuv::Ext.buf_init(FFI::MemoryPointer.from_string(data), size)
|
41
|
+
|
42
|
+
# local as this variable will be avaliable until the handle is closed
|
43
|
+
@write_callbacks = @write_callbacks || []
|
44
|
+
|
45
|
+
#
|
46
|
+
# create the curried callback
|
47
|
+
#
|
48
|
+
callback = FFI::Function.new(:void, [:pointer, :int]) do |req, status|
|
49
|
+
::Libuv::Ext.free(req)
|
50
|
+
# remove the callback from the array
|
51
|
+
# assumes writes are done in order
|
52
|
+
promise = @write_callbacks.shift[0]
|
53
|
+
resolve promise, status
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
@write_callbacks << [deferred, callback]
|
58
|
+
req = ::Libuv::Ext.create_request(:uv_write)
|
59
|
+
error = check_result ::Libuv::Ext.write(req, handle, buffer, 1, callback)
|
60
|
+
|
61
|
+
if error
|
62
|
+
@write_callbacks.pop
|
63
|
+
::Libuv::Ext.free(req)
|
64
|
+
deferred.reject(error)
|
65
|
+
|
66
|
+
reject(error) # close the handle
|
67
|
+
end
|
68
|
+
rescue Exception => e
|
69
|
+
deferred.reject(e) # this write exception may not be fatal
|
70
|
+
end
|
71
|
+
deferred.promise
|
72
|
+
end
|
73
|
+
|
74
|
+
def readable?
|
75
|
+
::Libuv::Ext.is_readable(handle) > 0
|
76
|
+
end
|
77
|
+
|
78
|
+
def writable?
|
79
|
+
::Libuv::Ext.is_writable(handle) > 0
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
|
86
|
+
def on_listen(server, status)
|
87
|
+
e = check_result(status)
|
88
|
+
|
89
|
+
if e
|
90
|
+
reject(e) # is this cause for closing the handle?
|
91
|
+
else
|
92
|
+
begin
|
93
|
+
@on_listen.call(self)
|
94
|
+
rescue Exception => e
|
95
|
+
@loop.log :error, :stream_listen_cb, e
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_allocate(client, suggested_size)
|
101
|
+
::Libuv::Ext.buf_init(::Libuv::Ext.malloc(suggested_size), suggested_size)
|
102
|
+
end
|
103
|
+
|
104
|
+
def on_read(handle, nread, buf)
|
105
|
+
e = check_result(nread)
|
106
|
+
base = buf[:base]
|
107
|
+
|
108
|
+
if e
|
109
|
+
::Libuv::Ext.free(base)
|
110
|
+
reject(e)
|
111
|
+
else
|
112
|
+
data = base.read_string(nread)
|
113
|
+
::Libuv::Ext.free(base)
|
114
|
+
defer.notify(data) # stream the data
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_shutdown(req, status)
|
119
|
+
::Libuv::Ext.free(req)
|
120
|
+
@close_error = check_result(status)
|
121
|
+
close
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/libuv/tcp.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
|
4
|
+
module Libuv
|
5
|
+
class TCP < Handle
|
6
|
+
include Stream, Net
|
7
|
+
|
8
|
+
|
9
|
+
KEEPALIVE_ARGUMENT_ERROR = "delay must be an Integer".freeze
|
10
|
+
|
11
|
+
|
12
|
+
def initialize(loop, acceptor = nil)
|
13
|
+
@loop = loop
|
14
|
+
|
15
|
+
tcp_ptr = ::Libuv::Ext.create_handle(:uv_tcp)
|
16
|
+
error = check_result(::Libuv::Ext.tcp_init(loop.handle, tcp_ptr))
|
17
|
+
error = check_result(::Libuv::Ext.accept(acceptor, tcp_ptr)) if acceptor && error.nil?
|
18
|
+
|
19
|
+
super(tcp_ptr, error)
|
20
|
+
end
|
21
|
+
|
22
|
+
def bind(ip, port, callback = nil, &blk)
|
23
|
+
@on_listen = callback || blk
|
24
|
+
assert_type(String, ip, IP_ARGUMENT_ERROR)
|
25
|
+
assert_type(Integer, port, PORT_ARGUMENT_ERROR)
|
26
|
+
|
27
|
+
begin
|
28
|
+
@tcp_socket = create_socket(IPAddr.new(ip), port)
|
29
|
+
@tcp_socket.bind
|
30
|
+
rescue Exception => e
|
31
|
+
reject(e)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def accept(callback = nil, &blk)
|
36
|
+
tcp = nil
|
37
|
+
begin
|
38
|
+
tcp = TCP.new(loop, handle)
|
39
|
+
rescue Exception => e
|
40
|
+
@loop.log :info, :tcp_accept_failed, e
|
41
|
+
end
|
42
|
+
if tcp
|
43
|
+
begin
|
44
|
+
(callback || blk).call(tcp)
|
45
|
+
rescue Exception => e
|
46
|
+
@loop.log :error, :tcp_accept_cb, e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def connect(ip, port, callback = nil, &blk)
|
53
|
+
@callback = callback || blk
|
54
|
+
assert_type(String, ip, IP_ARGUMENT_ERROR)
|
55
|
+
assert_type(Integer, port, PORT_ARGUMENT_ERROR)
|
56
|
+
|
57
|
+
begin
|
58
|
+
@tcp_socket = create_socket(IPAddr.new(ip), port)
|
59
|
+
@tcp_socket.connect(callback(:on_connect))
|
60
|
+
rescue Exception => e
|
61
|
+
reject(e)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def sockname
|
66
|
+
sockaddr, len = get_sockaddr_and_len
|
67
|
+
check_result! ::Libuv::Ext.tcp_getsockname(handle, sockaddr, len)
|
68
|
+
get_ip_and_port(::Libuv::Sockaddr.new(sockaddr), len.get_int(0))
|
69
|
+
end
|
70
|
+
|
71
|
+
def peername
|
72
|
+
sockaddr, len = get_sockaddr_and_len
|
73
|
+
check_result! ::Libuv::Ext.tcp_getpeername(handle, sockaddr, len)
|
74
|
+
get_ip_and_port(::Libuv::Sockaddr.new(sockaddr), len.get_int(0))
|
75
|
+
end
|
76
|
+
|
77
|
+
def enable_nodelay
|
78
|
+
check_result ::Libuv::Ext.tcp_nodelay(handle, 1)
|
79
|
+
end
|
80
|
+
|
81
|
+
def disable_nodelay
|
82
|
+
check_result ::Libuv::Ext.tcp_nodelay(handle, 0)
|
83
|
+
end
|
84
|
+
|
85
|
+
def enable_keepalive(delay)
|
86
|
+
assert_type(Integer, delay, KEEPALIVE_ARGUMENT_ERROR)
|
87
|
+
check_result ::Libuv::Ext.tcp_keepalive(handle, 1, delay)
|
88
|
+
end
|
89
|
+
|
90
|
+
def disable_keepalive
|
91
|
+
check_result ::Libuv::Ext.tcp_keepalive(handle, 0, 0)
|
92
|
+
end
|
93
|
+
|
94
|
+
def enable_simultaneous_accepts
|
95
|
+
check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 1)
|
96
|
+
end
|
97
|
+
|
98
|
+
def disable_simultaneous_accepts
|
99
|
+
check_result ::Libuv::Ext.tcp_simultaneous_accepts(handle, 0)
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
|
106
|
+
def create_socket(ip, port)
|
107
|
+
if ip.ipv4?
|
108
|
+
Socket4.new(loop, handle, ip.to_s, port)
|
109
|
+
else
|
110
|
+
Socket6.new(loop, handle, ip.to_s, port)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def on_connect(req, status)
|
115
|
+
::Libuv::Ext.free(req)
|
116
|
+
@callback.call(self)
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
class SocketBase
|
121
|
+
include Resource
|
122
|
+
|
123
|
+
def initialize(loop, tcp, ip, port)
|
124
|
+
@tcp, @sockaddr = tcp, ip_addr(ip, port)
|
125
|
+
end
|
126
|
+
|
127
|
+
def bind
|
128
|
+
check_result!(tcp_bind)
|
129
|
+
end
|
130
|
+
|
131
|
+
def connect(callback)
|
132
|
+
check_result!(tcp_connect(callback))
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
|
139
|
+
def connect_req
|
140
|
+
::Libuv::Ext.create_request(:uv_connect)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
class Socket4 < SocketBase
|
146
|
+
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
|
151
|
+
def ip_addr(ip, port)
|
152
|
+
::Libuv::Ext.ip4_addr(ip, port)
|
153
|
+
end
|
154
|
+
|
155
|
+
def tcp_bind
|
156
|
+
::Libuv::Ext.tcp_bind(@tcp, @sockaddr)
|
157
|
+
end
|
158
|
+
|
159
|
+
def tcp_connect(callback)
|
160
|
+
::Libuv::Ext.tcp_connect(
|
161
|
+
connect_req,
|
162
|
+
@tcp,
|
163
|
+
@sockaddr,
|
164
|
+
callback
|
165
|
+
)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
class Socket6 < SocketBase
|
171
|
+
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
|
176
|
+
def ip_addr(ip, port)
|
177
|
+
::Libuv::Ext.ip6_addr(ip, port)
|
178
|
+
end
|
179
|
+
|
180
|
+
def tcp_bind
|
181
|
+
::Libuv::Ext.tcp_bind6(@tcp, @sockaddr)
|
182
|
+
end
|
183
|
+
|
184
|
+
def tcp_connect(callback)
|
185
|
+
::Libuv::Ext.tcp_connect6(
|
186
|
+
connect_req,
|
187
|
+
@tcp,
|
188
|
+
@sockaddr,
|
189
|
+
callback
|
190
|
+
)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
data/lib/libuv/timer.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Libuv
|
2
|
+
class Timer < Handle
|
3
|
+
include Assertions
|
4
|
+
|
5
|
+
|
6
|
+
TIMEOUT_ERROR = "timeout must be an Integer".freeze
|
7
|
+
REPEAT_ERROR = "repeat must be an Integer".freeze
|
8
|
+
|
9
|
+
|
10
|
+
def initialize(loop, callback = nil)
|
11
|
+
@loop, @callback = loop, callback
|
12
|
+
|
13
|
+
timer_ptr = ::Libuv::Ext.create_handle(:uv_timer)
|
14
|
+
error = check_result(::Libuv::Ext.timer_init(loop.handle, timer_ptr))
|
15
|
+
|
16
|
+
super(timer_ptr, error)
|
17
|
+
end
|
18
|
+
|
19
|
+
def start(timeout, repeat = 0)
|
20
|
+
return if @closed
|
21
|
+
|
22
|
+
assert_type(Integer, timeout, TIMEOUT_ERROR)
|
23
|
+
assert_type(Integer, repeat, REPEAT_ERROR)
|
24
|
+
|
25
|
+
error = check_result ::Libuv::Ext.timer_start(handle, callback(:on_timer), timeout, repeat)
|
26
|
+
reject(error) if error
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
return if @closed
|
31
|
+
error = check_result ::Libuv::Ext.timer_stop(handle)
|
32
|
+
reject(error) if error
|
33
|
+
end
|
34
|
+
|
35
|
+
def again
|
36
|
+
return if @closed
|
37
|
+
error = check_result ::Libuv::Ext.timer_again(handle)
|
38
|
+
reject(error) if error
|
39
|
+
end
|
40
|
+
|
41
|
+
def repeat=(repeat)
|
42
|
+
return if @closed
|
43
|
+
assert_type(Integer, repeat, REPEAT_ERROR)
|
44
|
+
check_result ::Libuv::Ext.timer_set_repeat(handle, repeat)
|
45
|
+
reject(error) if error
|
46
|
+
end
|
47
|
+
|
48
|
+
def repeat
|
49
|
+
return if @closed
|
50
|
+
::Libuv::Ext.timer_get_repeat(handle)
|
51
|
+
end
|
52
|
+
|
53
|
+
def progress(callback = nil, &blk)
|
54
|
+
@callback = callback || blk
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
|
61
|
+
def on_timer(handle, status)
|
62
|
+
e = check_result(status)
|
63
|
+
|
64
|
+
if e
|
65
|
+
reject(e)
|
66
|
+
else
|
67
|
+
begin
|
68
|
+
@callback.call
|
69
|
+
rescue Exception => e
|
70
|
+
@loop.log :error, :timer_cb, e
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|