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