cool.io 0.9.0 → 1.0.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/CHANGES +6 -0
- data/README.markdown +172 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/cool.io.gemspec +138 -0
- data/examples/dslified_echo_client.rb +34 -0
- data/examples/dslified_echo_server.rb +24 -0
- data/examples/echo_client.rb +2 -2
- data/examples/echo_server.rb +3 -3
- data/ext/cool.io/loop.c +0 -2
- data/ext/http11_client/LICENSE +31 -0
- data/lib/cool.io.rb +2 -0
- data/lib/cool.io/dsl.rb +135 -0
- data/lib/cool.io/socket.rb +6 -8
- data/spec/dns_spec.rb +39 -0
- metadata +27 -20
- data/.gitignore +0 -25
- data/ext/libev/update_ev_wrap +0 -19
data/CHANGES
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
1.0.0:
|
2
|
+
|
3
|
+
* Fancy new DSL
|
4
|
+
|
1
5
|
0.9.0:
|
2
6
|
|
3
7
|
* Rename the project to cool.io
|
@@ -12,6 +16,8 @@
|
|
12
16
|
|
13
17
|
* Update to libev 4.01
|
14
18
|
|
19
|
+
* Initial Rubinius support
|
20
|
+
|
15
21
|
0.3.2:
|
16
22
|
|
17
23
|
* Perform a blocking system call if we're the only thread running (1.8 only)
|
data/README.markdown
CHANGED
@@ -1,4 +1,175 @@
|
|
1
1
|
Cool.io
|
2
2
|
=======
|
3
3
|
|
4
|
-
|
4
|
+
[http://coolio.github.com](http://coolio.github.com)
|
5
|
+
|
6
|
+
Cool.io is an event library for Ruby, built on the libev event library which
|
7
|
+
provides a cross-platform interface to high performance system calls . This
|
8
|
+
includes the epoll system call for Linux, the kqueue system call for BSDs and
|
9
|
+
OS X, and the completion ports interface for Solaris.
|
10
|
+
|
11
|
+
Cool.io also binds asynchronous wrappers to Ruby's core socket classes so you can
|
12
|
+
use them in conjunction with Cool.io to build asynchronous event-driven
|
13
|
+
applications.
|
14
|
+
|
15
|
+
You can include Cool.io in your programs with:
|
16
|
+
|
17
|
+
require 'rubygems'
|
18
|
+
require 'cool.io'
|
19
|
+
|
20
|
+
Questions? Sign up for the mailing list by emailing: [cool.io@librelist.com](mailto:cool.io@librelist.com)
|
21
|
+
|
22
|
+
The latest development code is available via github at:
|
23
|
+
|
24
|
+
[git://github.com/tarcieri/cool.io.git](git://github.com/tarcieri/cool.io.git)
|
25
|
+
|
26
|
+
Anatomy
|
27
|
+
-------
|
28
|
+
|
29
|
+
Cool.io builds on two core classes which bind to the libev API:
|
30
|
+
|
31
|
+
* Cool.io::Loop - This class represents an event loop which uses underlying high
|
32
|
+
performance system calls to wait for events.
|
33
|
+
|
34
|
+
* Cool.io::Watcher - This is the base class for event observers. Once you attach
|
35
|
+
an event observer to a loop and start running it, you will begin receiving
|
36
|
+
callbacks to particlar methods when events occur.
|
37
|
+
|
38
|
+
Watchers
|
39
|
+
--------
|
40
|
+
|
41
|
+
There are presently four types of watchers:
|
42
|
+
|
43
|
+
* Cool.io::IOWatcher - This class waits for an IO object to become readable,
|
44
|
+
writable, or both.
|
45
|
+
|
46
|
+
* Cool.io::TimerWatcher - This class waits for a specified duration then fires
|
47
|
+
an event. You can also configure it to fire an event at specified intervals.
|
48
|
+
|
49
|
+
* Cool.io::StatWatcher - Monitors files or directories for changes
|
50
|
+
|
51
|
+
* Cool.io::AsyncWatcher - Can be used to wake up a Cool.io::Loop running in a
|
52
|
+
different thread. This allows each thread to run a separate Cool.io::Loop and
|
53
|
+
for the different event loops to be able to signal each other.
|
54
|
+
|
55
|
+
Using Watchers
|
56
|
+
--------------
|
57
|
+
|
58
|
+
Watchers have five important methods:
|
59
|
+
|
60
|
+
* attach(loop) - This binds a watcher to the specified event loop. If the
|
61
|
+
watcher is already bound to a loop it will be detached first, then attached
|
62
|
+
to the new one.
|
63
|
+
|
64
|
+
* detach - This completely unbinds a watcher from an event loop.
|
65
|
+
|
66
|
+
* disable - This stops the watcher from receiving events but does not unbind
|
67
|
+
it from the loop. If you are trying to toggle a watcher on and off, it's
|
68
|
+
best to use this method (and enable) as it performs better than completely
|
69
|
+
removing the watcher from the event loop.
|
70
|
+
|
71
|
+
* enable - This re-enables a watcher which has been disabled in the past.
|
72
|
+
The watcher must still be bound to an event loop.
|
73
|
+
|
74
|
+
* evloop - This returns the Cool.io::Loop object which the watcher is currently
|
75
|
+
bound to.
|
76
|
+
|
77
|
+
Asynchronous Wrappers
|
78
|
+
---------------------
|
79
|
+
|
80
|
+
Several classes which provide asynchronous event-driven wrappers for Ruby's
|
81
|
+
core socket classes are also provided. Among these are:
|
82
|
+
|
83
|
+
* Cool.io::TCPSocket - A buffered wrapper to core Ruby's Socket class for use with
|
84
|
+
TCP sockets. You can asynchronously create outgoing TCP connections using
|
85
|
+
its Cool.io::TCPSocket.connect method. Cool.io::TCPSocket provides write buffering
|
86
|
+
to ensure that writing never blocks, and has asynchronous callbacks for
|
87
|
+
several events, including when the connection is opened (or failed), when
|
88
|
+
data is received, when the write buffer has been written out completely,
|
89
|
+
and when the connection closes.
|
90
|
+
|
91
|
+
* Cool.io::TCPServer - A wrapper for TCPServer which creates new instances of
|
92
|
+
Cool.io::TCPSocket (or any subclass you wish to provide) whenever an incoming
|
93
|
+
connection is received.
|
94
|
+
|
95
|
+
* Cool.io::HttpClient - An HTTP/1.1 client with support for chunked encoding
|
96
|
+
and streaming response processing through asynchronous callbacks.
|
97
|
+
|
98
|
+
Example Program
|
99
|
+
---------------
|
100
|
+
|
101
|
+
Cool.io provides a Sinatra-like DSL for authoring event-driven programs:
|
102
|
+
|
103
|
+
require 'rubygems'
|
104
|
+
require 'cool.io'
|
105
|
+
|
106
|
+
ADDR = '127.0.0.1'
|
107
|
+
PORT = 4321
|
108
|
+
|
109
|
+
cool.io.connection :echo_server_connection do
|
110
|
+
on_connect do
|
111
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
112
|
+
end
|
113
|
+
|
114
|
+
on_close do
|
115
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
116
|
+
end
|
117
|
+
|
118
|
+
on_read do |data|
|
119
|
+
write data
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
puts "Echo server listening on #{ADDR}:#{PORT}"
|
124
|
+
cool.io.server ADDR, PORT, :echo_server_connection
|
125
|
+
cool.io.run
|
126
|
+
|
127
|
+
This creates a new connection class called :echo_server_connection and defines
|
128
|
+
a set of callbacks for when various events occur.
|
129
|
+
|
130
|
+
We then create a new server on the given address and port. When this server
|
131
|
+
receives new connections, it will create new instances of the given connection
|
132
|
+
class for each connection.
|
133
|
+
|
134
|
+
Finally, we kick everything off with cool.io.run. Calling cool.io.run will
|
135
|
+
block, listening for events on our server.
|
136
|
+
|
137
|
+
Using Cool.io subclasses directly
|
138
|
+
---------------------------------
|
139
|
+
|
140
|
+
Below is an example of how to write an echo server using a subclass instead of
|
141
|
+
the DSL:
|
142
|
+
|
143
|
+
require 'cool.io'
|
144
|
+
HOST = 'localhost'
|
145
|
+
PORT = 4321
|
146
|
+
|
147
|
+
class EchoServerConnection < Cool.io::TCPSocket
|
148
|
+
def on_connect
|
149
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
150
|
+
end
|
151
|
+
|
152
|
+
def on_close
|
153
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
154
|
+
end
|
155
|
+
|
156
|
+
def on_read(data)
|
157
|
+
write data
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
server = Cool.io::TCPServer.new(HOST, PORT, EchoServerConnection)
|
162
|
+
server.attach(Cool.io::Loop.default)
|
163
|
+
|
164
|
+
puts "Echo server listening on #{HOST}:#{PORT}"
|
165
|
+
Cool.io::Loop.default.run
|
166
|
+
|
167
|
+
Here a new observer type (EchoServerConnection) is made by subclassing an
|
168
|
+
existing one and adding new implementations to existing event handlers.
|
169
|
+
|
170
|
+
A new event loop is created, and a new Cool.io::TCPServer (whose base class is
|
171
|
+
Cool.io::Watcher) is created and attached to the event loop.
|
172
|
+
|
173
|
+
Once this is done, the event loop is started with event_loop.run. This method
|
174
|
+
will block until there are no active watchers for the loop or the loop is
|
175
|
+
stopped explicitly with event_loop.stop.
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
gem.homepage = "http://github.com/tarcieri/cool.io"
|
13
13
|
gem.authors = ["Tony Arcieri"]
|
14
14
|
gem.add_dependency "iobuffer", ">= 0.1.3"
|
15
|
-
gem.add_development_dependency "rspec", "
|
15
|
+
gem.add_development_dependency "rspec", ">= 2.1.0"
|
16
16
|
gem.extensions = FileList["ext/**/extconf.rb"].to_a
|
17
17
|
|
18
18
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
data/cool.io.gemspec
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{cool.io}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tony Arcieri"]
|
12
|
+
s.date = %q{2010-12-13}
|
13
|
+
s.description = %q{A Ruby wrapper around the libev high performance event library}
|
14
|
+
s.email = %q{tony@medioh.com}
|
15
|
+
s.extensions = ["ext/cool.io/extconf.rb", "ext/http11_client/extconf.rb"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE",
|
18
|
+
"README.markdown"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"CHANGES",
|
22
|
+
"LICENSE",
|
23
|
+
"README.markdown",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"cool.io.gemspec",
|
27
|
+
"examples/dslified_echo_client.rb",
|
28
|
+
"examples/dslified_echo_server.rb",
|
29
|
+
"examples/echo_client.rb",
|
30
|
+
"examples/echo_server.rb",
|
31
|
+
"examples/google.rb",
|
32
|
+
"examples/httpclient.rb",
|
33
|
+
"ext/cool.io/.gitignore",
|
34
|
+
"ext/cool.io/cool.io.h",
|
35
|
+
"ext/cool.io/cool.io_ext.c",
|
36
|
+
"ext/cool.io/ev_wrap.h",
|
37
|
+
"ext/cool.io/extconf.rb",
|
38
|
+
"ext/cool.io/iowatcher.c",
|
39
|
+
"ext/cool.io/libev.c",
|
40
|
+
"ext/cool.io/loop.c",
|
41
|
+
"ext/cool.io/stat_watcher.c",
|
42
|
+
"ext/cool.io/timer_watcher.c",
|
43
|
+
"ext/cool.io/utils.c",
|
44
|
+
"ext/cool.io/watcher.c",
|
45
|
+
"ext/cool.io/watcher.h",
|
46
|
+
"ext/http11_client/.gitignore",
|
47
|
+
"ext/http11_client/LICENSE",
|
48
|
+
"ext/http11_client/ext_help.h",
|
49
|
+
"ext/http11_client/extconf.rb",
|
50
|
+
"ext/http11_client/http11_client.c",
|
51
|
+
"ext/http11_client/http11_parser.c",
|
52
|
+
"ext/http11_client/http11_parser.h",
|
53
|
+
"ext/http11_client/http11_parser.rl",
|
54
|
+
"ext/libev/Changes",
|
55
|
+
"ext/libev/LICENSE",
|
56
|
+
"ext/libev/README",
|
57
|
+
"ext/libev/README.embed",
|
58
|
+
"ext/libev/ev.c",
|
59
|
+
"ext/libev/ev.h",
|
60
|
+
"ext/libev/ev_epoll.c",
|
61
|
+
"ext/libev/ev_kqueue.c",
|
62
|
+
"ext/libev/ev_poll.c",
|
63
|
+
"ext/libev/ev_port.c",
|
64
|
+
"ext/libev/ev_select.c",
|
65
|
+
"ext/libev/ev_vars.h",
|
66
|
+
"ext/libev/ev_win32.c",
|
67
|
+
"ext/libev/ev_wrap.h",
|
68
|
+
"ext/libev/test_libev_win32.c",
|
69
|
+
"lib/.gitignore",
|
70
|
+
"lib/cool.io.rb",
|
71
|
+
"lib/cool.io/async_watcher.rb",
|
72
|
+
"lib/cool.io/dns_resolver.rb",
|
73
|
+
"lib/cool.io/dsl.rb",
|
74
|
+
"lib/cool.io/eventmachine.rb",
|
75
|
+
"lib/cool.io/http_client.rb",
|
76
|
+
"lib/cool.io/io.rb",
|
77
|
+
"lib/cool.io/iowatcher.rb",
|
78
|
+
"lib/cool.io/listener.rb",
|
79
|
+
"lib/cool.io/loop.rb",
|
80
|
+
"lib/cool.io/meta.rb",
|
81
|
+
"lib/cool.io/server.rb",
|
82
|
+
"lib/cool.io/socket.rb",
|
83
|
+
"lib/cool.io/timer_watcher.rb",
|
84
|
+
"lib/coolio.rb",
|
85
|
+
"lib/rev.rb",
|
86
|
+
"spec/async_watcher_spec.rb",
|
87
|
+
"spec/dns_spec.rb",
|
88
|
+
"spec/possible_tests/schedules_other_threads.rb",
|
89
|
+
"spec/possible_tests/test_on_resolve_failed.rb",
|
90
|
+
"spec/possible_tests/test_resolves.rb",
|
91
|
+
"spec/possible_tests/test_write_during_resolve.rb",
|
92
|
+
"spec/possible_tests/works_straight.rb",
|
93
|
+
"spec/spec_helper.rb",
|
94
|
+
"spec/timer_watcher_spec.rb",
|
95
|
+
"spec/unix_listener_spec.rb",
|
96
|
+
"spec/unix_server_spec.rb"
|
97
|
+
]
|
98
|
+
s.homepage = %q{http://github.com/tarcieri/cool.io}
|
99
|
+
s.require_paths = ["lib"]
|
100
|
+
s.rubygems_version = %q{1.3.7}
|
101
|
+
s.summary = %q{The cool event framework for Ruby}
|
102
|
+
s.test_files = [
|
103
|
+
"examples/dslified_echo_client.rb",
|
104
|
+
"examples/dslified_echo_server.rb",
|
105
|
+
"examples/echo_client.rb",
|
106
|
+
"examples/echo_server.rb",
|
107
|
+
"examples/google.rb",
|
108
|
+
"examples/httpclient.rb",
|
109
|
+
"spec/async_watcher_spec.rb",
|
110
|
+
"spec/dns_spec.rb",
|
111
|
+
"spec/possible_tests/schedules_other_threads.rb",
|
112
|
+
"spec/possible_tests/test_on_resolve_failed.rb",
|
113
|
+
"spec/possible_tests/test_resolves.rb",
|
114
|
+
"spec/possible_tests/test_write_during_resolve.rb",
|
115
|
+
"spec/possible_tests/works_straight.rb",
|
116
|
+
"spec/spec_helper.rb",
|
117
|
+
"spec/timer_watcher_spec.rb",
|
118
|
+
"spec/unix_listener_spec.rb",
|
119
|
+
"spec/unix_server_spec.rb"
|
120
|
+
]
|
121
|
+
|
122
|
+
if s.respond_to? :specification_version then
|
123
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
124
|
+
s.specification_version = 3
|
125
|
+
|
126
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
127
|
+
s.add_runtime_dependency(%q<iobuffer>, [">= 0.1.3"])
|
128
|
+
s.add_development_dependency(%q<rspec>, [">= 2.1.0"])
|
129
|
+
else
|
130
|
+
s.add_dependency(%q<iobuffer>, [">= 0.1.3"])
|
131
|
+
s.add_dependency(%q<rspec>, [">= 2.1.0"])
|
132
|
+
end
|
133
|
+
else
|
134
|
+
s.add_dependency(%q<iobuffer>, [">= 0.1.3"])
|
135
|
+
s.add_dependency(%q<rspec>, [">= 2.1.0"])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
cool.io.connect ADDR, PORT do
|
10
|
+
on_connect do
|
11
|
+
puts "Connected to #{remote_host}:#{remote_port}"
|
12
|
+
write "bounce this back to me"
|
13
|
+
end
|
14
|
+
|
15
|
+
on_close do
|
16
|
+
puts "Disconnected from #{remote_host}:#{remote_port}"
|
17
|
+
end
|
18
|
+
|
19
|
+
on_read do |data|
|
20
|
+
puts "Got: #{data}"
|
21
|
+
close
|
22
|
+
end
|
23
|
+
|
24
|
+
on_resolve_failed do
|
25
|
+
puts "Error: Couldn't resolve #{remote_host}"
|
26
|
+
end
|
27
|
+
|
28
|
+
on_connect_failed do
|
29
|
+
puts "Error: Connection refused to #{remote_host}:#{remote_port}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
puts "Echo client connecting to #{ADDR}:#{PORT}..."
|
34
|
+
cool.io.run
|
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'cool.io'
|
5
|
+
|
6
|
+
ADDR = '127.0.0.1'
|
7
|
+
PORT = 4321
|
8
|
+
|
9
|
+
cool.io.server ADDR, PORT do
|
10
|
+
on_connect do
|
11
|
+
puts "#{remote_addr}:#{remote_port} connected"
|
12
|
+
end
|
13
|
+
|
14
|
+
on_close do
|
15
|
+
puts "#{remote_addr}:#{remote_port} disconnected"
|
16
|
+
end
|
17
|
+
|
18
|
+
on_read do |data|
|
19
|
+
write data
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "Echo server listening on #{ADDR}:#{PORT}"
|
24
|
+
cool.io.run
|
data/examples/echo_client.rb
CHANGED
@@ -6,7 +6,7 @@ require 'cool.io'
|
|
6
6
|
ADDR = '127.0.0.1'
|
7
7
|
PORT = 4321
|
8
8
|
|
9
|
-
class ClientConnection <
|
9
|
+
class ClientConnection < Cool.io::TCPSocket
|
10
10
|
def on_connect
|
11
11
|
puts "#{remote_addr}:#{remote_port} connected"
|
12
12
|
write "bounce this back to me"
|
@@ -31,7 +31,7 @@ class ClientConnection < Coolio::TCPSocket
|
|
31
31
|
|
32
32
|
end
|
33
33
|
|
34
|
-
event_loop =
|
34
|
+
event_loop = Cool.io::Loop.default
|
35
35
|
client = ClientConnection.connect(ADDR, PORT)
|
36
36
|
client.attach(event_loop)
|
37
37
|
puts "Echo client connecting to #{ADDR}:#{PORT}..."
|
data/examples/echo_server.rb
CHANGED
@@ -6,7 +6,7 @@ require 'cool.io'
|
|
6
6
|
ADDR = '127.0.0.1'
|
7
7
|
PORT = 4321
|
8
8
|
|
9
|
-
class EchoServerConnection <
|
9
|
+
class EchoServerConnection < Cool.io::TCPSocket
|
10
10
|
def on_connect
|
11
11
|
puts "#{remote_addr}:#{remote_port} connected"
|
12
12
|
end
|
@@ -20,8 +20,8 @@ class EchoServerConnection < Coolio::TCPSocket
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
event_loop =
|
24
|
-
|
23
|
+
event_loop = Cool.io::Loop.default
|
24
|
+
Cool.io::TCPServer.new(ADDR, PORT, EchoServerConnection).attach(event_loop)
|
25
25
|
|
26
26
|
puts "Echo server listening on #{ADDR}:#{PORT}"
|
27
27
|
event_loop.run
|
data/ext/cool.io/loop.c
CHANGED
@@ -274,9 +274,7 @@ static VALUE Coolio_Loop_run_nonblock(VALUE self)
|
|
274
274
|
|
275
275
|
assert(loop_data->ev_loop && !loop_data->events_received);
|
276
276
|
|
277
|
-
TRAP_BEG;
|
278
277
|
RUN_LOOP(loop_data, EVLOOP_NONBLOCK);
|
279
|
-
TRAP_END;
|
280
278
|
Coolio_Loop_dispatch_events(loop_data);
|
281
279
|
|
282
280
|
nevents = INT2NUM(loop_data->events_received);
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Copyright (c) 2010, Zed A. Shaw and Mongrel2 Project Contributors.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are
|
6
|
+
met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
* Redistributions in binary form must reproduce the above copyright
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
13
|
+
documentation and/or other materials provided with the distribution.
|
14
|
+
|
15
|
+
* Neither the name of the Mongrel2 Project, Zed A. Shaw, nor the names
|
16
|
+
of its contributors may be used to endorse or promote products
|
17
|
+
derived from this software without specific prior written
|
18
|
+
permission.
|
19
|
+
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
21
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
23
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
24
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
25
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
26
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
27
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
28
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
29
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
30
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
|
data/lib/cool.io.rb
CHANGED
@@ -18,10 +18,12 @@ require "cool.io/dns_resolver"
|
|
18
18
|
require "cool.io/socket"
|
19
19
|
require "cool.io/server"
|
20
20
|
require "cool.io/http_client"
|
21
|
+
require "cool.io/dsl"
|
21
22
|
|
22
23
|
module Coolio
|
23
24
|
VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
|
24
25
|
def self.version; VERSION; end
|
26
|
+
def self.inspect; "Cool.io"; end
|
25
27
|
end
|
26
28
|
|
27
29
|
module Cool
|
data/lib/cool.io/dsl.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C)2010 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
|
+
# A module we stash all the connections defined by the DSL under
|
9
|
+
module Connections; end
|
10
|
+
|
11
|
+
# A DSL for defining Cool.io connection types and servers
|
12
|
+
module DSL
|
13
|
+
# Define all methods on the metaclass
|
14
|
+
module_function
|
15
|
+
|
16
|
+
# Run the default Cool.io event loop
|
17
|
+
def run
|
18
|
+
Cool.io::Loop.default.run
|
19
|
+
end
|
20
|
+
|
21
|
+
# Connect to the given host and port using the given connection class
|
22
|
+
def connect(host, port, connection_name = nil, *initializer_args, &block)
|
23
|
+
if block_given?
|
24
|
+
initializer_args.unshift connection_name if connection_name
|
25
|
+
|
26
|
+
klass = Class.new Cool.io::TCPSocket
|
27
|
+
connection_builder = ConnectionBuilder.new klass
|
28
|
+
connection_builder.instance_eval &block
|
29
|
+
else
|
30
|
+
raise ArgumentError, "no connection name or block given" unless connection_name
|
31
|
+
klass = self[connection_name]
|
32
|
+
end
|
33
|
+
|
34
|
+
client = klass.connect host, port, *initializer_args
|
35
|
+
client.attach Cool.io::Loop.default
|
36
|
+
client
|
37
|
+
end
|
38
|
+
|
39
|
+
# Create a new Cool.io::TCPServer
|
40
|
+
def server(host, port, connection_name = nil, *initializer_args, &block)
|
41
|
+
if block_given?
|
42
|
+
initializer_args.unshift connection_name if connection_name
|
43
|
+
|
44
|
+
klass = Class.new Cool.io::TCPSocket
|
45
|
+
connection_builder = ConnectionBuilder.new klass
|
46
|
+
connection_builder.instance_eval &block
|
47
|
+
else
|
48
|
+
raise ArgumentError, "no connection name or block given" unless connection_name
|
49
|
+
klass = self[connection_name]
|
50
|
+
end
|
51
|
+
|
52
|
+
server = Cool.io::TCPServer.new host, port, klass, *initializer_args
|
53
|
+
server.attach Cool.io::Loop.default
|
54
|
+
server
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create a new Cool.io::TCPSocket class
|
58
|
+
def connection(name, &block)
|
59
|
+
# Camelize class name
|
60
|
+
class_name = name.to_s.split('_').map { |s| s.capitalize }.join
|
61
|
+
|
62
|
+
connection = Class.new Cool.io::TCPSocket
|
63
|
+
connection_builder = ConnectionBuilder.new connection
|
64
|
+
connection_builder.instance_eval &block
|
65
|
+
|
66
|
+
Coolio::Connections.const_set class_name, connection
|
67
|
+
end
|
68
|
+
|
69
|
+
# Look up a connection class by its name
|
70
|
+
def [](connection_name)
|
71
|
+
class_name = connection_name.to_s.split('_').map { |s| s.capitalize }.join
|
72
|
+
|
73
|
+
begin
|
74
|
+
Coolio::Connections.const_get class_name
|
75
|
+
rescue NameError
|
76
|
+
raise NameError, "No connection type registered for #{connection_name.inspect}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Builder for Cool.io::TCPSocket classes
|
81
|
+
class ConnectionBuilder
|
82
|
+
def initialize(klass)
|
83
|
+
@klass = klass
|
84
|
+
end
|
85
|
+
|
86
|
+
# Declare an initialize function
|
87
|
+
def initializer(&action)
|
88
|
+
@klass.send :define_method, :initialize, &action
|
89
|
+
end
|
90
|
+
|
91
|
+
# Declare the on_connect callback
|
92
|
+
def on_connect(&action)
|
93
|
+
@klass.send :define_method, :on_connect, &action
|
94
|
+
end
|
95
|
+
|
96
|
+
# Declare a callback fired if we failed to connect
|
97
|
+
def on_connect_failed(&action)
|
98
|
+
@klass.send :define_method, :on_connect_failed, &action
|
99
|
+
end
|
100
|
+
|
101
|
+
# Declare a callback fired if DNS resolution failed
|
102
|
+
def on_resolve_failed(&action)
|
103
|
+
@klass.send :define_method, :on_resolve_failed, &action
|
104
|
+
end
|
105
|
+
|
106
|
+
# Declare the on_close callback
|
107
|
+
def on_close(&action)
|
108
|
+
@klass.send :define_method, :on_close, &action
|
109
|
+
end
|
110
|
+
|
111
|
+
# Declare the on_read callback
|
112
|
+
def on_read(&action)
|
113
|
+
@klass.send :define_method, :on_read, &action
|
114
|
+
end
|
115
|
+
|
116
|
+
# Declare the on_write_complete callback
|
117
|
+
def on_write_complete(&action)
|
118
|
+
@klass.send :define_method, :on_write_complete, &action
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# The Cool module containing all our coolness
|
125
|
+
module Cool
|
126
|
+
module Coolness
|
127
|
+
def cool; Cool::IOThunk; end
|
128
|
+
end
|
129
|
+
|
130
|
+
module IOThunk
|
131
|
+
def self.io; Coolio::DSL; end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
extend Cool::Coolness
|
data/lib/cool.io/socket.rb
CHANGED
@@ -39,10 +39,8 @@ module Coolio
|
|
39
39
|
event_callback :on_connect_failed
|
40
40
|
|
41
41
|
# Called if a hostname failed to resolve when connecting
|
42
|
-
# Defaults to
|
43
|
-
|
44
|
-
on_connect_failed
|
45
|
-
end
|
42
|
+
# Defaults to calling on_connect_failed
|
43
|
+
alias_method :on_resolve_failed, :on_connect_failed
|
46
44
|
|
47
45
|
#########
|
48
46
|
protected
|
@@ -123,7 +121,7 @@ module Coolio
|
|
123
121
|
|
124
122
|
# Called by precreate during asyncronous DNS resolution
|
125
123
|
def preinitialize(addr, port, *args)
|
126
|
-
@_write_buffer = ::IO::Buffer.new # allow for writing BEFORE
|
124
|
+
@_write_buffer = ::IO::Buffer.new # allow for writing BEFORE DNS has resolved
|
127
125
|
@remote_host, @remote_addr, @remote_port = addr, addr, port
|
128
126
|
@_resolver = TCPConnectResolver.new(self, addr, port, *args)
|
129
127
|
end
|
@@ -137,7 +135,7 @@ module Coolio
|
|
137
135
|
|
138
136
|
super
|
139
137
|
|
140
|
-
@address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
|
138
|
+
@address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
|
141
139
|
end
|
142
140
|
|
143
141
|
def peeraddr
|
@@ -153,9 +151,9 @@ module Coolio
|
|
153
151
|
@host, addr, @port = host, addr, port
|
154
152
|
@address_family = nil
|
155
153
|
|
156
|
-
|
154
|
+
super(family, ::Socket::SOCK_STREAM, 0)
|
157
155
|
begin
|
158
|
-
|
156
|
+
connect_nonblock(::Socket.sockaddr_in(port, addr))
|
159
157
|
rescue Errno::EINPROGRESS
|
160
158
|
end
|
161
159
|
end
|
data/spec/dns_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
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
|
+
ConnectorThingy.connect(VALID_DOMAIN, 80).attach(@loop)
|
26
|
+
|
27
|
+
proc do
|
28
|
+
@loop.run
|
29
|
+
end.should raise_error(ItWorked)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "fires on_resolve_failed for invalid domains" do
|
33
|
+
ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
|
34
|
+
|
35
|
+
proc do
|
36
|
+
@loop.run
|
37
|
+
end.should raise_error(WontResolve)
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cool.io
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
- 9
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 1.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tony Arcieri
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-
|
18
|
+
date: 2010-12-13 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -40,14 +40,14 @@ dependencies:
|
|
40
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
45
|
+
hash: 11
|
46
46
|
segments:
|
47
47
|
- 2
|
48
|
+
- 1
|
48
49
|
- 0
|
49
|
-
|
50
|
-
version: 2.0.0
|
50
|
+
version: 2.1.0
|
51
51
|
type: :development
|
52
52
|
version_requirements: *id002
|
53
53
|
description: A Ruby wrapper around the libev high performance event library
|
@@ -61,12 +61,14 @@ extra_rdoc_files:
|
|
61
61
|
- LICENSE
|
62
62
|
- README.markdown
|
63
63
|
files:
|
64
|
-
- .gitignore
|
65
64
|
- CHANGES
|
66
65
|
- LICENSE
|
67
66
|
- README.markdown
|
68
67
|
- Rakefile
|
69
68
|
- VERSION
|
69
|
+
- cool.io.gemspec
|
70
|
+
- examples/dslified_echo_client.rb
|
71
|
+
- examples/dslified_echo_server.rb
|
70
72
|
- examples/echo_client.rb
|
71
73
|
- examples/echo_server.rb
|
72
74
|
- examples/google.rb
|
@@ -85,6 +87,7 @@ files:
|
|
85
87
|
- ext/cool.io/watcher.c
|
86
88
|
- ext/cool.io/watcher.h
|
87
89
|
- ext/http11_client/.gitignore
|
90
|
+
- ext/http11_client/LICENSE
|
88
91
|
- ext/http11_client/ext_help.h
|
89
92
|
- ext/http11_client/extconf.rb
|
90
93
|
- ext/http11_client/http11_client.c
|
@@ -106,11 +109,11 @@ files:
|
|
106
109
|
- ext/libev/ev_win32.c
|
107
110
|
- ext/libev/ev_wrap.h
|
108
111
|
- ext/libev/test_libev_win32.c
|
109
|
-
- ext/libev/update_ev_wrap
|
110
112
|
- lib/.gitignore
|
111
113
|
- lib/cool.io.rb
|
112
114
|
- lib/cool.io/async_watcher.rb
|
113
115
|
- lib/cool.io/dns_resolver.rb
|
116
|
+
- lib/cool.io/dsl.rb
|
114
117
|
- lib/cool.io/eventmachine.rb
|
115
118
|
- lib/cool.io/http_client.rb
|
116
119
|
- lib/cool.io/io.rb
|
@@ -124,6 +127,7 @@ files:
|
|
124
127
|
- lib/coolio.rb
|
125
128
|
- lib/rev.rb
|
126
129
|
- spec/async_watcher_spec.rb
|
130
|
+
- spec/dns_spec.rb
|
127
131
|
- spec/possible_tests/schedules_other_threads.rb
|
128
132
|
- spec/possible_tests/test_on_resolve_failed.rb
|
129
133
|
- spec/possible_tests/test_resolves.rb
|
@@ -138,8 +142,8 @@ homepage: http://github.com/tarcieri/cool.io
|
|
138
142
|
licenses: []
|
139
143
|
|
140
144
|
post_install_message:
|
141
|
-
rdoc_options:
|
142
|
-
|
145
|
+
rdoc_options: []
|
146
|
+
|
143
147
|
require_paths:
|
144
148
|
- lib
|
145
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -168,17 +172,20 @@ signing_key:
|
|
168
172
|
specification_version: 3
|
169
173
|
summary: The cool event framework for Ruby
|
170
174
|
test_files:
|
175
|
+
- examples/dslified_echo_client.rb
|
176
|
+
- examples/dslified_echo_server.rb
|
177
|
+
- examples/echo_client.rb
|
178
|
+
- examples/echo_server.rb
|
179
|
+
- examples/google.rb
|
180
|
+
- examples/httpclient.rb
|
171
181
|
- spec/async_watcher_spec.rb
|
172
|
-
- spec/
|
173
|
-
- spec/timer_watcher_spec.rb
|
174
|
-
- spec/unix_listener_spec.rb
|
175
|
-
- spec/unix_server_spec.rb
|
182
|
+
- spec/dns_spec.rb
|
176
183
|
- spec/possible_tests/schedules_other_threads.rb
|
177
184
|
- spec/possible_tests/test_on_resolve_failed.rb
|
178
185
|
- spec/possible_tests/test_resolves.rb
|
179
186
|
- spec/possible_tests/test_write_during_resolve.rb
|
180
187
|
- spec/possible_tests/works_straight.rb
|
181
|
-
-
|
182
|
-
-
|
183
|
-
-
|
184
|
-
-
|
188
|
+
- spec/spec_helper.rb
|
189
|
+
- spec/timer_watcher_spec.rb
|
190
|
+
- spec/unix_listener_spec.rb
|
191
|
+
- spec/unix_server_spec.rb
|
data/.gitignore
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
## MAC OS
|
2
|
-
.DS_Store
|
3
|
-
|
4
|
-
## TEXTMATE
|
5
|
-
*.tmproj
|
6
|
-
tmtags
|
7
|
-
|
8
|
-
## EMACS
|
9
|
-
*~
|
10
|
-
\#*
|
11
|
-
.\#*
|
12
|
-
|
13
|
-
## VIM
|
14
|
-
*.swp
|
15
|
-
|
16
|
-
## PROJECT::GENERAL
|
17
|
-
coverage
|
18
|
-
rdoc
|
19
|
-
pkg
|
20
|
-
|
21
|
-
## RUBINIUS
|
22
|
-
*.rbc
|
23
|
-
|
24
|
-
## PROJECT::SPECIFIC
|
25
|
-
conftest.dSYM
|
data/ext/libev/update_ev_wrap
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
#!/bin/sh
|
2
|
-
|
3
|
-
(
|
4
|
-
echo '#define VAR(name,decl) name'
|
5
|
-
echo '#define EV_GENWRAP 1'
|
6
|
-
cat ev_vars.h
|
7
|
-
) | cc -E -o - - | perl -ne '
|
8
|
-
while (<>) {
|
9
|
-
push @syms, $1 if /(^\w+)/;
|
10
|
-
}
|
11
|
-
print "/* DO NOT EDIT, automatically generated by update_ev_wrap */\n",
|
12
|
-
"#ifndef EV_WRAP_H\n",
|
13
|
-
"#define EV_WRAP_H\n",
|
14
|
-
(map "#define $_ ((loop)->$_)\n", @syms),
|
15
|
-
"#else\n",
|
16
|
-
"#undef EV_WRAP_H\n",
|
17
|
-
(map "#undef $_\n", @syms),
|
18
|
-
"#endif\n";
|
19
|
-
' >ev_wrap.h
|