cool.io 1.3.0 → 1.3.1
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 +4 -4
- data/.gitignore +3 -0
- data/CHANGES.md +7 -0
- data/ext/cool.io/extconf.rb +8 -24
- data/ext/cool.io/loop.c +1 -1
- data/ext/iobuffer/iobuffer.c +2 -0
- data/ext/libev/ev.c +4 -3
- data/ext/libev/ev_select.c +19 -1
- data/lib/cool.io/dns_resolver.rb +1 -2
- data/lib/cool.io/io.rb +1 -1
- data/lib/cool.io/version.rb +1 -1
- data/spec/async_watcher_spec.rb +4 -4
- data/spec/dns_spec.rb +11 -7
- data/spec/iobuffer_spec.rb +147 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/stat_watcher_spec.rb +3 -3
- data/spec/tcp_server_spec.rb +97 -4
- data/spec/tcp_socket_spec.rb +171 -13
- data/spec/timer_watcher_spec.rb +23 -19
- data/spec/udp_socket_spec.rb +58 -0
- data/spec/unix_listener_spec.rb +6 -6
- data/spec/unix_server_spec.rb +6 -6
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69788383b1d7d04b499aed3a4c7430bde6af09cb
|
4
|
+
data.tar.gz: a5bd943271281ef7e72c886cf07b33ea98a7ca0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02ff98d0fa4b9b90ed484e5db28c88adcbf4dde3e27ee436282b5a2aab3ea0afe2cfe88d79b10cb643c717e1af0e93736b914112b42061ac640f4ae07a001e84
|
7
|
+
data.tar.gz: ec26d9e2759c5b999f82dbf8dcfac2f407aa571bf941df4b0a6761c00787b793d0574429b0be6887316cbe861c7eef661300c50d7a662f69f87618f7be2717e9
|
data/.gitignore
CHANGED
data/CHANGES.md
CHANGED
data/ext/cool.io/extconf.rb
CHANGED
@@ -4,25 +4,11 @@ libs = []
|
|
4
4
|
|
5
5
|
$defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
$defs << '-DHAVE_RB_THEREAD_CALL_WITHOUT_GVL'
|
13
|
-
end
|
14
|
-
|
15
|
-
if have_func('rb_thread_alone')
|
16
|
-
$defs << '-DHAVE_RB_THREAD_ALONE'
|
17
|
-
end
|
18
|
-
|
19
|
-
if have_func('rb_str_set_len')
|
20
|
-
$defs << '-DHAVE_RB_STR_SET_LEN'
|
21
|
-
end
|
22
|
-
|
23
|
-
if have_library('rt', 'clock_gettime')
|
24
|
-
libs << "-lrt"
|
25
|
-
end
|
7
|
+
have_func('rb_thread_blocking_region')
|
8
|
+
have_func('rb_thread_call_without_gvl')
|
9
|
+
have_func('rb_thread_alone')
|
10
|
+
have_func('rb_str_set_len')
|
11
|
+
have_library('rt', 'clock_gettime')
|
26
12
|
|
27
13
|
if have_header('sys/select.h')
|
28
14
|
$defs << '-DEV_USE_SELECT'
|
@@ -44,9 +30,7 @@ if have_header('port.h')
|
|
44
30
|
$defs << '-DEV_USE_PORT'
|
45
31
|
end
|
46
32
|
|
47
|
-
|
48
|
-
$defs << '-DHAVE_SYS_RESOURCE_H'
|
49
|
-
end
|
33
|
+
have_header('sys/resource.h')
|
50
34
|
|
51
35
|
# ncpu detection specifics
|
52
36
|
case RUBY_PLATFORM
|
@@ -64,14 +48,14 @@ dir_config('cool.io_ext')
|
|
64
48
|
create_makefile('cool.io_ext')
|
65
49
|
|
66
50
|
# win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version. See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
|
67
|
-
if RUBY_PLATFORM =~ /mingw|
|
51
|
+
if RUBY_PLATFORM =~ /mingw|mswin/
|
68
52
|
makefile_contents = File.read 'Makefile'
|
69
53
|
|
70
54
|
# "Init_cool could not be found" when loading cool.io.so.
|
71
55
|
# I'm not sure why this is needed. But this line causes "1114 A dynamic link library (DLL) initialization routine failed." So I commented out this line.
|
72
56
|
#makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
|
73
57
|
|
74
|
-
makefile_contents.gsub!
|
58
|
+
makefile_contents.gsub! /LIBS = (.*) (\S*ws2_32\S*)/i, 'LIBS = \\2 \\1'
|
75
59
|
File.open('Makefile', 'w') { |f| f.write makefile_contents }
|
76
60
|
end
|
77
61
|
|
data/ext/cool.io/loop.c
CHANGED
@@ -81,7 +81,7 @@ static void Coolio_Loop_free(struct Coolio_Loop *loop)
|
|
81
81
|
|
82
82
|
static VALUE Coolio_Loop_initialize(VALUE self)
|
83
83
|
{
|
84
|
-
Coolio_Loop_ev_loop_new(self, INT2NUM(0));
|
84
|
+
return Coolio_Loop_ev_loop_new(self, INT2NUM(0));
|
85
85
|
}
|
86
86
|
|
87
87
|
/* Wrapper for populating a Coolio_Loop struct with a new event loop */
|
data/ext/iobuffer/iobuffer.c
CHANGED
data/ext/libev/ev.c
CHANGED
@@ -1153,8 +1153,8 @@ ecb_inline ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () ==
|
|
1153
1153
|
int m = x & 0x3ff;
|
1154
1154
|
float r;
|
1155
1155
|
|
1156
|
-
if (!e ) r = ldexpf (m , -24);
|
1157
|
-
else if (e != 31) r = ldexpf (m + 0x400, e - 25);
|
1156
|
+
if (!e ) r = ldexpf ((float)m , -24);
|
1157
|
+
else if (e != 31) r = ldexpf ((float)m + 0x400, e - 25);
|
1158
1158
|
else if (m ) r = ECB_NAN;
|
1159
1159
|
else r = ECB_INFINITY;
|
1160
1160
|
|
@@ -2263,7 +2263,7 @@ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
|
|
2263
2263
|
#ifdef _WIN32
|
2264
2264
|
WSABUF buf;
|
2265
2265
|
DWORD sent;
|
2266
|
-
buf.buf = &buf;
|
2266
|
+
buf.buf = (CHAR*)&buf;
|
2267
2267
|
buf.len = 1;
|
2268
2268
|
WSASend (EV_FD_TO_WIN32_HANDLE (evpipe [1]), &buf, 1, &sent, 0, 0, 0);
|
2269
2269
|
#else
|
@@ -3343,6 +3343,7 @@ VALUE ev_backend_poll(void **args)
|
|
3343
3343
|
struct ev_loop *loop = (struct ev_loop *)args[0];
|
3344
3344
|
ev_tstamp waittime = *(ev_tstamp *)args[1];
|
3345
3345
|
backend_poll (EV_A_ waittime);
|
3346
|
+
return Qnil;
|
3346
3347
|
}
|
3347
3348
|
#endif
|
3348
3349
|
/* ######################################## */
|
data/ext/libev/ev_select.c
CHANGED
@@ -106,6 +106,7 @@ if (__i == ((fd_set *)(set))->fd_count) {\
|
|
106
106
|
} while(0)
|
107
107
|
#define EV_WIN_FD_ZERO(set) (((fd_set *)(set))->fd_count=0)
|
108
108
|
#define EV_WIN_FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set))
|
109
|
+
#define EV_WIN_FD_COUNT(set) (((fd_set *)(set))->fd_count)
|
109
110
|
/* ######################################## */
|
110
111
|
#else
|
111
112
|
#define EV_WIN_FD_CLR FD_CLR
|
@@ -192,6 +193,23 @@ select_poll (EV_P_ ev_tstamp timeout)
|
|
192
193
|
int res;
|
193
194
|
int fd_setsize;
|
194
195
|
|
196
|
+
#ifdef _WIN32
|
197
|
+
/* POSIX defines the case when the readfds, writefds, and errorfds arguments
|
198
|
+
* are all null pointers.
|
199
|
+
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html
|
200
|
+
*
|
201
|
+
* But Windows doesn't define such case; simply say don't so that
|
202
|
+
* https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx
|
203
|
+
* "Any two of the parameters, readfds, writefds, or exceptfds, can be given
|
204
|
+
* as null. At least one must be non-null, and any non-null descriptor set
|
205
|
+
* must contain at least one handle to a socket."
|
206
|
+
* At least on Windows Server 2012 R2 Datacenter with Visual Studio 2013
|
207
|
+
* (Visual C++ 12), it cause WaitForMultipleObjects stuck.
|
208
|
+
*/
|
209
|
+
if (EV_WIN_FD_COUNT(vec_ri) == 0 && EV_WIN_FD_COUNT(vec_wi) == 0)
|
210
|
+
return;
|
211
|
+
#endif
|
212
|
+
|
195
213
|
EV_RELEASE_CB;
|
196
214
|
EV_TV_SET (tv, timeout);
|
197
215
|
|
@@ -246,7 +264,7 @@ select_poll (EV_P_ ev_tstamp timeout)
|
|
246
264
|
{
|
247
265
|
if (timeout)
|
248
266
|
{
|
249
|
-
unsigned long ms = timeout * 1e3;
|
267
|
+
unsigned long ms = (unsigned long)(timeout * 1e3);
|
250
268
|
Sleep (ms ? ms : 1);
|
251
269
|
}
|
252
270
|
|
data/lib/cool.io/dns_resolver.rb
CHANGED
@@ -106,9 +106,8 @@ module Coolio
|
|
106
106
|
def send_request
|
107
107
|
nameserver = @nameservers.shift
|
108
108
|
@nameservers << nameserver # rotate them
|
109
|
-
@socket.connect @nameservers.first, DNS_PORT
|
110
109
|
begin
|
111
|
-
@socket.send request_message, 0
|
110
|
+
@socket.send request_message, 0, @nameservers.first, DNS_PORT
|
112
111
|
rescue Errno::EHOSTUNREACH # TODO figure out why it has to be wrapper here, when the other wrapper should be wrapping this one!
|
113
112
|
end
|
114
113
|
end
|
data/lib/cool.io/io.rb
CHANGED
data/lib/cool.io/version.rb
CHANGED
data/spec/async_watcher_spec.rb
CHANGED
@@ -30,7 +30,7 @@ describe Cool.io::AsyncWatcher, :env => :exclude_win do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# ensure children are ready
|
33
|
-
nr_fork.times { rd.sysread(1).
|
33
|
+
nr_fork.times { expect(rd.sysread(1)).to eq('.') }
|
34
34
|
|
35
35
|
# send our signals
|
36
36
|
nr_signal.times { aw.signal }
|
@@ -41,15 +41,15 @@ describe Cool.io::AsyncWatcher, :env => :exclude_win do
|
|
41
41
|
children.each do |pid|
|
42
42
|
Process.kill(:TERM, pid)
|
43
43
|
_, status = Process.waitpid2(pid)
|
44
|
-
status.exitstatus.
|
44
|
+
expect(status.exitstatus).to eq(0)
|
45
45
|
end
|
46
46
|
|
47
47
|
# we should've written a line for every signal we sent
|
48
48
|
lines = tmp.readlines
|
49
|
-
lines.size.
|
49
|
+
expect(lines.size).to eq(nr_signal)
|
50
50
|
|
51
51
|
# theoretically a bad kernel scheduler could give us fewer...
|
52
|
-
lines.sort.uniq.size.
|
52
|
+
expect(lines.sort.uniq.size).to eq(nr_fork)
|
53
53
|
|
54
54
|
tmp.close!
|
55
55
|
end
|
data/spec/dns_spec.rb
CHANGED
@@ -22,18 +22,22 @@ describe "DNS" do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "connects to valid domains" do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
begin
|
26
|
+
c = ConnectorThingy.connect(VALID_DOMAIN, 80).attach(@loop)
|
27
|
+
|
28
|
+
expect do
|
29
|
+
@loop.run
|
30
|
+
end.to raise_error(ItWorked)
|
31
|
+
ensure
|
32
|
+
c.close
|
33
|
+
end
|
30
34
|
end
|
31
35
|
|
32
36
|
it "fires on_resolve_failed for invalid domains" do
|
33
37
|
ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
|
34
38
|
|
35
|
-
|
39
|
+
expect do
|
36
40
|
@loop.run
|
37
|
-
end.
|
41
|
+
end.to raise_error(WontResolve)
|
38
42
|
end
|
39
43
|
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
|
4
|
+
describe IO::Buffer do
|
5
|
+
|
6
|
+
let :buffer do
|
7
|
+
IO::Buffer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "provides a subset of the methods available in Strings" do
|
11
|
+
expect(buffer << "foo").to eq "foo"
|
12
|
+
expect(buffer << "bar").to eq "bar"
|
13
|
+
expect(buffer.to_str).to eq "foobar"
|
14
|
+
expect(buffer.to_str).to eq "foobar"
|
15
|
+
expect(buffer.size).to eq 6
|
16
|
+
end
|
17
|
+
|
18
|
+
it "provides append and prepend" do
|
19
|
+
expect(buffer.append "bar").to eq "bar"
|
20
|
+
expect(buffer.prepend "foo").to eq "foo"
|
21
|
+
expect(buffer.append "baz").to eq "baz"
|
22
|
+
expect(buffer.to_str).to eq "foobarbaz"
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#read" do
|
26
|
+
it "can be used to retrieve the contents of a buffer" do
|
27
|
+
expect(buffer << "foo").to eq "foo"
|
28
|
+
expect(buffer.read 2).to eq "fo"
|
29
|
+
expect(buffer << "bar").to eq "bar"
|
30
|
+
expect(buffer.read 2).to eq "ob"
|
31
|
+
expect(buffer << "baz").to eq "baz"
|
32
|
+
expect(buffer.read 3).to eq "arb"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "provides methods for performing non-blocking I/O" do
|
37
|
+
require "tempfile"
|
38
|
+
|
39
|
+
context "#read_from" do
|
40
|
+
context "using local file", :env => :exclude_win do
|
41
|
+
let :tmp do
|
42
|
+
t = Tempfile.open "read_from"
|
43
|
+
t << "foobar"
|
44
|
+
t.rewind
|
45
|
+
t
|
46
|
+
end
|
47
|
+
|
48
|
+
it "will read as much data as possible" do
|
49
|
+
expect(buffer.read_from tmp).to eq 6
|
50
|
+
expect(buffer.to_str).to eq "foobar"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "using udp socket" do
|
55
|
+
before :each do
|
56
|
+
@receiver = UDPSocket.open
|
57
|
+
@receiver.bind nil, 0
|
58
|
+
|
59
|
+
@sender = UDPSocket.open
|
60
|
+
@sender.connect "localhost", @receiver.addr[1]
|
61
|
+
end
|
62
|
+
after :each do
|
63
|
+
@receiver.close
|
64
|
+
@sender.close
|
65
|
+
end
|
66
|
+
|
67
|
+
it "will read as much data as possible" do
|
68
|
+
select [], [@sender]
|
69
|
+
@sender.send "foo", 0
|
70
|
+
select [@receiver]
|
71
|
+
expect(buffer.read_from @receiver).to eq 3
|
72
|
+
expect(buffer.to_str).to eq "foo"
|
73
|
+
|
74
|
+
select [], [@sender]
|
75
|
+
@sender.send "barbaz", 0
|
76
|
+
select [@receiver]
|
77
|
+
expect(buffer.read_from @receiver).to eq 6
|
78
|
+
expect(buffer.to_str).to eq "foobarbaz"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "#write_to" do
|
84
|
+
context "using local file", :env => :exclude_win do
|
85
|
+
let :tmp do
|
86
|
+
Tempfile.open "write_to"
|
87
|
+
end
|
88
|
+
it "writes the contents of the buffer" do
|
89
|
+
buffer << "foo"
|
90
|
+
expect(buffer.write_to tmp).to eq 3
|
91
|
+
tmp.rewind
|
92
|
+
expect(tmp.read 3).to eq "foo"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "using udp socket" do
|
97
|
+
before :each do
|
98
|
+
@receiver = UDPSocket.open
|
99
|
+
@receiver.bind nil, 0
|
100
|
+
|
101
|
+
@sender = UDPSocket.open
|
102
|
+
@sender.connect "localhost", @receiver.addr[1]
|
103
|
+
end
|
104
|
+
after :each do
|
105
|
+
@receiver.close
|
106
|
+
@sender.close
|
107
|
+
end
|
108
|
+
|
109
|
+
it "will read as much data as possible" do
|
110
|
+
buffer << "foo"
|
111
|
+
select [], [@sender]
|
112
|
+
expect(buffer.write_to @sender).to eq 3
|
113
|
+
select [@receiver]
|
114
|
+
expect(@receiver.recvfrom_nonblock(3)[0]).to eq "foo"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "#clear" do
|
121
|
+
it "clear all data" do
|
122
|
+
buffer << "foo"
|
123
|
+
expect(buffer.size).to eq 3
|
124
|
+
expect(buffer.empty?).to eq false
|
125
|
+
buffer.clear
|
126
|
+
expect(buffer.size).to eq 0
|
127
|
+
expect(buffer.empty?).to eq true
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context "#read_frame" do
|
132
|
+
it "Read up to and including the given frame marker" do
|
133
|
+
buffer << "foo\nbarbaz"
|
134
|
+
data = ""
|
135
|
+
expect(buffer.read_frame data, "\n".ord).to eq true
|
136
|
+
expect(buffer.empty?).to eq false
|
137
|
+
expect(data).to eq "foo\n"
|
138
|
+
expect(buffer.to_str).to eq "barbaz"
|
139
|
+
|
140
|
+
expect(buffer.read_frame data, "\n".ord).to eq false
|
141
|
+
expect(buffer.empty?).to eq true
|
142
|
+
expect(data).to eq "foo\nbarbaz"
|
143
|
+
expect(buffer.to_str).to eq ""
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/stat_watcher_spec.rb
CHANGED
@@ -62,16 +62,16 @@ describe Cool.io::StatWatcher do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
it "fire on_change when the file it is watching is modified" do
|
65
|
-
watcher.accessed.
|
65
|
+
expect(watcher.accessed).to eq(true)
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should pass previous and current file stat info given a stat watcher" do
|
69
|
-
watcher.previous.ino.
|
69
|
+
expect(watcher.previous.ino).to eq(watcher.current.ino)
|
70
70
|
end
|
71
71
|
|
72
72
|
it "should raise when the handler does not take 2 parameters" do
|
73
73
|
class MyStatWatcher < Cool.io::StatWatcher; def on_change; end; end
|
74
|
-
|
74
|
+
expect { watcher.accessed }.to raise_error(ArgumentError)
|
75
75
|
end
|
76
76
|
|
77
77
|
end
|
data/spec/tcp_server_spec.rb
CHANGED
@@ -109,11 +109,11 @@ end
|
|
109
109
|
describe Coolio::TCPServer do
|
110
110
|
|
111
111
|
it '#run' do
|
112
|
-
test_run("hello").
|
112
|
+
expect(test_run("hello")).to eq("hello")
|
113
113
|
end
|
114
114
|
|
115
115
|
it '#run_once' do
|
116
|
-
test_run_once("hello").
|
116
|
+
expect(test_run_once("hello")).to eq("hello")
|
117
117
|
end
|
118
118
|
|
119
119
|
it '#run_once(timeout)' do
|
@@ -125,8 +125,101 @@ describe Coolio::TCPServer do
|
|
125
125
|
end
|
126
126
|
|
127
127
|
it '#run(timeout)' do
|
128
|
-
test_run_timeout("hello").
|
128
|
+
expect(test_run_timeout("hello")).to eq("hello")
|
129
129
|
end
|
130
130
|
|
131
|
+
describe "functionaltest" do
|
132
|
+
let :loop do
|
133
|
+
Coolio::Loop.new
|
134
|
+
end
|
135
|
+
|
136
|
+
let :port do
|
137
|
+
unused_port
|
138
|
+
end
|
139
|
+
|
140
|
+
context "#on_connect" do
|
141
|
+
class ServerOnConnect < Coolio::Socket
|
142
|
+
def initialize(io, cb)
|
143
|
+
super(io)
|
144
|
+
@cb = cb
|
145
|
+
end
|
146
|
+
def on_connect
|
147
|
+
@cb.call
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "connected socket called on_connect" do
|
152
|
+
begin
|
153
|
+
connected = false
|
154
|
+
server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { connected = true })
|
155
|
+
loop.attach server
|
156
|
+
s = TCPSocket.open("localhost", port)
|
157
|
+
loop.run_once
|
158
|
+
s.close
|
159
|
+
expect(connected).to eq true
|
160
|
+
ensure
|
161
|
+
server.detach
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "#on_close" do
|
167
|
+
class ServerOnClose < Coolio::Socket
|
168
|
+
def initialize(io, cb)
|
169
|
+
super(io)
|
170
|
+
@cb = cb
|
171
|
+
end
|
172
|
+
def on_close
|
173
|
+
@cb.call
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "closed socket called on_close" do
|
178
|
+
begin
|
179
|
+
closed = false
|
180
|
+
server = Cool.io::TCPServer.new("localhost", port, ServerOnConnect, proc { closed = true })
|
181
|
+
loop.attach server
|
182
|
+
s = TCPSocket.open("localhost", port)
|
183
|
+
loop.run_once
|
184
|
+
s.close
|
185
|
+
loop.run_once
|
186
|
+
expect(closed).to eq true
|
187
|
+
ensure
|
188
|
+
server.detach
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "#on_read" do
|
194
|
+
class Echo < Coolio::Socket
|
195
|
+
def initialize(io, cb)
|
196
|
+
super(io)
|
197
|
+
@cb = cb
|
198
|
+
end
|
199
|
+
def on_read(data)
|
200
|
+
@cb.call data
|
201
|
+
size = write(data + "fff")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
it "server socket received data" do
|
206
|
+
begin
|
207
|
+
data = "aaa"
|
208
|
+
server = Cool.io::TCPServer.new("localhost", port, Echo, proc { |d| data = d })
|
209
|
+
loop.attach server
|
210
|
+
thread = Thread.new { loop.run }
|
211
|
+
s = TCPSocket.open("localhost", port)
|
212
|
+
s.write "zzz"
|
213
|
+
sleep 0.1
|
214
|
+
expect(data).to eq "zzz"
|
215
|
+
expect(s.read 6).to eq "zzzfff"
|
216
|
+
ensure
|
217
|
+
s.close
|
218
|
+
loop.stop
|
219
|
+
server.detach
|
220
|
+
thread.join
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
131
225
|
end
|
132
|
-
|
data/spec/tcp_socket_spec.rb
CHANGED
@@ -1,27 +1,185 @@
|
|
1
1
|
require File.expand_path('../spec_helper', __FILE__)
|
2
2
|
|
3
3
|
describe Coolio::TCPSocket do
|
4
|
-
|
4
|
+
let :loop do
|
5
|
+
Coolio::Loop.new
|
6
|
+
end
|
7
|
+
|
5
8
|
before :each do
|
6
|
-
@
|
7
|
-
@host = @
|
8
|
-
@port = @
|
9
|
+
@echo = TCPServer.new("127.0.0.1", 0)
|
10
|
+
@host = @echo.addr[3]
|
11
|
+
@port = @echo.addr[1]
|
12
|
+
@running = true
|
13
|
+
@echo_thread = Thread.new do
|
14
|
+
socks = [@echo]
|
15
|
+
begin
|
16
|
+
serv socks
|
17
|
+
ensure
|
18
|
+
socks.each do |s|
|
19
|
+
s.close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
Thread.pass
|
23
|
+
end
|
9
24
|
end
|
10
|
-
|
25
|
+
|
26
|
+
def serv(socks)
|
27
|
+
while @running
|
28
|
+
selected = select(socks, [], [], 0.1)
|
29
|
+
next if selected.nil?
|
30
|
+
selected[0].each do |s|
|
31
|
+
if s == @echo
|
32
|
+
socks.push s.accept
|
33
|
+
next
|
34
|
+
end
|
35
|
+
begin
|
36
|
+
unless s.eof?
|
37
|
+
s.write(s.read_nonblock 1)
|
38
|
+
end
|
39
|
+
rescue SystemCallError, EOFError, IOError, SocketError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown
|
46
|
+
if @running
|
47
|
+
@running = false
|
48
|
+
@echo_thread.join
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
11
52
|
after :each do
|
12
|
-
|
53
|
+
shutdown
|
13
54
|
end
|
14
55
|
|
15
|
-
|
16
|
-
|
17
|
-
it 'detaches all watchers on #close before loop#run' do
|
18
|
-
reactor = Coolio::Loop.new
|
56
|
+
context "#close" do
|
57
|
+
it "detaches all watchers on #close before loop#run" do
|
19
58
|
client = Coolio::TCPSocket.connect(@host, @port)
|
20
|
-
|
59
|
+
loop.attach client
|
21
60
|
client.close
|
22
|
-
|
61
|
+
expect(loop.watchers.size).to eq 0
|
23
62
|
end
|
24
63
|
end
|
25
64
|
|
26
|
-
|
65
|
+
context "#on_connect" do
|
66
|
+
class OnConnect < Cool.io::TCPSocket
|
67
|
+
attr :connected
|
68
|
+
def on_connect
|
69
|
+
@connected = true
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "connected client called on_connect" do
|
74
|
+
begin
|
75
|
+
c = OnConnect.connect(@host, @port)
|
76
|
+
loop.attach c
|
77
|
+
loop.run_once
|
78
|
+
expect(c.connected).to eq true
|
79
|
+
ensure
|
80
|
+
c.close
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
27
84
|
|
85
|
+
context "#on_connect_failed" do
|
86
|
+
class OnConnectFailed < Cool.io::TCPSocket
|
87
|
+
attr :connect_failed
|
88
|
+
def on_connect_failed
|
89
|
+
@connect_failed = true
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "try to connect dead host" do
|
94
|
+
serv = TCPServer.new(0)
|
95
|
+
dead_host = serv.addr[3]
|
96
|
+
dead_port = serv.addr[1]
|
97
|
+
serv.close
|
98
|
+
|
99
|
+
c = OnConnectFailed.connect(dead_host, dead_port)
|
100
|
+
loop.attach c
|
101
|
+
loop.run_once # on_connect_failed
|
102
|
+
expect(c.connect_failed).to eq true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "#on_close" do
|
107
|
+
class Closed < StandardError; end
|
108
|
+
class OnClose < Cool.io::TCPSocket
|
109
|
+
def on_close
|
110
|
+
raise Closed
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
let :client do
|
115
|
+
OnClose.connect(@host, @port)
|
116
|
+
end
|
117
|
+
|
118
|
+
before :each do
|
119
|
+
loop.attach client
|
120
|
+
loop.run_once # on_connect
|
121
|
+
client.write "0"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "disconnect from client" do
|
125
|
+
expect { client.close }.to raise_error(Closed)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "disconnect from server" do
|
129
|
+
shutdown
|
130
|
+
expect { loop.run }.to raise_error(Closed)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "#on_read" do
|
135
|
+
class Finished < StandardError; end
|
136
|
+
class OnRead < Cool.io::TCPSocket
|
137
|
+
attr :read_data, :times
|
138
|
+
def on_connect
|
139
|
+
@read_data = ""
|
140
|
+
@times = 0
|
141
|
+
end
|
142
|
+
def on_read(data)
|
143
|
+
@read_data += data
|
144
|
+
@times += 1
|
145
|
+
if @times < 5
|
146
|
+
write "#{@times}"
|
147
|
+
else
|
148
|
+
close
|
149
|
+
raise Finished
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it "receive 5 times" do
|
155
|
+
c = OnRead.connect(@host, @port)
|
156
|
+
loop.attach c
|
157
|
+
loop.run_once # on_connect
|
158
|
+
c.write "0"
|
159
|
+
expect { loop.run }.to raise_error(Finished)
|
160
|
+
|
161
|
+
expect(c.times).to eq 5
|
162
|
+
expect(c.read_data).to eq "01234"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "#on_write_complete" do
|
167
|
+
class WriteComplete < StandardError; end
|
168
|
+
class OnWriteComplete < Cool.io::TCPSocket
|
169
|
+
attr :called
|
170
|
+
def on_write_complete
|
171
|
+
@called = true
|
172
|
+
close
|
173
|
+
raise WriteComplete
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it "on_write_complete is called" do
|
178
|
+
c = OnWriteComplete.connect(@host, @port)
|
179
|
+
loop.attach c
|
180
|
+
loop.run_once # on_connect
|
181
|
+
c.write "aaa"
|
182
|
+
expect { loop.run }.to raise_error(WriteComplete)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
data/spec/timer_watcher_spec.rb
CHANGED
@@ -4,15 +4,19 @@ describe Cool.io::TimerWatcher do
|
|
4
4
|
|
5
5
|
interval = 0.010
|
6
6
|
|
7
|
+
let :loop do
|
8
|
+
Cool.io::Loop.new
|
9
|
+
end
|
10
|
+
|
7
11
|
it "can have the on_timer callback defined after creation" do
|
8
12
|
@watcher = Cool.io::TimerWatcher.new(interval, true)
|
9
13
|
nr = '0'
|
10
|
-
@watcher.on_timer { nr.succ! }.
|
11
|
-
@watcher.attach(
|
12
|
-
nr.
|
14
|
+
expect(@watcher.on_timer { nr.succ! }).to be_nil
|
15
|
+
expect(@watcher.attach(loop)).to eq(@watcher)
|
16
|
+
expect(nr).to eq('0')
|
13
17
|
sleep interval
|
14
|
-
|
15
|
-
nr.
|
18
|
+
loop.run_once
|
19
|
+
expect(nr).to eq('1')
|
16
20
|
end
|
17
21
|
|
18
22
|
it "can be subclassed" do
|
@@ -24,29 +28,29 @@ describe Cool.io::TimerWatcher do
|
|
24
28
|
end
|
25
29
|
end
|
26
30
|
@watcher = MyTimerWatcher.new(interval, true)
|
27
|
-
@watcher.attach(
|
28
|
-
MyTimerWatcher::TMP.
|
31
|
+
expect(@watcher.attach(loop)).to eq(@watcher)
|
32
|
+
expect(MyTimerWatcher::TMP).to eq('0')
|
29
33
|
sleep interval
|
30
|
-
|
31
|
-
MyTimerWatcher::TMP.
|
34
|
+
loop.run_once
|
35
|
+
expect(MyTimerWatcher::TMP).to eq('1')
|
32
36
|
end
|
33
37
|
|
34
38
|
it "can have the on_timer callback redefined between runs" do
|
35
39
|
@watcher = Cool.io::TimerWatcher.new(interval, true)
|
36
40
|
nr = '0'
|
37
|
-
@watcher.on_timer { nr.succ! }.
|
38
|
-
@watcher.attach(
|
39
|
-
nr.
|
41
|
+
expect(@watcher.on_timer { nr.succ! }).to be_nil
|
42
|
+
expect(@watcher.attach(loop)).to eq(@watcher)
|
43
|
+
expect(nr).to eq('0')
|
40
44
|
sleep interval
|
41
|
-
|
42
|
-
nr.
|
45
|
+
loop.run_once
|
46
|
+
expect(nr).to eq('1')
|
43
47
|
@watcher.detach
|
44
|
-
@watcher.on_timer { nr = :foo }.
|
45
|
-
@watcher.attach(
|
46
|
-
nr.
|
48
|
+
expect(@watcher.on_timer { nr = :foo }).to be_nil
|
49
|
+
expect(@watcher.attach(loop)).to eq(@watcher)
|
50
|
+
expect(nr).to eq('1')
|
47
51
|
sleep interval
|
48
|
-
|
49
|
-
nr.
|
52
|
+
loop.run_once
|
53
|
+
expect(nr).to eq(:foo)
|
50
54
|
end
|
51
55
|
|
52
56
|
after :each do
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Coolio::UDPSocket" do
|
4
|
+
let :loop do
|
5
|
+
Coolio::Loop.new
|
6
|
+
end
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@echo = UDPSocket.open
|
10
|
+
@echo.bind nil, 0
|
11
|
+
@port = @echo.addr[1]
|
12
|
+
|
13
|
+
@running = true
|
14
|
+
@echo_thread = Thread.new do
|
15
|
+
while @running
|
16
|
+
begin
|
17
|
+
msg, sender = @echo.recvfrom_nonblock(3)
|
18
|
+
@echo.send(msg + "bbb", 0, sender[3], sender[1])
|
19
|
+
rescue IO::WaitReadable
|
20
|
+
end
|
21
|
+
Thread.pass
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
after :each do
|
27
|
+
@running = false
|
28
|
+
@echo_thread.join
|
29
|
+
@echo.close
|
30
|
+
end
|
31
|
+
|
32
|
+
class Readable < Cool.io::IOWatcher
|
33
|
+
attr :socket, :received
|
34
|
+
def initialize
|
35
|
+
@socket = UDPSocket.new
|
36
|
+
super(@socket)
|
37
|
+
end
|
38
|
+
|
39
|
+
def on_readable
|
40
|
+
@received = @socket.recvfrom_nonblock(6).first
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "receive message #on_readable 5 times" do
|
45
|
+
5.times do
|
46
|
+
begin
|
47
|
+
r = Readable.new
|
48
|
+
r.socket.send "aaa", 0, "localhost", @port
|
49
|
+
|
50
|
+
loop.attach r
|
51
|
+
loop.run_once
|
52
|
+
expect(r.received).to eq "aaabbb"
|
53
|
+
ensure
|
54
|
+
r.detach
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/spec/unix_listener_spec.rb
CHANGED
@@ -5,21 +5,21 @@ describe Cool.io::UNIXListener, :env => :exclude_win do
|
|
5
5
|
|
6
6
|
before :each do
|
7
7
|
@tmp = Tempfile.new('coolio_unix_listener_spec')
|
8
|
-
File.unlink(@tmp.path).
|
9
|
-
File.exist?(@tmp.path).
|
8
|
+
expect(File.unlink(@tmp.path)).to eq(1)
|
9
|
+
expect(File.exist?(@tmp.path)).to eq(false)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "creates a new UNIXListener" do
|
13
13
|
listener = Cool.io::UNIXListener.new(@tmp.path)
|
14
|
-
File.socket?(@tmp.path).
|
14
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
15
15
|
end
|
16
16
|
|
17
17
|
it "builds off an existing UNIXServer" do
|
18
18
|
unix_server = UNIXServer.new(@tmp.path)
|
19
|
-
File.socket?(@tmp.path).
|
19
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
20
20
|
listener = Cool.io::UNIXListener.new(unix_server)
|
21
|
-
File.socket?(@tmp.path).
|
22
|
-
listener.fileno.
|
21
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
22
|
+
expect(listener.fileno).to eq(unix_server.fileno)
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
data/spec/unix_server_spec.rb
CHANGED
@@ -5,23 +5,23 @@ describe Cool.io::UNIXServer, :env => :exclude_win do
|
|
5
5
|
|
6
6
|
before :each do
|
7
7
|
@tmp = Tempfile.new('coolio_unix_server_spec')
|
8
|
-
File.unlink(@tmp.path).
|
9
|
-
File.exist?(@tmp.path).
|
8
|
+
expect(File.unlink(@tmp.path)).to eq(1)
|
9
|
+
expect(File.exist?(@tmp.path)).to eq(false)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "creates a new Cool.io::UNIXServer" do
|
13
13
|
listener = Cool.io::UNIXListener.new(@tmp.path)
|
14
14
|
listener.listen(24)
|
15
|
-
File.socket?(@tmp.path).
|
15
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "builds off an existing ::UNIXServer" do
|
19
19
|
unix_server = ::UNIXServer.new(@tmp.path)
|
20
|
-
File.socket?(@tmp.path).
|
20
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
21
21
|
listener = Cool.io::UNIXServer.new(unix_server, Coolio::UNIXSocket)
|
22
22
|
listener.listen(24)
|
23
|
-
File.socket?(@tmp.path).
|
24
|
-
listener.fileno.
|
23
|
+
expect(File.socket?(@tmp.path)).to eq(true)
|
24
|
+
expect(listener.fileno).to eq(unix_server.fileno)
|
25
25
|
end
|
26
26
|
|
27
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cool.io
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-05-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -129,11 +129,13 @@ files:
|
|
129
129
|
- lib/coolio.rb
|
130
130
|
- spec/async_watcher_spec.rb
|
131
131
|
- spec/dns_spec.rb
|
132
|
+
- spec/iobuffer_spec.rb
|
132
133
|
- spec/spec_helper.rb
|
133
134
|
- spec/stat_watcher_spec.rb
|
134
135
|
- spec/tcp_server_spec.rb
|
135
136
|
- spec/tcp_socket_spec.rb
|
136
137
|
- spec/timer_watcher_spec.rb
|
138
|
+
- spec/udp_socket_spec.rb
|
137
139
|
- spec/unix_listener_spec.rb
|
138
140
|
- spec/unix_server_spec.rb
|
139
141
|
homepage: http://coolio.github.com
|
@@ -155,17 +157,19 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
157
|
version: '0'
|
156
158
|
requirements: []
|
157
159
|
rubyforge_project:
|
158
|
-
rubygems_version: 2.
|
160
|
+
rubygems_version: 2.2.2
|
159
161
|
signing_key:
|
160
162
|
specification_version: 4
|
161
163
|
summary: A cool framework for doing high performance I/O in Ruby
|
162
164
|
test_files:
|
163
165
|
- spec/async_watcher_spec.rb
|
164
166
|
- spec/dns_spec.rb
|
167
|
+
- spec/iobuffer_spec.rb
|
165
168
|
- spec/spec_helper.rb
|
166
169
|
- spec/stat_watcher_spec.rb
|
167
170
|
- spec/tcp_server_spec.rb
|
168
171
|
- spec/tcp_socket_spec.rb
|
169
172
|
- spec/timer_watcher_spec.rb
|
173
|
+
- spec/udp_socket_spec.rb
|
170
174
|
- spec/unix_listener_spec.rb
|
171
175
|
- spec/unix_server_spec.rb
|