libuv 0.11.21 → 0.11.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +17 -17
- data/.gitmodules +3 -3
- data/.rspec +1 -1
- data/.travis.yml +16 -16
- data/Gemfile +4 -4
- data/LICENSE +23 -23
- data/README.md +89 -88
- data/Rakefile +31 -31
- data/lib/libuv.rb +54 -54
- data/lib/libuv/async.rb +47 -47
- data/lib/libuv/check.rb +55 -55
- data/lib/libuv/dns.rb +85 -85
- data/lib/libuv/error.rb +74 -73
- data/lib/libuv/ext/ext.rb +258 -258
- data/lib/libuv/ext/platform/darwin_x64.rb +23 -23
- data/lib/libuv/ext/platform/linux.rb +7 -7
- data/lib/libuv/ext/platform/unix.rb +29 -29
- data/lib/libuv/ext/platform/windows.rb +40 -40
- data/lib/libuv/ext/tasks.rb +31 -31
- data/lib/libuv/ext/tasks/mac.rb +23 -23
- data/lib/libuv/ext/tasks/unix.rb +23 -23
- data/lib/libuv/ext/tasks/win.rb +14 -14
- data/lib/libuv/ext/types.rb +238 -238
- data/lib/libuv/file.rb +269 -269
- data/lib/libuv/filesystem.rb +232 -232
- data/lib/libuv/fs_event.rb +31 -31
- data/lib/libuv/handle.rb +85 -85
- data/lib/libuv/idle.rb +56 -56
- data/lib/libuv/loop.rb +412 -412
- data/lib/libuv/mixins/assertions.rb +23 -23
- data/lib/libuv/mixins/fs_checks.rb +58 -58
- data/lib/libuv/mixins/listener.rb +34 -34
- data/lib/libuv/mixins/net.rb +40 -40
- data/lib/libuv/mixins/resource.rb +27 -27
- data/lib/libuv/mixins/stream.rb +154 -154
- data/lib/libuv/pipe.rb +203 -203
- data/lib/libuv/prepare.rb +56 -56
- data/lib/libuv/signal.rb +51 -51
- data/lib/libuv/tcp.rb +334 -332
- data/lib/libuv/timer.rb +85 -85
- data/lib/libuv/tty.rb +37 -37
- data/lib/libuv/udp.rb +240 -240
- data/lib/libuv/version.rb +3 -3
- data/lib/libuv/work.rb +75 -75
- data/libuv.gemspec +56 -56
- data/spec/async_spec.rb +60 -60
- data/spec/cpu_spec.rb +10 -10
- data/spec/defer_spec.rb +980 -980
- data/spec/dns_spec.rb +90 -90
- data/spec/filesystem_spec.rb +261 -250
- data/spec/idle_spec.rb +56 -56
- data/spec/pipe_spec.rb +160 -160
- data/spec/tcp_spec.rb +267 -267
- metadata +55 -61
@@ -1,23 +1,23 @@
|
|
1
|
-
module Libuv
|
2
|
-
module Assertions
|
3
|
-
MSG_NO_PROC = 'no block given'
|
4
|
-
|
5
|
-
def assert_block(proc, msg = MSG_NO_PROC)
|
6
|
-
raise ArgumentError, msg, caller unless proc.respond_to? :call
|
7
|
-
end
|
8
|
-
|
9
|
-
def assert_type(type, actual, msg = nil)
|
10
|
-
if not actual.kind_of?(type)
|
11
|
-
msg ||= "value #{actual.inspect} is not a valid #{type}"
|
12
|
-
raise ArgumentError, msg, caller
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def assert_boolean(actual, msg = nil)
|
17
|
-
if not (actual.kind_of?(TrueClass) || actual.kind_of?(FalseClass))
|
18
|
-
msg ||= "value #{actual.inspect} is not a valid Boolean"
|
19
|
-
raise ArgumentError, msg, caller
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
1
|
+
module Libuv
|
2
|
+
module Assertions
|
3
|
+
MSG_NO_PROC = 'no block given'
|
4
|
+
|
5
|
+
def assert_block(proc, msg = MSG_NO_PROC)
|
6
|
+
raise ArgumentError, msg, caller unless proc.respond_to? :call
|
7
|
+
end
|
8
|
+
|
9
|
+
def assert_type(type, actual, msg = nil)
|
10
|
+
if not actual.kind_of?(type)
|
11
|
+
msg ||= "value #{actual.inspect} is not a valid #{type}"
|
12
|
+
raise ArgumentError, msg, caller
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def assert_boolean(actual, msg = nil)
|
17
|
+
if not (actual.kind_of?(TrueClass) || actual.kind_of?(FalseClass))
|
18
|
+
msg ||= "value #{actual.inspect} is not a valid Boolean"
|
19
|
+
raise ArgumentError, msg, caller
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,58 +1,58 @@
|
|
1
|
-
|
2
|
-
module Libuv
|
3
|
-
module FsChecks
|
4
|
-
|
5
|
-
|
6
|
-
def stat
|
7
|
-
@stat_deferred = @loop.defer
|
8
|
-
|
9
|
-
request = ::Libuv::Ext.create_request(:uv_fs)
|
10
|
-
pre_check @stat_deferred, request, ::Libuv::Ext.fs_fstat(@loop.handle, request, @fileno, callback(:on_stat))
|
11
|
-
@stat_deferred.promise
|
12
|
-
end
|
13
|
-
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
|
18
|
-
def on_stat(req)
|
19
|
-
if post_check(req, @stat_deferred)
|
20
|
-
uv_stat = req[:stat]
|
21
|
-
uv_members = uv_stat.members
|
22
|
-
|
23
|
-
stats = {}
|
24
|
-
uv_members.each do |key|
|
25
|
-
stats[key] = uv_stat[key]
|
26
|
-
end
|
27
|
-
|
28
|
-
cleanup(req)
|
29
|
-
@stat_deferred.resolve(stats)
|
30
|
-
end
|
31
|
-
@stat_deferred = nil
|
32
|
-
end
|
33
|
-
|
34
|
-
def pre_check(deferrable, request, result)
|
35
|
-
error = check_result result
|
36
|
-
if error
|
37
|
-
::Libuv::Ext.free(request)
|
38
|
-
deferrable.reject(error)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def cleanup(req)
|
43
|
-
::Libuv::Ext.fs_req_cleanup(req)
|
44
|
-
::Libuv::Ext.free(req)
|
45
|
-
end
|
46
|
-
|
47
|
-
def post_check(req, deferrable)
|
48
|
-
error = check_result(req[:result])
|
49
|
-
if error
|
50
|
-
cleanup(req)
|
51
|
-
deferrable.reject(error)
|
52
|
-
false
|
53
|
-
else
|
54
|
-
true
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
1
|
+
|
2
|
+
module Libuv
|
3
|
+
module FsChecks
|
4
|
+
|
5
|
+
|
6
|
+
def stat
|
7
|
+
@stat_deferred = @loop.defer
|
8
|
+
|
9
|
+
request = ::Libuv::Ext.create_request(:uv_fs)
|
10
|
+
pre_check @stat_deferred, request, ::Libuv::Ext.fs_fstat(@loop.handle, request, @fileno, callback(:on_stat))
|
11
|
+
@stat_deferred.promise
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
|
18
|
+
def on_stat(req)
|
19
|
+
if post_check(req, @stat_deferred)
|
20
|
+
uv_stat = req[:stat]
|
21
|
+
uv_members = uv_stat.members
|
22
|
+
|
23
|
+
stats = {}
|
24
|
+
uv_members.each do |key|
|
25
|
+
stats[key] = uv_stat[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
cleanup(req)
|
29
|
+
@stat_deferred.resolve(stats)
|
30
|
+
end
|
31
|
+
@stat_deferred = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def pre_check(deferrable, request, result)
|
35
|
+
error = check_result result
|
36
|
+
if error
|
37
|
+
::Libuv::Ext.free(request)
|
38
|
+
deferrable.reject(error)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def cleanup(req)
|
43
|
+
::Libuv::Ext.fs_req_cleanup(req)
|
44
|
+
::Libuv::Ext.free(req)
|
45
|
+
end
|
46
|
+
|
47
|
+
def post_check(req, deferrable)
|
48
|
+
error = check_result(req[:result])
|
49
|
+
if error
|
50
|
+
cleanup(req)
|
51
|
+
deferrable.reject(error)
|
52
|
+
false
|
53
|
+
else
|
54
|
+
true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -1,34 +1,34 @@
|
|
1
|
-
require 'thread_safe'
|
2
|
-
require 'set'
|
3
|
-
|
4
|
-
module Libuv
|
5
|
-
module Listener
|
6
|
-
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
|
11
|
-
CALLBACKS = ThreadSafe::Cache.new
|
12
|
-
|
13
|
-
|
14
|
-
def callbacks
|
15
|
-
@callbacks ||= Set.new
|
16
|
-
end
|
17
|
-
|
18
|
-
def callback(name)
|
19
|
-
const_name = "#{name}_#{object_id}".to_sym
|
20
|
-
unless CALLBACKS[const_name]
|
21
|
-
callbacks << const_name
|
22
|
-
CALLBACKS[const_name] = method(name)
|
23
|
-
end
|
24
|
-
CALLBACKS[const_name]
|
25
|
-
end
|
26
|
-
|
27
|
-
def clear_callbacks
|
28
|
-
callbacks.each do |name|
|
29
|
-
CALLBACKS.delete(name)
|
30
|
-
end
|
31
|
-
callbacks.clear
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
require 'thread_safe'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
module Libuv
|
5
|
+
module Listener
|
6
|
+
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
|
11
|
+
CALLBACKS = ThreadSafe::Cache.new
|
12
|
+
|
13
|
+
|
14
|
+
def callbacks
|
15
|
+
@callbacks ||= Set.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def callback(name)
|
19
|
+
const_name = "#{name}_#{object_id}".to_sym
|
20
|
+
unless CALLBACKS[const_name]
|
21
|
+
callbacks << const_name
|
22
|
+
CALLBACKS[const_name] = method(name)
|
23
|
+
end
|
24
|
+
CALLBACKS[const_name]
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_callbacks
|
28
|
+
callbacks.each do |name|
|
29
|
+
CALLBACKS.delete(name)
|
30
|
+
end
|
31
|
+
callbacks.clear
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/libuv/mixins/net.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
module Libuv
|
4
|
-
module Net
|
5
|
-
|
6
|
-
|
7
|
-
IP_ARGUMENT_ERROR = "ip must be a String".freeze # Arguments specifying an IP address
|
8
|
-
PORT_ARGUMENT_ERROR = "port must be an Integer".freeze # Arguments specifying an IP port
|
9
|
-
INET_ADDRSTRLEN = 16
|
10
|
-
INET6_ADDRSTRLEN = 46
|
11
|
-
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
|
16
|
-
def get_sockaddr_and_len
|
17
|
-
sockaddr = FFI::MemoryPointer.new(::Libuv::Ext::Sockaddr)
|
18
|
-
len = FFI::MemoryPointer.new(:int)
|
19
|
-
len.put_int(0, ::Libuv::Ext::Sockaddr.size)
|
20
|
-
[sockaddr, len]
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_ip_and_port(sockaddr, len = nil)
|
24
|
-
if sockaddr[:sa_family] == Socket::Constants::AF_INET6
|
25
|
-
len ||= INET6_ADDRSTRLEN
|
26
|
-
sockaddr_in6 = ::Libuv::Ext::SockaddrIn6.new(sockaddr.pointer)
|
27
|
-
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
28
|
-
::Libuv::Ext.ip6_name(sockaddr_in6, ip_ptr, len)
|
29
|
-
port = ::Libuv::Ext.ntohs(sockaddr_in6[:sin6_port])
|
30
|
-
else
|
31
|
-
len ||= INET_ADDRSTRLEN
|
32
|
-
sockaddr_in = ::Libuv::Ext::SockaddrIn.new(sockaddr.pointer)
|
33
|
-
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
34
|
-
::Libuv::Ext.ip4_name(sockaddr_in, ip_ptr, len)
|
35
|
-
port = ::Libuv::Ext.ntohs(sockaddr_in[:sin_port])
|
36
|
-
end
|
37
|
-
[ip_ptr.read_string, port]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Libuv
|
4
|
+
module Net
|
5
|
+
|
6
|
+
|
7
|
+
IP_ARGUMENT_ERROR = "ip must be a String".freeze # Arguments specifying an IP address
|
8
|
+
PORT_ARGUMENT_ERROR = "port must be an Integer".freeze # Arguments specifying an IP port
|
9
|
+
INET_ADDRSTRLEN = 16
|
10
|
+
INET6_ADDRSTRLEN = 46
|
11
|
+
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
|
16
|
+
def get_sockaddr_and_len
|
17
|
+
sockaddr = FFI::MemoryPointer.new(::Libuv::Ext::Sockaddr)
|
18
|
+
len = FFI::MemoryPointer.new(:int)
|
19
|
+
len.put_int(0, ::Libuv::Ext::Sockaddr.size)
|
20
|
+
[sockaddr, len]
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_ip_and_port(sockaddr, len = nil)
|
24
|
+
if sockaddr[:sa_family] == Socket::Constants::AF_INET6
|
25
|
+
len ||= INET6_ADDRSTRLEN
|
26
|
+
sockaddr_in6 = ::Libuv::Ext::SockaddrIn6.new(sockaddr.pointer)
|
27
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
28
|
+
::Libuv::Ext.ip6_name(sockaddr_in6, ip_ptr, len)
|
29
|
+
port = ::Libuv::Ext.ntohs(sockaddr_in6[:sin6_port])
|
30
|
+
else
|
31
|
+
len ||= INET_ADDRSTRLEN
|
32
|
+
sockaddr_in = ::Libuv::Ext::SockaddrIn.new(sockaddr.pointer)
|
33
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
34
|
+
::Libuv::Ext.ip4_name(sockaddr_in, ip_ptr, len)
|
35
|
+
port = ::Libuv::Ext.ntohs(sockaddr_in[:sin_port])
|
36
|
+
end
|
37
|
+
[ip_ptr.read_string, port]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,28 +1,28 @@
|
|
1
|
-
module Libuv
|
2
|
-
module Resource
|
3
|
-
|
4
|
-
|
5
|
-
def resolve(deferred, rc)
|
6
|
-
if rc && rc < 0
|
7
|
-
deferred.reject(@loop.lookup_error(rc))
|
8
|
-
else
|
9
|
-
deferred.resolve(nil)
|
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
|
1
|
+
module Libuv
|
2
|
+
module Resource
|
3
|
+
|
4
|
+
|
5
|
+
def resolve(deferred, rc)
|
6
|
+
if rc && rc < 0
|
7
|
+
deferred.reject(@loop.lookup_error(rc))
|
8
|
+
else
|
9
|
+
deferred.resolve(nil)
|
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
28
|
end
|
data/lib/libuv/mixins/stream.rb
CHANGED
@@ -1,155 +1,155 @@
|
|
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
|
-
STREAM_CLOSED_ERROR = "unable to write to a closed stream".freeze
|
8
|
-
CLOSED_HANDLE_ERROR = "handle closed before accept called".freeze
|
9
|
-
|
10
|
-
|
11
|
-
def listen(backlog)
|
12
|
-
return if @closed
|
13
|
-
assert_type(Integer, backlog, BACKLOG_ERROR)
|
14
|
-
error = check_result ::Libuv::Ext.listen(handle, Integer(backlog), callback(:on_listen))
|
15
|
-
reject(error) if error
|
16
|
-
end
|
17
|
-
|
18
|
-
# Starts reading from the handle
|
19
|
-
def start_read
|
20
|
-
return if @closed
|
21
|
-
error = check_result ::Libuv::Ext.read_start(handle, callback(:on_allocate), callback(:on_read))
|
22
|
-
reject(error) if error
|
23
|
-
end
|
24
|
-
|
25
|
-
# Stops reading from the handle
|
26
|
-
def stop_read
|
27
|
-
return if @closed
|
28
|
-
error = check_result ::Libuv::Ext.read_stop(handle)
|
29
|
-
reject(error) if error
|
30
|
-
end
|
31
|
-
|
32
|
-
# Shutsdown the writes on the handle waiting until the last write is complete before triggering the callback
|
33
|
-
def shutdown
|
34
|
-
return if @closed
|
35
|
-
error = check_result ::Libuv::Ext.shutdown(::Libuv::Ext.create_request(:uv_shutdown), handle, callback(:on_shutdown))
|
36
|
-
reject(error) if error
|
37
|
-
end
|
38
|
-
|
39
|
-
def write(data)
|
40
|
-
# NOTE:: Similar to udp.rb -> send
|
41
|
-
deferred = @loop.defer
|
42
|
-
if !@closed
|
43
|
-
begin
|
44
|
-
assert_type(String, data, WRITE_ERROR)
|
45
|
-
|
46
|
-
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
47
|
-
buffer = ::Libuv::Ext.buf_init(FFI::MemoryPointer.from_string(data), size)
|
48
|
-
|
49
|
-
# local as this variable will be avaliable until the handle is closed
|
50
|
-
@write_callbacks ||= []
|
51
|
-
|
52
|
-
#
|
53
|
-
# create the curried callback
|
54
|
-
#
|
55
|
-
callback = FFI::Function.new(:void, [:pointer, :int]) do |req, status|
|
56
|
-
::Libuv::Ext.free(req)
|
57
|
-
# remove the callback from the array
|
58
|
-
# assumes writes are done in order
|
59
|
-
promise = @write_callbacks.shift[0]
|
60
|
-
resolve promise, status
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
@write_callbacks << [deferred, callback]
|
65
|
-
req = ::Libuv::Ext.create_request(:uv_write)
|
66
|
-
error = check_result ::Libuv::Ext.write(req, handle, buffer, 1, callback)
|
67
|
-
|
68
|
-
if error
|
69
|
-
@write_callbacks.pop
|
70
|
-
::Libuv::Ext.free(req)
|
71
|
-
deferred.reject(error)
|
72
|
-
|
73
|
-
reject(error) # close the handle
|
74
|
-
end
|
75
|
-
rescue Exception => e
|
76
|
-
deferred.reject(e) # this write exception may not be fatal
|
77
|
-
end
|
78
|
-
else
|
79
|
-
deferred.reject(RuntimeError.new(STREAM_CLOSED_ERROR))
|
80
|
-
end
|
81
|
-
deferred.promise
|
82
|
-
end
|
83
|
-
|
84
|
-
def readable?
|
85
|
-
return false if @closed
|
86
|
-
::Libuv::Ext.is_readable(handle) > 0
|
87
|
-
end
|
88
|
-
|
89
|
-
def writable?
|
90
|
-
return false if @closed
|
91
|
-
::Libuv::Ext.is_writable(handle) > 0
|
92
|
-
end
|
93
|
-
|
94
|
-
def progress(callback = nil, &blk)
|
95
|
-
@progress = callback || blk
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
|
102
|
-
def on_listen(server, status)
|
103
|
-
e = check_result(status)
|
104
|
-
|
105
|
-
if e
|
106
|
-
reject(e) # is this cause for closing the handle?
|
107
|
-
else
|
108
|
-
begin
|
109
|
-
@on_listen.call(self)
|
110
|
-
rescue Exception => e
|
111
|
-
@loop.log :error, :stream_listen_cb, e
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def on_allocate(client, suggested_size, buffer)
|
117
|
-
buffer[:len] = suggested_size
|
118
|
-
buffer[:base] = ::Libuv::Ext.malloc(suggested_size)
|
119
|
-
end
|
120
|
-
|
121
|
-
def on_read(handle, nread, buf)
|
122
|
-
e = check_result(nread)
|
123
|
-
base = buf[:base]
|
124
|
-
|
125
|
-
if e
|
126
|
-
::Libuv::Ext.free(base)
|
127
|
-
# I assume this is desirable behaviour
|
128
|
-
if e.is_a? ::Libuv::Error::EOF
|
129
|
-
close # Close gracefully
|
130
|
-
else
|
131
|
-
reject(e)
|
132
|
-
end
|
133
|
-
else
|
134
|
-
data = base.read_string(nread)
|
135
|
-
::Libuv::Ext.free(base)
|
136
|
-
|
137
|
-
if @tls.nil?
|
138
|
-
begin
|
139
|
-
@progress.call data, self
|
140
|
-
rescue Exception => e
|
141
|
-
@loop.log :error, :stream_progress_cb, e
|
142
|
-
end
|
143
|
-
else
|
144
|
-
@tls.decrypt(data)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def on_shutdown(req, status)
|
150
|
-
::Libuv::Ext.free(req)
|
151
|
-
@close_error = check_result(status)
|
152
|
-
close
|
153
|
-
end
|
154
|
-
end
|
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
|
+
STREAM_CLOSED_ERROR = "unable to write to a closed stream".freeze
|
8
|
+
CLOSED_HANDLE_ERROR = "handle closed before accept called".freeze
|
9
|
+
|
10
|
+
|
11
|
+
def listen(backlog)
|
12
|
+
return if @closed
|
13
|
+
assert_type(Integer, backlog, BACKLOG_ERROR)
|
14
|
+
error = check_result ::Libuv::Ext.listen(handle, Integer(backlog), callback(:on_listen))
|
15
|
+
reject(error) if error
|
16
|
+
end
|
17
|
+
|
18
|
+
# Starts reading from the handle
|
19
|
+
def start_read
|
20
|
+
return if @closed
|
21
|
+
error = check_result ::Libuv::Ext.read_start(handle, callback(:on_allocate), callback(:on_read))
|
22
|
+
reject(error) if error
|
23
|
+
end
|
24
|
+
|
25
|
+
# Stops reading from the handle
|
26
|
+
def stop_read
|
27
|
+
return if @closed
|
28
|
+
error = check_result ::Libuv::Ext.read_stop(handle)
|
29
|
+
reject(error) if error
|
30
|
+
end
|
31
|
+
|
32
|
+
# Shutsdown the writes on the handle waiting until the last write is complete before triggering the callback
|
33
|
+
def shutdown
|
34
|
+
return if @closed
|
35
|
+
error = check_result ::Libuv::Ext.shutdown(::Libuv::Ext.create_request(:uv_shutdown), handle, callback(:on_shutdown))
|
36
|
+
reject(error) if error
|
37
|
+
end
|
38
|
+
|
39
|
+
def write(data)
|
40
|
+
# NOTE:: Similar to udp.rb -> send
|
41
|
+
deferred = @loop.defer
|
42
|
+
if !@closed
|
43
|
+
begin
|
44
|
+
assert_type(String, data, WRITE_ERROR)
|
45
|
+
|
46
|
+
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
47
|
+
buffer = ::Libuv::Ext.buf_init(FFI::MemoryPointer.from_string(data), size)
|
48
|
+
|
49
|
+
# local as this variable will be avaliable until the handle is closed
|
50
|
+
@write_callbacks ||= []
|
51
|
+
|
52
|
+
#
|
53
|
+
# create the curried callback
|
54
|
+
#
|
55
|
+
callback = FFI::Function.new(:void, [:pointer, :int]) do |req, status|
|
56
|
+
::Libuv::Ext.free(req)
|
57
|
+
# remove the callback from the array
|
58
|
+
# assumes writes are done in order
|
59
|
+
promise = @write_callbacks.shift[0]
|
60
|
+
resolve promise, status
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
@write_callbacks << [deferred, callback]
|
65
|
+
req = ::Libuv::Ext.create_request(:uv_write)
|
66
|
+
error = check_result ::Libuv::Ext.write(req, handle, buffer, 1, callback)
|
67
|
+
|
68
|
+
if error
|
69
|
+
@write_callbacks.pop
|
70
|
+
::Libuv::Ext.free(req)
|
71
|
+
deferred.reject(error)
|
72
|
+
|
73
|
+
reject(error) # close the handle
|
74
|
+
end
|
75
|
+
rescue Exception => e
|
76
|
+
deferred.reject(e) # this write exception may not be fatal
|
77
|
+
end
|
78
|
+
else
|
79
|
+
deferred.reject(RuntimeError.new(STREAM_CLOSED_ERROR))
|
80
|
+
end
|
81
|
+
deferred.promise
|
82
|
+
end
|
83
|
+
|
84
|
+
def readable?
|
85
|
+
return false if @closed
|
86
|
+
::Libuv::Ext.is_readable(handle) > 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def writable?
|
90
|
+
return false if @closed
|
91
|
+
::Libuv::Ext.is_writable(handle) > 0
|
92
|
+
end
|
93
|
+
|
94
|
+
def progress(callback = nil, &blk)
|
95
|
+
@progress = callback || blk
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
|
102
|
+
def on_listen(server, status)
|
103
|
+
e = check_result(status)
|
104
|
+
|
105
|
+
if e
|
106
|
+
reject(e) # is this cause for closing the handle?
|
107
|
+
else
|
108
|
+
begin
|
109
|
+
@on_listen.call(self)
|
110
|
+
rescue Exception => e
|
111
|
+
@loop.log :error, :stream_listen_cb, e
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def on_allocate(client, suggested_size, buffer)
|
117
|
+
buffer[:len] = suggested_size
|
118
|
+
buffer[:base] = ::Libuv::Ext.malloc(suggested_size)
|
119
|
+
end
|
120
|
+
|
121
|
+
def on_read(handle, nread, buf)
|
122
|
+
e = check_result(nread)
|
123
|
+
base = buf[:base]
|
124
|
+
|
125
|
+
if e
|
126
|
+
::Libuv::Ext.free(base)
|
127
|
+
# I assume this is desirable behaviour
|
128
|
+
if e.is_a? ::Libuv::Error::EOF
|
129
|
+
close # Close gracefully
|
130
|
+
else
|
131
|
+
reject(e)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
data = base.read_string(nread)
|
135
|
+
::Libuv::Ext.free(base)
|
136
|
+
|
137
|
+
if @tls.nil?
|
138
|
+
begin
|
139
|
+
@progress.call data, self
|
140
|
+
rescue Exception => e
|
141
|
+
@loop.log :error, :stream_progress_cb, e
|
142
|
+
end
|
143
|
+
else
|
144
|
+
@tls.decrypt(data)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def on_shutdown(req, status)
|
150
|
+
::Libuv::Ext.free(req)
|
151
|
+
@close_error = check_result(status)
|
152
|
+
close
|
153
|
+
end
|
154
|
+
end
|
155
155
|
end
|