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.
Files changed (79) hide show
  1. data/.gitignore +17 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +13 -0
  5. data/Formula/libuv.rb +20 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE +24 -0
  8. data/README.rdoc +70 -0
  9. data/Rakefile +29 -0
  10. data/examples/example +0 -0
  11. data/examples/example.c +37 -0
  12. data/examples/example.rb +29 -0
  13. data/examples/example_oop.rb +26 -0
  14. data/examples/python.py +1 -0
  15. data/examples/ruby.rb +1 -0
  16. data/examples/tcp_client_oop.rb +31 -0
  17. data/examples/tcp_example +0 -0
  18. data/examples/tcp_example.c +68 -0
  19. data/examples/tcp_example.rb +41 -0
  20. data/examples/tcp_example_oop.rb +43 -0
  21. data/examples/tcp_example_plain.rb +19 -0
  22. data/examples/tty_example.rb +20 -0
  23. data/features/async.feature +38 -0
  24. data/features/idle.feature +44 -0
  25. data/features/pipe.feature +150 -0
  26. data/features/prepare_and_check.feature +49 -0
  27. data/features/step_definitions/additional_cli_steps.rb +20 -0
  28. data/features/support/env.rb +6 -0
  29. data/lib/uv.rb +248 -0
  30. data/lib/uv/assertions.rb +24 -0
  31. data/lib/uv/async.rb +24 -0
  32. data/lib/uv/check.rb +27 -0
  33. data/lib/uv/error.rb +58 -0
  34. data/lib/uv/file.rb +221 -0
  35. data/lib/uv/file/stat.rb +35 -0
  36. data/lib/uv/filesystem.rb +335 -0
  37. data/lib/uv/fs_event.rb +21 -0
  38. data/lib/uv/handle.rb +65 -0
  39. data/lib/uv/idle.rb +27 -0
  40. data/lib/uv/listener.rb +26 -0
  41. data/lib/uv/loop.rb +326 -0
  42. data/lib/uv/net.rb +31 -0
  43. data/lib/uv/pipe.rb +47 -0
  44. data/lib/uv/prepare.rb +27 -0
  45. data/lib/uv/resource.rb +20 -0
  46. data/lib/uv/stream.rb +105 -0
  47. data/lib/uv/tasks.rb +27 -0
  48. data/lib/uv/tasks/mac.rb +23 -0
  49. data/lib/uv/tasks/unix.rb +23 -0
  50. data/lib/uv/tasks/win.rb +2 -0
  51. data/lib/uv/tcp.rb +162 -0
  52. data/lib/uv/timer.rb +48 -0
  53. data/lib/uv/tty.rb +30 -0
  54. data/lib/uv/types.rb +249 -0
  55. data/lib/uv/types/darwin_x64.rb +10 -0
  56. data/lib/uv/types/linux.rb +6 -0
  57. data/lib/uv/types/unix.rb +12 -0
  58. data/lib/uv/types/windows.rb +13 -0
  59. data/lib/uv/udp.rb +215 -0
  60. data/lib/uv/version.rb +3 -0
  61. data/lib/uvrb.rb +1 -0
  62. data/spec/shared_examples/handle.rb +54 -0
  63. data/spec/shared_examples/stream.rb +109 -0
  64. data/spec/spec_helper.rb +26 -0
  65. data/spec/uv/async_spec.rb +18 -0
  66. data/spec/uv/check_spec.rb +30 -0
  67. data/spec/uv/file_spec.rb +177 -0
  68. data/spec/uv/filesystem_spec.rb +246 -0
  69. data/spec/uv/fs_event_spec.rb +10 -0
  70. data/spec/uv/idle_spec.rb +30 -0
  71. data/spec/uv/loop_spec.rb +241 -0
  72. data/spec/uv/pipe_spec.rb +54 -0
  73. data/spec/uv/prepare_spec.rb +30 -0
  74. data/spec/uv/tcp_spec.rb +134 -0
  75. data/spec/uv/timer_spec.rb +61 -0
  76. data/spec/uv/tty_spec.rb +53 -0
  77. data/spec/uv/udp_spec.rb +190 -0
  78. data/uvrb.gemspec +28 -0
  79. 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
@@ -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
@@ -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}")
@@ -0,0 +1,2 @@
1
+ abort "can't build on windows using this rake task (yet)"
2
+ configure_command = 'vcbuild.bat'
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