uvrb 0.1.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.
- data/.gitignore +17 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.travis.yml +13 -0
- data/Formula/libuv.rb +20 -0
- data/Gemfile +3 -0
- data/LICENSE +24 -0
- data/README.rdoc +70 -0
- data/Rakefile +29 -0
- data/examples/example +0 -0
- data/examples/example.c +37 -0
- data/examples/example.rb +29 -0
- data/examples/example_oop.rb +26 -0
- data/examples/python.py +1 -0
- data/examples/ruby.rb +1 -0
- data/examples/tcp_client_oop.rb +31 -0
- data/examples/tcp_example +0 -0
- data/examples/tcp_example.c +68 -0
- data/examples/tcp_example.rb +41 -0
- data/examples/tcp_example_oop.rb +43 -0
- data/examples/tcp_example_plain.rb +19 -0
- data/examples/tty_example.rb +20 -0
- data/features/async.feature +38 -0
- data/features/idle.feature +44 -0
- data/features/pipe.feature +150 -0
- data/features/prepare_and_check.feature +49 -0
- data/features/step_definitions/additional_cli_steps.rb +20 -0
- data/features/support/env.rb +6 -0
- data/lib/uv.rb +248 -0
- data/lib/uv/assertions.rb +24 -0
- data/lib/uv/async.rb +24 -0
- data/lib/uv/check.rb +27 -0
- data/lib/uv/error.rb +58 -0
- data/lib/uv/file.rb +221 -0
- data/lib/uv/file/stat.rb +35 -0
- data/lib/uv/filesystem.rb +335 -0
- data/lib/uv/fs_event.rb +21 -0
- data/lib/uv/handle.rb +65 -0
- data/lib/uv/idle.rb +27 -0
- data/lib/uv/listener.rb +26 -0
- data/lib/uv/loop.rb +326 -0
- data/lib/uv/net.rb +31 -0
- data/lib/uv/pipe.rb +47 -0
- data/lib/uv/prepare.rb +27 -0
- data/lib/uv/resource.rb +20 -0
- data/lib/uv/stream.rb +105 -0
- data/lib/uv/tasks.rb +27 -0
- data/lib/uv/tasks/mac.rb +23 -0
- data/lib/uv/tasks/unix.rb +23 -0
- data/lib/uv/tasks/win.rb +2 -0
- data/lib/uv/tcp.rb +162 -0
- data/lib/uv/timer.rb +48 -0
- data/lib/uv/tty.rb +30 -0
- data/lib/uv/types.rb +249 -0
- data/lib/uv/types/darwin_x64.rb +10 -0
- data/lib/uv/types/linux.rb +6 -0
- data/lib/uv/types/unix.rb +12 -0
- data/lib/uv/types/windows.rb +13 -0
- data/lib/uv/udp.rb +215 -0
- data/lib/uv/version.rb +3 -0
- data/lib/uvrb.rb +1 -0
- data/spec/shared_examples/handle.rb +54 -0
- data/spec/shared_examples/stream.rb +109 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/uv/async_spec.rb +18 -0
- data/spec/uv/check_spec.rb +30 -0
- data/spec/uv/file_spec.rb +177 -0
- data/spec/uv/filesystem_spec.rb +246 -0
- data/spec/uv/fs_event_spec.rb +10 -0
- data/spec/uv/idle_spec.rb +30 -0
- data/spec/uv/loop_spec.rb +241 -0
- data/spec/uv/pipe_spec.rb +54 -0
- data/spec/uv/prepare_spec.rb +30 -0
- data/spec/uv/tcp_spec.rb +134 -0
- data/spec/uv/timer_spec.rb +61 -0
- data/spec/uv/tty_spec.rb +53 -0
- data/spec/uv/udp_spec.rb +190 -0
- data/uvrb.gemspec +28 -0
- metadata +247 -0
data/lib/uv/net.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module UV
|
4
|
+
module Net
|
5
|
+
private
|
6
|
+
|
7
|
+
def get_sockaddr_and_len
|
8
|
+
sockaddr = FFI::MemoryPointer.new(UV::Sockaddr)
|
9
|
+
len = FFI::MemoryPointer.new(:int)
|
10
|
+
len.put_int(0, UV::Sockaddr.size)
|
11
|
+
[sockaddr, len]
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_ip_and_port(sockaddr, len=nil)
|
15
|
+
if sockaddr[:sa_family] == Socket::Constants::AF_INET6
|
16
|
+
len ||= Socket::Constants::INET6_ADDRSTRLEN
|
17
|
+
sockaddr_in6 = UV::SockaddrIn6.new(sockaddr.pointer)
|
18
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
19
|
+
UV.ip6_name(sockaddr_in6, ip_ptr, len)
|
20
|
+
port = UV.ntohs(sockaddr_in6[:sin6_port])
|
21
|
+
else
|
22
|
+
len ||= Socket::Constants::INET_ADDRSTRLEN
|
23
|
+
sockaddr_in = UV::SockaddrIn.new(sockaddr.pointer)
|
24
|
+
ip_ptr = FFI::MemoryPointer.new(:char, len)
|
25
|
+
UV.ip4_name(sockaddr_in, ip_ptr, len)
|
26
|
+
port = UV.ntohs(sockaddr_in[:sin_port])
|
27
|
+
end
|
28
|
+
[ip_ptr.read_string, port]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/uv/pipe.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module UV
|
2
|
+
class Pipe
|
3
|
+
include Stream
|
4
|
+
|
5
|
+
def open(fileno)
|
6
|
+
assert_type(Integer, fileno, "io#fileno must return an integer file descriptor")
|
7
|
+
|
8
|
+
check_result! UV.pipe_open(handle, fileno)
|
9
|
+
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def bind(name)
|
14
|
+
assert_type(String, name, "name must be a String")
|
15
|
+
|
16
|
+
check_result! UV.pipe_bind(handle, name)
|
17
|
+
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect(name, &block)
|
22
|
+
assert_block(block)
|
23
|
+
assert_arity(1, block)
|
24
|
+
assert_type(String, name, "name must be a String")
|
25
|
+
|
26
|
+
@connect_block = block
|
27
|
+
|
28
|
+
UV.pipe_connect(UV.create_request(:uv_connect), handle, name, callback(:on_connect))
|
29
|
+
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def pending_instances=(count)
|
34
|
+
assert_type(Integer, count, "count must be an Integer")
|
35
|
+
|
36
|
+
UV.pipe_pending_instances(handle, count)
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def on_connect(req, status)
|
43
|
+
UV.free(req)
|
44
|
+
@connect_block.call(check_result(status))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/uv/prepare.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module UV
|
2
|
+
class Prepare
|
3
|
+
include Handle
|
4
|
+
|
5
|
+
def start(&block)
|
6
|
+
assert_block(block)
|
7
|
+
assert_arity(1, block)
|
8
|
+
|
9
|
+
@prepare_block = block
|
10
|
+
|
11
|
+
check_result! UV.prepare_start(handle, callback(:on_prepare))
|
12
|
+
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def stop
|
17
|
+
check_result! UV.prepare_stop(handle)
|
18
|
+
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def on_prepare(handle, status)
|
24
|
+
@prepare_block.call(check_result(status))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/uv/resource.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module UV
|
2
|
+
module Resource
|
3
|
+
def check_result(rc)
|
4
|
+
@loop.last_error if rc == -1
|
5
|
+
end
|
6
|
+
|
7
|
+
def check_result!(rc)
|
8
|
+
e = check_result(rc)
|
9
|
+
raise e if e
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_ptr
|
13
|
+
@pointer
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
attr_reader :loop
|
19
|
+
end
|
20
|
+
end
|
data/lib/uv/stream.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
module UV
|
2
|
+
module Stream
|
3
|
+
include Handle
|
4
|
+
|
5
|
+
def listen(backlog, &block)
|
6
|
+
assert_block(block)
|
7
|
+
assert_arity(1, block)
|
8
|
+
assert_type(Integer, backlog, "backlog must be an Integer")
|
9
|
+
|
10
|
+
@listen_block = block
|
11
|
+
|
12
|
+
check_result! UV.listen(handle, Integer(backlog), callback(:on_listen))
|
13
|
+
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def accept
|
18
|
+
client = loop.send(handle_name)
|
19
|
+
|
20
|
+
check_result! UV.accept(handle, client.handle)
|
21
|
+
|
22
|
+
client
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_read(&block)
|
26
|
+
assert_block(block)
|
27
|
+
assert_arity(2, block)
|
28
|
+
|
29
|
+
@read_block = block
|
30
|
+
|
31
|
+
check_result! UV.read_start(handle, callback(:on_allocate), callback(:on_read))
|
32
|
+
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def stop_read
|
37
|
+
check_result! UV.read_stop(handle)
|
38
|
+
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def write(data, &block)
|
43
|
+
assert_block(block)
|
44
|
+
assert_arity(1, block)
|
45
|
+
assert_type(String, data, "data must be a String")
|
46
|
+
|
47
|
+
@write_block = block
|
48
|
+
size = data.respond_to?(:bytesize) ? data.bytesize : data.size
|
49
|
+
buffer = UV.buf_init(FFI::MemoryPointer.from_string(data), size)
|
50
|
+
|
51
|
+
check_result! UV.write(UV.create_request(:uv_write), handle, buffer, 1, callback(:on_write))
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def shutdown(&block)
|
57
|
+
assert_block(block)
|
58
|
+
assert_arity(1, block)
|
59
|
+
|
60
|
+
@shutdown_block = block
|
61
|
+
|
62
|
+
check_result! UV.shutdown(UV.create_request(:uv_shutdown), handle, callback(:on_shutdown))
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def readable?
|
68
|
+
UV.is_readable(handle) > 0
|
69
|
+
end
|
70
|
+
|
71
|
+
def writable?
|
72
|
+
UV.is_writable(handle) > 0
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def on_listen(server, status)
|
78
|
+
@listen_block.call(check_result(status))
|
79
|
+
end
|
80
|
+
|
81
|
+
def on_allocate(client, suggested_size)
|
82
|
+
UV.buf_init(UV.malloc(suggested_size), suggested_size)
|
83
|
+
end
|
84
|
+
|
85
|
+
def on_read(handle, nread, buf)
|
86
|
+
e = check_result(nread)
|
87
|
+
base = buf[:base]
|
88
|
+
unless e
|
89
|
+
data = base.read_string(nread)
|
90
|
+
end
|
91
|
+
UV.free(base)
|
92
|
+
@read_block.call(e, data)
|
93
|
+
end
|
94
|
+
|
95
|
+
def on_write(req, status)
|
96
|
+
UV.free(req)
|
97
|
+
@write_block.call(check_result(status))
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_shutdown(req, status)
|
101
|
+
UV.free(req)
|
102
|
+
@shutdown_block.call(check_result(status))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/uv/tasks.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module FFI::Platform
|
2
|
+
def self.ia32?
|
3
|
+
ARCH == "i386"
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.x64?
|
7
|
+
ARCH == "x86_64"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
file 'ext/libuv/build' do
|
12
|
+
system "git", "submodule", "update", "--init"
|
13
|
+
end
|
14
|
+
|
15
|
+
file 'ext/libuv/build/gyp' => 'ext/libuv/build' do
|
16
|
+
system "svn", "export", "-r1214", "http://gyp.googlecode.com/svn/trunk", "ext/libuv/build/gyp"
|
17
|
+
end
|
18
|
+
|
19
|
+
CLEAN.include('ext/libuv/build/gyp')
|
20
|
+
|
21
|
+
if FFI::Platform.windows?
|
22
|
+
require 'uv/tasks/win'
|
23
|
+
elsif FFI::Platform.mac?
|
24
|
+
require 'uv/tasks/mac'
|
25
|
+
else # UNIX
|
26
|
+
require 'uv/tasks/unix'
|
27
|
+
end
|
data/lib/uv/tasks/mac.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
file 'ext/libuv/uv.xcodeproj' => 'ext/libuv/build/gyp' do
|
2
|
+
target_arch = 'ia32'if FFI::Platform.ia32?
|
3
|
+
target_arch = 'x64' if FFI::Platform.x64?
|
4
|
+
|
5
|
+
abort "Don't know how to build on #{FFI::Platform::ARCH} (yet)" unless target_arch
|
6
|
+
|
7
|
+
Dir.chdir("ext/libuv") do |path|
|
8
|
+
system "./gyp_uv -f xcode -Dtarget_arch=#{target_arch}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
file "ext/libuv/build/Release/libuv.#{FFI::Platform::LIBSUFFIX}" => 'ext/libuv/uv.xcodeproj' do
|
13
|
+
Dir.chdir("ext/libuv") do |path|
|
14
|
+
system 'xcodebuild -project uv.xcodeproj -configuration Release -target All'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
file "ext/libuv.#{FFI::Platform::LIBSUFFIX}" => "ext/libuv/build/Release/libuv.#{FFI::Platform::LIBSUFFIX}" do
|
19
|
+
File.symlink("libuv/build/Release/libuv.#{FFI::Platform::LIBSUFFIX}", "ext/libuv.#{FFI::Platform::LIBSUFFIX}")
|
20
|
+
end
|
21
|
+
|
22
|
+
CLEAN.include('ext/libuv/uv.xcodeproj')
|
23
|
+
CLOBBER.include("ext/libuv/build/Release/libuv.#{FFI::Platform::LIBSUFFIX}")
|
@@ -0,0 +1,23 @@
|
|
1
|
+
file 'ext/libuv/out' => 'ext/libuv/build/gyp' do
|
2
|
+
target_arch = 'ia32'if FFI::Platform.ia32?
|
3
|
+
target_arch = 'x64' if FFI::Platform.x64?
|
4
|
+
|
5
|
+
abort "Don't know how to build on #{FFI::Platform::ARCH} (yet)" unless target_arch
|
6
|
+
|
7
|
+
Dir.chdir("ext/libuv") do |path|
|
8
|
+
system "./gyp_uv -f make -Dtarget_arch=#{target_arch}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
file "ext/libuv/out/Release/lib.target/libuv.#{FFI::Platform::LIBSUFFIX}" => 'ext/libuv/out' do
|
13
|
+
Dir.chdir("ext/libuv") do |path|
|
14
|
+
system 'make -C out BUILDTYPE=Release'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
file "ext/libuv.#{FFI::Platform::LIBSUFFIX}" => "ext/libuv/out/Release/lib.target/libuv.#{FFI::Platform::LIBSUFFIX}" do
|
19
|
+
File.symlink("libuv/out/Release/lib.target/libuv.#{FFI::Platform::LIBSUFFIX}", "ext/libuv.#{FFI::Platform::LIBSUFFIX}")
|
20
|
+
end
|
21
|
+
|
22
|
+
CLEAN.include('ext/libuv/out')
|
23
|
+
CLOBBER.include("ext/libuv/out/Release/lib.target/libuv.#{FFI::Platform::LIBSUFFIX}")
|
data/lib/uv/tasks/win.rb
ADDED
data/lib/uv/tcp.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
|
3
|
+
module UV
|
4
|
+
class TCP
|
5
|
+
include Stream, Net
|
6
|
+
|
7
|
+
def bind(ip, port)
|
8
|
+
assert_type(String, ip, "ip must be a String")
|
9
|
+
assert_type(Integer, port, "port must be an Integer")
|
10
|
+
|
11
|
+
@socket = create_socket(IPAddr.new(ip), port)
|
12
|
+
|
13
|
+
@socket.bind
|
14
|
+
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def connect(ip, port, &block)
|
19
|
+
assert_block(block)
|
20
|
+
assert_arity(1, block)
|
21
|
+
assert_type(String, ip, "ip must be a String")
|
22
|
+
assert_type(Integer, port, "port must be an Integer")
|
23
|
+
|
24
|
+
@connect_block = block
|
25
|
+
@socket = create_socket(IPAddr.new(ip), port)
|
26
|
+
|
27
|
+
@socket.connect(callback(:on_connect))
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def sockname
|
33
|
+
sockaddr, len = get_sockaddr_and_len
|
34
|
+
check_result! UV.tcp_getsockname(handle, sockaddr, len)
|
35
|
+
get_ip_and_port(UV::Sockaddr.new(sockaddr), len.get_int(0))
|
36
|
+
end
|
37
|
+
|
38
|
+
def peername
|
39
|
+
sockaddr, len = get_sockaddr_and_len
|
40
|
+
check_result! UV.tcp_getpeername(handle, sockaddr, len)
|
41
|
+
get_ip_and_port(UV::Sockaddr.new(sockaddr), len.get_int(0))
|
42
|
+
end
|
43
|
+
|
44
|
+
def enable_nodelay
|
45
|
+
check_result! UV.tcp_nodelay(handle, 1)
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def disable_nodelay
|
51
|
+
check_result! UV.tcp_nodelay(handle, 0)
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
def enable_keepalive(delay)
|
57
|
+
assert_type(Integer, delay, "delay must be an Integer")
|
58
|
+
|
59
|
+
check_result! UV.tcp_keepalive(handle, 1, delay)
|
60
|
+
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def disable_keepalive
|
65
|
+
check_result! UV.tcp_keepalive(handle, 0, 0)
|
66
|
+
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def enable_simultaneous_accepts
|
71
|
+
check_result! UV.tcp_simultaneous_accepts(handle, 1)
|
72
|
+
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def disable_simultaneous_accepts
|
77
|
+
check_result! UV.tcp_simultaneous_accepts(handle, 0)
|
78
|
+
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
def create_socket(ip, port)
|
84
|
+
if ip.ipv4?
|
85
|
+
Socket4.new(@loop, handle, ip.to_s, port)
|
86
|
+
else
|
87
|
+
Socket6.new(@loop, handle, ip.to_s, port)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def on_connect(req, status)
|
92
|
+
UV.free(req)
|
93
|
+
@connect_block.call(check_result(status))
|
94
|
+
end
|
95
|
+
|
96
|
+
module SocketMethods
|
97
|
+
include Resource
|
98
|
+
|
99
|
+
def initialize(loop, tcp, ip, port)
|
100
|
+
@loop, @tcp, @sockaddr = loop, tcp, ip_addr(ip, port)
|
101
|
+
end
|
102
|
+
|
103
|
+
def bind
|
104
|
+
check_result! tcp_bind
|
105
|
+
end
|
106
|
+
|
107
|
+
def connect(callback)
|
108
|
+
check_result! tcp_connect(callback)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def connect_req
|
114
|
+
UV.create_request(:uv_connect)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class Socket4
|
119
|
+
include SocketMethods
|
120
|
+
|
121
|
+
private
|
122
|
+
def ip_addr(ip, port)
|
123
|
+
UV.ip4_addr(ip, port)
|
124
|
+
end
|
125
|
+
|
126
|
+
def tcp_bind
|
127
|
+
UV.tcp_bind(@tcp, @sockaddr)
|
128
|
+
end
|
129
|
+
|
130
|
+
def tcp_connect(callback)
|
131
|
+
UV.tcp_connect(
|
132
|
+
connect_req,
|
133
|
+
@tcp,
|
134
|
+
@sockaddr,
|
135
|
+
callback
|
136
|
+
)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class Socket6
|
141
|
+
include SocketMethods
|
142
|
+
|
143
|
+
private
|
144
|
+
def ip_addr(ip, port)
|
145
|
+
UV.ip6_addr(ip, port)
|
146
|
+
end
|
147
|
+
|
148
|
+
def tcp_bind
|
149
|
+
UV.tcp_bind6(@tcp, @sockaddr)
|
150
|
+
end
|
151
|
+
|
152
|
+
def tcp_connect(callback)
|
153
|
+
UV.tcp_connect6(
|
154
|
+
connect_req,
|
155
|
+
@tcp,
|
156
|
+
@sockaddr,
|
157
|
+
callback
|
158
|
+
)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|