eventmachine 1.0.3-x86-mingw32 → 1.2.0.dev.2-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +84 -1
- data/README.md +6 -7
- data/ext/binder.cpp +10 -10
- data/ext/binder.h +5 -5
- data/ext/cmain.cpp +173 -61
- data/ext/ed.cpp +262 -127
- data/ext/ed.h +50 -30
- data/ext/em.cpp +491 -445
- data/ext/em.h +101 -36
- data/ext/eventmachine.h +67 -51
- data/ext/extconf.rb +124 -31
- data/ext/fastfilereader/extconf.rb +9 -2
- data/ext/fastfilereader/mapper.cpp +3 -1
- data/ext/fastfilereader/rubymain.cpp +7 -7
- data/ext/kb.cpp +1 -1
- data/ext/pipe.cpp +11 -4
- data/ext/project.h +26 -6
- data/ext/rubymain.cpp +408 -201
- data/ext/ssl.cpp +167 -20
- data/ext/ssl.h +11 -2
- data/java/src/com/rubyeventmachine/EmReactor.java +16 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +2 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +6 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +55 -10
- data/lib/1.9/fastfilereaderext.so +0 -0
- data/lib/1.9/rubyeventmachine.so +0 -0
- data/lib/2.0/fastfilereaderext.so +0 -0
- data/lib/2.0/rubyeventmachine.so +0 -0
- data/lib/2.1/fastfilereaderext.so +0 -0
- data/lib/2.1/rubyeventmachine.so +0 -0
- data/lib/2.2/fastfilereaderext.so +0 -0
- data/lib/2.2/rubyeventmachine.so +0 -0
- data/lib/2.3/fastfilereaderext.so +0 -0
- data/lib/2.3/rubyeventmachine.so +0 -0
- data/lib/em/buftok.rb +34 -85
- data/lib/em/channel.rb +5 -0
- data/lib/em/completion.rb +2 -2
- data/lib/em/connection.rb +62 -4
- data/lib/em/iterator.rb +30 -48
- data/lib/em/pool.rb +1 -1
- data/lib/em/protocols/httpclient.rb +31 -11
- data/lib/em/protocols/line_and_text.rb +4 -4
- data/lib/em/protocols/linetext2.rb +44 -39
- data/lib/em/protocols/smtpclient.rb +60 -31
- data/lib/em/protocols/smtpserver.rb +32 -9
- data/lib/em/pure_ruby.rb +8 -3
- data/lib/em/queue.rb +16 -7
- data/lib/em/resolver.rb +64 -24
- data/lib/em/threaded_resource.rb +2 -2
- data/lib/em/tick_loop.rb +19 -19
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +96 -49
- data/lib/jeventmachine.rb +17 -0
- data/rakelib/package.rake +31 -4
- data/tests/dhparam.pem +13 -0
- data/tests/em_test_helper.rb +87 -0
- data/tests/test_attach.rb +25 -0
- data/tests/test_basic.rb +27 -38
- data/tests/test_channel.rb +14 -1
- data/tests/test_completion.rb +1 -0
- data/tests/test_connection_count.rb +22 -1
- data/tests/test_connection_write.rb +35 -0
- data/tests/test_defer.rb +17 -0
- data/tests/test_epoll.rb +26 -14
- data/tests/test_file_watch.rb +1 -0
- data/tests/test_fork.rb +75 -0
- data/tests/test_httpclient.rb +43 -0
- data/tests/test_idle_connection.rb +6 -4
- data/tests/test_ipv4.rb +125 -0
- data/tests/test_ipv6.rb +131 -0
- data/tests/test_iterator.rb +115 -0
- data/tests/test_kb.rb +19 -25
- data/tests/test_ltp2.rb +20 -0
- data/tests/test_many_fds.rb +22 -0
- data/tests/test_pause.rb +29 -0
- data/tests/test_pool.rb +2 -0
- data/tests/test_process_watch.rb +2 -0
- data/tests/test_processes.rb +7 -7
- data/tests/test_queue.rb +14 -0
- data/tests/test_resolver.rb +56 -7
- data/tests/test_set_sock_opt.rb +2 -0
- data/tests/test_smtpclient.rb +20 -0
- data/tests/test_ssl_args.rb +2 -2
- data/tests/test_ssl_dhparam.rb +83 -0
- data/tests/test_ssl_ecdh_curve.rb +79 -0
- data/tests/test_ssl_extensions.rb +49 -0
- data/tests/test_ssl_methods.rb +22 -5
- data/tests/test_ssl_protocols.rb +246 -0
- data/tests/test_ssl_verify.rb +103 -59
- data/tests/test_system.rb +4 -0
- data/tests/test_threaded_resource.rb +8 -0
- data/tests/test_unbind_reason.rb +5 -1
- metadata +173 -107
- data/.gitignore +0 -21
- data/.travis.yml +0 -12
- data/.yardopts +0 -7
- data/Gemfile +0 -2
- data/Rakefile +0 -20
- data/eventmachine.gemspec +0 -36
- data/rakelib/cpp.rake_example +0 -77
data/lib/em/resolver.rb
CHANGED
@@ -2,30 +2,31 @@ module EventMachine
|
|
2
2
|
module DNS
|
3
3
|
class Resolver
|
4
4
|
|
5
|
+
def self.windows?
|
6
|
+
if RUBY_PLATFORM =~ /mswin32|cygwin|mingw|bccwin/
|
7
|
+
require 'win32/resolv'
|
8
|
+
true
|
9
|
+
else
|
10
|
+
false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
HOSTS_FILE = windows? ? Win32::Resolv.get_hosts_path : '/etc/hosts'
|
15
|
+
|
16
|
+
@hosts = nil
|
17
|
+
@nameservers = nil
|
18
|
+
@socket = nil
|
19
|
+
|
5
20
|
def self.resolve(hostname)
|
6
21
|
Request.new(socket, hostname)
|
7
22
|
end
|
8
23
|
|
9
|
-
@socket = @nameservers = nil
|
10
|
-
|
11
24
|
def self.socket
|
12
|
-
if
|
25
|
+
if @socket && @socket.error?
|
13
26
|
@socket = Socket.open
|
14
|
-
|
15
|
-
@
|
16
|
-
IO.readlines('/etc/hosts').each do |line|
|
17
|
-
next if line =~ /^#/
|
18
|
-
addr, host = line.split(/\s+/)
|
19
|
-
|
20
|
-
if @hosts[host]
|
21
|
-
@hosts[host] << addr
|
22
|
-
else
|
23
|
-
@hosts[host] = [addr]
|
24
|
-
end
|
25
|
-
end
|
27
|
+
else
|
28
|
+
@socket ||= Socket.open
|
26
29
|
end
|
27
|
-
|
28
|
-
@socket
|
29
30
|
end
|
30
31
|
|
31
32
|
def self.nameservers=(ns)
|
@@ -33,15 +34,23 @@ module EventMachine
|
|
33
34
|
end
|
34
35
|
|
35
36
|
def self.nameservers
|
36
|
-
if
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
return @nameservers if @nameservers
|
38
|
+
|
39
|
+
if windows?
|
40
|
+
_, ns = Win32::Resolv.get_resolv_info
|
41
|
+
return @nameservers = ns || []
|
42
|
+
end
|
43
|
+
|
44
|
+
@nameservers = []
|
45
|
+
IO.readlines('/etc/resolv.conf').each do |line|
|
46
|
+
if line =~ /^nameserver (.+)$/
|
47
|
+
@nameservers << $1.split(/\s+/).first
|
42
48
|
end
|
43
49
|
end
|
50
|
+
|
44
51
|
@nameservers
|
52
|
+
rescue
|
53
|
+
@nameservers = []
|
45
54
|
end
|
46
55
|
|
47
56
|
def self.nameserver
|
@@ -49,7 +58,21 @@ module EventMachine
|
|
49
58
|
end
|
50
59
|
|
51
60
|
def self.hosts
|
61
|
+
return @hosts if @hosts
|
62
|
+
|
63
|
+
@hosts = {}
|
64
|
+
IO.readlines(HOSTS_FILE).each do |line|
|
65
|
+
next if line =~ /^#/
|
66
|
+
addr, host = line.split(/\s+/)
|
67
|
+
|
68
|
+
next unless addr && host
|
69
|
+
@hosts[host] ||= []
|
70
|
+
@hosts[host] << addr
|
71
|
+
end
|
72
|
+
|
52
73
|
@hosts
|
74
|
+
rescue
|
75
|
+
@hosts = {}
|
53
76
|
end
|
54
77
|
end
|
55
78
|
|
@@ -66,7 +89,15 @@ module EventMachine
|
|
66
89
|
|
67
90
|
def post_init
|
68
91
|
@requests = {}
|
69
|
-
|
92
|
+
end
|
93
|
+
|
94
|
+
def start_timer
|
95
|
+
@timer ||= EM.add_periodic_timer(0.1, &method(:tick))
|
96
|
+
end
|
97
|
+
|
98
|
+
def stop_timer
|
99
|
+
EM.cancel_timer(@timer)
|
100
|
+
@timer = nil
|
70
101
|
end
|
71
102
|
|
72
103
|
def unbind
|
@@ -84,6 +115,13 @@ module EventMachine
|
|
84
115
|
else
|
85
116
|
@requests[id] = req
|
86
117
|
end
|
118
|
+
|
119
|
+
start_timer
|
120
|
+
end
|
121
|
+
|
122
|
+
def deregister_request(id, req)
|
123
|
+
@requests.delete(id)
|
124
|
+
stop_timer if @requests.length == 0
|
87
125
|
end
|
88
126
|
|
89
127
|
def send_packet(pkt)
|
@@ -109,6 +147,7 @@ module EventMachine
|
|
109
147
|
req = @requests[msg.id]
|
110
148
|
if req
|
111
149
|
@requests.delete(msg.id)
|
150
|
+
stop_timer if @requests.length == 0
|
112
151
|
req.receive_answer(msg)
|
113
152
|
end
|
114
153
|
end
|
@@ -140,6 +179,7 @@ module EventMachine
|
|
140
179
|
if @tries < @max_tries
|
141
180
|
send
|
142
181
|
else
|
182
|
+
@socket.deregister_request(@id, self)
|
143
183
|
fail 'retries exceeded'
|
144
184
|
end
|
145
185
|
end
|
data/lib/em/threaded_resource.rb
CHANGED
data/lib/em/tick_loop.rb
CHANGED
@@ -7,25 +7,25 @@ module EventMachine
|
|
7
7
|
# A TickLoop is useful when one needs to distribute amounts of work
|
8
8
|
# throughout ticks in order to maintain response times. It is also useful for
|
9
9
|
# simple repeated checks and metrics.
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
10
|
+
# @example
|
11
|
+
# # Here we run through an array one item per tick until it is empty,
|
12
|
+
# # printing each element.
|
13
|
+
# # When the array is empty, we return :stop from the callback, and the
|
14
|
+
# # loop will terminate.
|
15
|
+
# # When the loop terminates, the on_stop callbacks will be called.
|
16
|
+
# EM.run do
|
17
|
+
# array = (1..100).to_a
|
18
|
+
#
|
19
|
+
# tickloop = EM.tick_loop do
|
20
|
+
# if array.empty?
|
21
|
+
# :stop
|
22
|
+
# else
|
23
|
+
# puts array.shift
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# tickloop.on_stop { EM.stop }
|
28
|
+
# end
|
29
29
|
#
|
30
30
|
class TickLoop
|
31
31
|
|
data/lib/em/version.rb
CHANGED
data/lib/eventmachine.rb
CHANGED
@@ -156,11 +156,12 @@ module EventMachine
|
|
156
156
|
# will start without release_machine being called and will immediately throw
|
157
157
|
|
158
158
|
#
|
159
|
-
if reactor_running
|
159
|
+
if @reactor_running and @reactor_pid != Process.pid
|
160
160
|
# Reactor was started in a different parent, meaning we have forked.
|
161
161
|
# Clean up reactor state so a new reactor boots up in this child.
|
162
162
|
stop_event_loop
|
163
163
|
release_machine
|
164
|
+
cleanup_machine
|
164
165
|
@reactor_running = false
|
165
166
|
end
|
166
167
|
|
@@ -184,36 +185,22 @@ module EventMachine
|
|
184
185
|
add_timer(0) { signal_loopbreak }
|
185
186
|
end
|
186
187
|
@reactor_thread = Thread.current
|
187
|
-
|
188
|
+
|
189
|
+
# Rubinius needs to come back into "Ruby space" for GC to work,
|
190
|
+
# so we'll crank the machine here.
|
191
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
|
192
|
+
while run_machine_once; end
|
193
|
+
else
|
194
|
+
run_machine
|
195
|
+
end
|
196
|
+
|
188
197
|
ensure
|
189
198
|
until @tails.empty?
|
190
199
|
@tails.pop.call
|
191
200
|
end
|
192
201
|
|
193
|
-
|
194
|
-
|
195
|
-
ensure
|
196
|
-
if @threadpool
|
197
|
-
@threadpool.each { |t| t.exit }
|
198
|
-
@threadpool.each do |t|
|
199
|
-
next unless t.alive?
|
200
|
-
begin
|
201
|
-
# Thread#kill! does not exist on 1.9 or rbx, and raises
|
202
|
-
# NotImplemented on jruby
|
203
|
-
t.kill!
|
204
|
-
rescue NoMethodError, NotImplementedError
|
205
|
-
t.kill
|
206
|
-
# XXX t.join here?
|
207
|
-
end
|
208
|
-
end
|
209
|
-
@threadqueue = nil
|
210
|
-
@resultqueue = nil
|
211
|
-
@threadpool = nil
|
212
|
-
@all_threads_spawned = false
|
213
|
-
end
|
214
|
-
|
215
|
-
@next_tick_queue = []
|
216
|
-
end
|
202
|
+
release_machine
|
203
|
+
cleanup_machine
|
217
204
|
@reactor_running = false
|
218
205
|
@reactor_thread = nil
|
219
206
|
end
|
@@ -258,15 +245,32 @@ module EventMachine
|
|
258
245
|
# Original patch by Aman Gupta.
|
259
246
|
#
|
260
247
|
Kernel.fork do
|
261
|
-
if
|
262
|
-
|
263
|
-
|
248
|
+
if reactor_running?
|
249
|
+
stop_event_loop
|
250
|
+
release_machine
|
251
|
+
cleanup_machine
|
264
252
|
@reactor_running = false
|
253
|
+
@reactor_thread = nil
|
265
254
|
end
|
266
|
-
|
255
|
+
run block
|
267
256
|
end
|
268
257
|
end
|
269
258
|
|
259
|
+
# Clean up Ruby space following a release_machine
|
260
|
+
def self.cleanup_machine
|
261
|
+
if @threadpool && !@threadpool.empty?
|
262
|
+
# Tell the threads to stop
|
263
|
+
@threadpool.each { |t| t.exit }
|
264
|
+
# Join the threads or bump the stragglers one more time
|
265
|
+
@threadpool.each { |t| t.join 0.01 || t.exit }
|
266
|
+
end
|
267
|
+
@threadpool = nil
|
268
|
+
@threadqueue = nil
|
269
|
+
@resultqueue = nil
|
270
|
+
@all_threads_spawned = false
|
271
|
+
@next_tick_queue = []
|
272
|
+
end
|
273
|
+
|
270
274
|
# Adds a block to call as the reactor is shutting down.
|
271
275
|
#
|
272
276
|
# These callbacks are called in the _reverse_ order to which they are added.
|
@@ -531,6 +535,15 @@ module EventMachine
|
|
531
535
|
s
|
532
536
|
end
|
533
537
|
|
538
|
+
# Attach to an existing socket's file descriptor. The socket may have been
|
539
|
+
# started with {EventMachine.start_server}.
|
540
|
+
def self.attach_server sock, handler=nil, *args, &block
|
541
|
+
klass = klass_from_handler(Connection, handler, *args)
|
542
|
+
sd = sock.respond_to?(:fileno) ? sock.fileno : sock
|
543
|
+
s = attach_sd(sd)
|
544
|
+
@acceptors[s] = [klass,args,block,sock]
|
545
|
+
s
|
546
|
+
end
|
534
547
|
|
535
548
|
# Stop a TCP server socket that was started with {EventMachine.start_server}.
|
536
549
|
# @see EventMachine.start_server
|
@@ -737,7 +750,12 @@ module EventMachine
|
|
737
750
|
end
|
738
751
|
|
739
752
|
if io.respond_to?(:fileno)
|
740
|
-
|
753
|
+
# getDescriptorByFileno deprecated in JRuby 1.7.x, removed in JRuby 9000
|
754
|
+
if defined?(JRuby) && JRuby.runtime.respond_to?(:getDescriptorByFileno)
|
755
|
+
fd = JRuby.runtime.getDescriptorByFileno(io.fileno).getChannel
|
756
|
+
else
|
757
|
+
fd = io.fileno
|
758
|
+
end
|
741
759
|
else
|
742
760
|
fd = io
|
743
761
|
end
|
@@ -957,13 +975,16 @@ module EventMachine
|
|
957
975
|
callback = @next_tick_mutex.synchronize { @next_tick_queue.shift }
|
958
976
|
begin
|
959
977
|
callback.call
|
978
|
+
rescue
|
979
|
+
exception_raised = true
|
980
|
+
raise
|
960
981
|
ensure
|
961
982
|
# This is a little nasty. The problem is, if an exception occurs during
|
962
983
|
# the callback, then we need to send a signal to the reactor to actually
|
963
984
|
# do some work during the next_tick. The only mechanism we have from the
|
964
985
|
# ruby side is next_tick itself, although ideally, we'd just drop a byte
|
965
986
|
# on the loopback descriptor.
|
966
|
-
EM.next_tick {} if
|
987
|
+
EM.next_tick {} if exception_raised
|
967
988
|
end
|
968
989
|
end
|
969
990
|
end
|
@@ -972,11 +993,14 @@ module EventMachine
|
|
972
993
|
# EventMachine.defer is used for integrating blocking operations into EventMachine's control flow.
|
973
994
|
# The action of {.defer} is to take the block specified in the first parameter (the "operation")
|
974
995
|
# and schedule it for asynchronous execution on an internal thread pool maintained by EventMachine.
|
975
|
-
# When the operation completes, it will pass the result computed by the block (if any)
|
976
|
-
#
|
977
|
-
#
|
978
|
-
#
|
979
|
-
#
|
996
|
+
# When the operation completes, it will pass the result computed by the block (if any) back to the
|
997
|
+
# EventMachine reactor. Then, EventMachine calls the block specified in the second parameter to
|
998
|
+
# {.defer} (the "callback"), as part of its normal event handling loop. The result computed by the
|
999
|
+
# operation block is passed as a parameter to the callback. You may omit the callback parameter if
|
1000
|
+
# you don't need to execute any code after the operation completes. If the operation raises an
|
1001
|
+
# unhandled exception, the exception will be passed to the third parameter to {.defer} (the
|
1002
|
+
# "errback"), as part of its normal event handling loop. If no errback is provided, the exception
|
1003
|
+
# will be allowed to blow through to the main thread immediately.
|
980
1004
|
#
|
981
1005
|
# ## Caveats ##
|
982
1006
|
#
|
@@ -990,6 +1014,11 @@ module EventMachine
|
|
990
1014
|
# the number of threads in its pool, so if you do this enough times, your subsequent deferred
|
991
1015
|
# operations won't get a chance to run.
|
992
1016
|
#
|
1017
|
+
# The threads within the EventMachine's thread pool have abort_on_exception set to true. As a result,
|
1018
|
+
# if an unhandled exception is raised by the deferred operation and an errback is not provided, it
|
1019
|
+
# will blow through to the main thread immediately. If the main thread is within an indiscriminate
|
1020
|
+
# rescue block at that time, the exception could be handled improperly by the main thread.
|
1021
|
+
#
|
993
1022
|
# @example
|
994
1023
|
#
|
995
1024
|
# operation = proc {
|
@@ -999,14 +1028,18 @@ module EventMachine
|
|
999
1028
|
# callback = proc {|result|
|
1000
1029
|
# # do something with result here, such as send it back to a network client.
|
1001
1030
|
# }
|
1031
|
+
# errback = proc {|error|
|
1032
|
+
# # do something with error here, such as re-raising or logging.
|
1033
|
+
# }
|
1002
1034
|
#
|
1003
|
-
# EventMachine.defer(operation, callback)
|
1035
|
+
# EventMachine.defer(operation, callback, errback)
|
1004
1036
|
#
|
1005
1037
|
# @param [#call] op An operation you want to offload to EventMachine thread pool
|
1006
1038
|
# @param [#call] callback A callback that will be run on the event loop thread after `operation` finishes.
|
1039
|
+
# @param [#call] errback An errback that will be run on the event loop thread after `operation` raises an exception.
|
1007
1040
|
#
|
1008
1041
|
# @see EventMachine.threadpool_size
|
1009
|
-
def self.defer op = nil, callback = nil, &blk
|
1042
|
+
def self.defer op = nil, callback = nil, errback = nil, &blk
|
1010
1043
|
# OBSERVE that #next_tick hacks into this mechanism, so don't make any changes here
|
1011
1044
|
# without syncing there.
|
1012
1045
|
#
|
@@ -1023,7 +1056,7 @@ module EventMachine
|
|
1023
1056
|
spawn_threadpool
|
1024
1057
|
end
|
1025
1058
|
|
1026
|
-
@threadqueue << [op||blk,callback]
|
1059
|
+
@threadqueue << [op||blk,callback,errback]
|
1027
1060
|
end
|
1028
1061
|
|
1029
1062
|
|
@@ -1033,9 +1066,19 @@ module EventMachine
|
|
1033
1066
|
thread = Thread.new do
|
1034
1067
|
Thread.current.abort_on_exception = true
|
1035
1068
|
while true
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1069
|
+
begin
|
1070
|
+
op, cback, eback = *@threadqueue.pop
|
1071
|
+
rescue ThreadError
|
1072
|
+
$stderr.puts $!.message
|
1073
|
+
break # Ruby 2.0 may fail at Queue.pop
|
1074
|
+
end
|
1075
|
+
begin
|
1076
|
+
result = op.call
|
1077
|
+
@resultqueue << [result, cback]
|
1078
|
+
rescue Exception => error
|
1079
|
+
raise error unless eback
|
1080
|
+
@resultqueue << [error, eback]
|
1081
|
+
end
|
1039
1082
|
EventMachine.signal_loopbreak
|
1040
1083
|
end
|
1041
1084
|
end
|
@@ -1181,7 +1224,7 @@ module EventMachine
|
|
1181
1224
|
#
|
1182
1225
|
# @return [Boolean] true if the EventMachine reactor loop is currently running
|
1183
1226
|
def self.reactor_running?
|
1184
|
-
|
1227
|
+
@reactor_running && Process.pid == @reactor_pid
|
1185
1228
|
end
|
1186
1229
|
|
1187
1230
|
|
@@ -1447,9 +1490,13 @@ module EventMachine
|
|
1447
1490
|
rescue Errno::EBADF, IOError
|
1448
1491
|
end
|
1449
1492
|
end
|
1450
|
-
rescue
|
1451
|
-
|
1452
|
-
|
1493
|
+
rescue Exception => e
|
1494
|
+
if stopping?
|
1495
|
+
@wrapped_exception = $!
|
1496
|
+
stop
|
1497
|
+
else
|
1498
|
+
raise e
|
1499
|
+
end
|
1453
1500
|
end
|
1454
1501
|
elsif c = @acceptors.delete( conn_binding )
|
1455
1502
|
# no-op
|
@@ -1512,9 +1559,9 @@ module EventMachine
|
|
1512
1559
|
raise ArgumentError, "must provide module or subclass of #{klass.name}" unless klass >= handler
|
1513
1560
|
handler
|
1514
1561
|
elsif handler
|
1515
|
-
|
1562
|
+
if defined?(handler::EM_CONNECTION_CLASS)
|
1516
1563
|
handler::EM_CONNECTION_CLASS
|
1517
|
-
|
1564
|
+
else
|
1518
1565
|
handler::const_set(:EM_CONNECTION_CLASS, Class.new(klass) {include handler})
|
1519
1566
|
end
|
1520
1567
|
else
|