cool.io 0.9.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|