cool.io 1.4.1-x64-mingw32

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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +29 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGES.md +229 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +20 -0
  8. data/README.md +166 -0
  9. data/Rakefile +79 -0
  10. data/cool.io.gemspec +29 -0
  11. data/examples/callbacked_echo_server.rb +24 -0
  12. data/examples/dslified_echo_client.rb +34 -0
  13. data/examples/dslified_echo_server.rb +24 -0
  14. data/examples/echo_client.rb +38 -0
  15. data/examples/echo_server.rb +27 -0
  16. data/examples/google.rb +9 -0
  17. data/ext/cool.io/.gitignore +5 -0
  18. data/ext/cool.io/cool.io.h +59 -0
  19. data/ext/cool.io/cool.io_ext.c +25 -0
  20. data/ext/cool.io/ev_wrap.h +10 -0
  21. data/ext/cool.io/extconf.rb +61 -0
  22. data/ext/cool.io/iowatcher.c +189 -0
  23. data/ext/cool.io/libev.c +8 -0
  24. data/ext/cool.io/loop.c +261 -0
  25. data/ext/cool.io/stat_watcher.c +269 -0
  26. data/ext/cool.io/timer_watcher.c +219 -0
  27. data/ext/cool.io/utils.c +122 -0
  28. data/ext/cool.io/watcher.c +264 -0
  29. data/ext/cool.io/watcher.h +71 -0
  30. data/ext/iobuffer/extconf.rb +9 -0
  31. data/ext/iobuffer/iobuffer.c +767 -0
  32. data/ext/libev/Changes +507 -0
  33. data/ext/libev/LICENSE +37 -0
  34. data/ext/libev/README +58 -0
  35. data/ext/libev/README.embed +3 -0
  36. data/ext/libev/ev.c +5054 -0
  37. data/ext/libev/ev.h +853 -0
  38. data/ext/libev/ev_epoll.c +282 -0
  39. data/ext/libev/ev_kqueue.c +214 -0
  40. data/ext/libev/ev_poll.c +148 -0
  41. data/ext/libev/ev_port.c +185 -0
  42. data/ext/libev/ev_select.c +362 -0
  43. data/ext/libev/ev_vars.h +204 -0
  44. data/ext/libev/ev_win32.c +163 -0
  45. data/ext/libev/ev_wrap.h +200 -0
  46. data/ext/libev/ruby_gil.patch +97 -0
  47. data/ext/libev/test_libev_win32.c +123 -0
  48. data/ext/libev/win_select.patch +115 -0
  49. data/lib/.gitignore +2 -0
  50. data/lib/cool.io.rb +34 -0
  51. data/lib/cool.io/async_watcher.rb +43 -0
  52. data/lib/cool.io/custom_require.rb +9 -0
  53. data/lib/cool.io/dns_resolver.rb +219 -0
  54. data/lib/cool.io/dsl.rb +139 -0
  55. data/lib/cool.io/io.rb +194 -0
  56. data/lib/cool.io/iowatcher.rb +17 -0
  57. data/lib/cool.io/listener.rb +99 -0
  58. data/lib/cool.io/loop.rb +122 -0
  59. data/lib/cool.io/meta.rb +49 -0
  60. data/lib/cool.io/server.rb +75 -0
  61. data/lib/cool.io/socket.rb +230 -0
  62. data/lib/cool.io/timer_watcher.rb +17 -0
  63. data/lib/cool.io/version.rb +7 -0
  64. data/lib/coolio.rb +2 -0
  65. data/spec/async_watcher_spec.rb +57 -0
  66. data/spec/dns_spec.rb +43 -0
  67. data/spec/iobuffer_spec.rb +147 -0
  68. data/spec/spec_helper.rb +19 -0
  69. data/spec/stat_watcher_spec.rb +77 -0
  70. data/spec/tcp_server_spec.rb +225 -0
  71. data/spec/tcp_socket_spec.rb +185 -0
  72. data/spec/timer_watcher_spec.rb +59 -0
  73. data/spec/udp_socket_spec.rb +58 -0
  74. data/spec/unix_listener_spec.rb +25 -0
  75. data/spec/unix_server_spec.rb +27 -0
  76. metadata +182 -0
@@ -0,0 +1,17 @@
1
+ #--
2
+ # Copyright (C)2007 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ module Coolio
8
+ class TimerWatcher
9
+ # The actual implementation of this class resides in the C extension
10
+ # Here we metaprogram proper event_callbacks for the callback methods
11
+ # These can take a block and store it to be called when the event
12
+ # is actually fired.
13
+
14
+ extend Meta
15
+ event_callback :on_timer
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Coolio
2
+ VERSION = "1.4.1"
3
+
4
+ def self.version
5
+ VERSION
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ # For those people who don't like the cool.io styling...
2
+ require 'cool.io'
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'tempfile'
3
+ require 'fcntl'
4
+
5
+ describe Cool.io::AsyncWatcher, :env => :exclude_win do
6
+
7
+ it "does not signal on spurious wakeups" do
8
+ aw = Cool.io::AsyncWatcher.new
9
+ tmp = Tempfile.new('coolio_async_watcher_test')
10
+ nr_fork = 2 # must be at least two for spurious wakeups
11
+
12
+ # We have aetter chance of failing if this overflows the pipe buffer
13
+ # which POSIX requires >= 512 bytes, Linux 2.6 uses 4096 bytes
14
+ nr_signal = 4096 * 4
15
+
16
+ append = File.open(tmp.path, "ab")
17
+ append.sync = true
18
+ rd, wr = ::IO.pipe
19
+
20
+ aw.on_signal { append.syswrite("#$$\n") }
21
+ children = nr_fork.times.map do
22
+ fork do
23
+ trap(:TERM) { exit!(0) }
24
+ rloop = Cool.io::Loop.default
25
+ aw.attach(rloop)
26
+ wr.write '.' # signal to master that we're ready
27
+ rloop.run
28
+ exit!(1) # should not get here
29
+ end
30
+ end
31
+
32
+ # ensure children are ready
33
+ nr_fork.times { expect(rd.sysread(1)).to eq('.') }
34
+
35
+ # send our signals
36
+ nr_signal.times { aw.signal }
37
+
38
+ # wait for the pipe buffer to be consumed by the children
39
+ sleep 1 while tmp.stat.ctime >= (Time.now - 4)
40
+
41
+ children.each do |pid|
42
+ Process.kill(:TERM, pid)
43
+ _, status = Process.waitpid2(pid)
44
+ expect(status.exitstatus).to eq(0)
45
+ end
46
+
47
+ # we should've written a line for every signal we sent
48
+ lines = tmp.readlines
49
+ expect(lines.size).to eq(nr_signal)
50
+
51
+ # theoretically a bad kernel scheduler could give us fewer...
52
+ expect(lines.sort.uniq.size).to eq(nr_fork)
53
+
54
+ tmp.close!
55
+ end
56
+
57
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ VALID_DOMAIN = "google.com"
4
+ INVALID_DOMAIN = "gibidigibigididibitidibigitibidigitidididi.com"
5
+
6
+ class ItWorked < StandardError; end
7
+ class WontResolve < StandardError; end
8
+
9
+ class ConnectorThingy < Cool.io::TCPSocket
10
+ def on_connect
11
+ raise ItWorked
12
+ end
13
+
14
+ def on_resolve_failed
15
+ raise WontResolve
16
+ end
17
+ end
18
+
19
+ describe "DNS" do
20
+ before :each do
21
+ @loop = Cool.io::Loop.new
22
+ end
23
+
24
+ it "connects to valid domains" do
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
34
+ end
35
+
36
+ it "fires on_resolve_failed for invalid domains" do
37
+ ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
38
+
39
+ expect do
40
+ @loop.run
41
+ end.to raise_error(WontResolve)
42
+ end
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
@@ -0,0 +1,19 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'rspec'
5
+ require 'cool.io'
6
+
7
+ def unused_port
8
+ s = TCPServer.open(0)
9
+ port = s.addr[1]
10
+ s.close
11
+ port
12
+ end
13
+
14
+ RSpec.configure do |c|
15
+ if RUBY_PLATFORM =~ /mingw|mswin/
16
+ $stderr.puts "Skip some specs on Windows"
17
+ c.filter_run_excluding :env => :exclude_win
18
+ end
19
+ end
@@ -0,0 +1,77 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ TEMP_FILE_PATH = "./test.txt"
4
+
5
+ INTERVAL = 0.010
6
+
7
+ class MyStatWatcher < Cool.io::StatWatcher
8
+ attr_accessor :accessed, :previous, :current
9
+
10
+ def initialize(path)
11
+ super path, INTERVAL
12
+ end
13
+
14
+ def on_change(previous, current)
15
+ self.accessed = true
16
+ self.previous = previous
17
+ self.current = current
18
+ end
19
+ end
20
+
21
+ def run_with_file_change(path)
22
+ reactor = Cool.io::Loop.new
23
+
24
+ sw = MyStatWatcher.new(path)
25
+ sw.attach(reactor)
26
+
27
+ tw = Cool.io::TimerWatcher.new(INTERVAL, true)
28
+ tw.on_timer do
29
+ reactor.stop if sw.accessed
30
+ write_file(path)
31
+ end
32
+ tw.attach(reactor)
33
+
34
+ reactor.run
35
+
36
+ tw.detach
37
+ sw.detach
38
+
39
+ sw
40
+ end
41
+
42
+ def write_file(path)
43
+ File.open(path, "w+") { |f| f.write(rand.to_s) }
44
+ end
45
+
46
+ def delete_file(path)
47
+ File.delete(TEMP_FILE_PATH)
48
+ end
49
+
50
+ describe Cool.io::StatWatcher do
51
+
52
+ let :watcher do
53
+ run_with_file_change(TEMP_FILE_PATH)
54
+ end
55
+
56
+ before :each do
57
+ write_file(TEMP_FILE_PATH)
58
+ end
59
+
60
+ after :each do
61
+ delete_file(TEMP_FILE_PATH)
62
+ end
63
+
64
+ it "fire on_change when the file it is watching is modified" do
65
+ expect(watcher.accessed).to eq(true)
66
+ end
67
+
68
+ it "should pass previous and current file stat info given a stat watcher" do
69
+ expect(watcher.previous.ino).to eq(watcher.current.ino)
70
+ end
71
+
72
+ it "should raise when the handler does not take 2 parameters" do
73
+ class MyStatWatcher < Cool.io::StatWatcher; def on_change; end; end
74
+ expect { watcher.accessed }.to raise_error(ArgumentError)
75
+ end
76
+
77
+ end
@@ -0,0 +1,225 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ TIMEOUT = 0.010
4
+ HOST = '127.0.0.1'
5
+ PORT = unused_port
6
+
7
+ def send_data(data)
8
+ io = TCPSocket.new('127.0.0.1', PORT)
9
+ begin
10
+ io.write data
11
+ ensure
12
+ io.close
13
+ end
14
+ end
15
+
16
+ class MyConnection < Coolio::Socket
17
+ attr_accessor :data, :connected, :closed
18
+
19
+ def initialize(io, on_message)
20
+ super(io)
21
+ @on_message = on_message
22
+ end
23
+
24
+ def on_connect
25
+ @connected = true
26
+ end
27
+
28
+ def on_close
29
+ @closed = true
30
+ end
31
+
32
+ def on_read(data)
33
+ @on_message.call(data)
34
+ end
35
+ end
36
+
37
+ @data = ""
38
+ def on_message(data)
39
+ @data = data
40
+ end
41
+
42
+ def test_run(data = nil)
43
+ reactor = Coolio::Loop.new
44
+ server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
45
+ reactor.attach(server)
46
+ thread = Thread.new { reactor.run }
47
+ send_data(data) if data
48
+ sleep TIMEOUT
49
+ reactor.stop
50
+ server.detach
51
+ send_data('') # to leave from blocking loop
52
+ thread.join
53
+ @data
54
+ ensure
55
+ server.close
56
+ end
57
+
58
+ def test_run_once(data = nil)
59
+ reactor = Coolio::Loop.new
60
+ server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
61
+ reactor.attach(server)
62
+ thread = Thread.new do
63
+ reactor.run_once # on_connect
64
+ reactor.run_once # on_read
65
+ end
66
+ send_data(data) if data
67
+ thread.join
68
+ server.detach
69
+ @data
70
+ ensure
71
+ server.close
72
+ end
73
+
74
+ def test_run_once_timeout(timeout = TIMEOUT)
75
+ reactor = Coolio::Loop.new
76
+ server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
77
+ reactor.attach(server)
78
+ running = true
79
+ thread = Thread.new { reactor.run_once(timeout) }
80
+ sleep timeout
81
+ server.detach
82
+ thread.join
83
+ @data
84
+ ensure
85
+ server.close
86
+ end
87
+
88
+ def test_run_timeout(data = nil, timeout = TIMEOUT)
89
+ reactor = Coolio::Loop.new
90
+ server = Cool.io::TCPServer.new(HOST, PORT, MyConnection, method(:on_message))
91
+ reactor.attach(server)
92
+ running = true
93
+ thread = Thread.new do
94
+ while running and reactor.has_active_watchers?
95
+ reactor.run_once(timeout)
96
+ end
97
+ end
98
+ send_data(data) if data
99
+ sleep timeout
100
+ server.detach
101
+ running = false # another send is not required
102
+ thread.join
103
+ @data
104
+ ensure
105
+ server.close
106
+ end
107
+
108
+ # This test should work on Windows
109
+ describe Coolio::TCPServer do
110
+
111
+ it '#run' do
112
+ expect(test_run("hello")).to eq("hello")
113
+ end
114
+
115
+ it '#run_once' do
116
+ expect(test_run_once("hello")).to eq("hello")
117
+ end
118
+
119
+ it '#run_once(timeout)' do
120
+ test_run_once_timeout # should not block
121
+ end
122
+
123
+ it '#run_once(-timeout)' do
124
+ expect { test_run_once_timeout(-0.1) }.to raise_error(ArgumentError)
125
+ end
126
+
127
+ it '#run(timeout)' do
128
+ expect(test_run_timeout("hello")).to eq("hello")
129
+ end
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
225
+ end