rainbows 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -101,7 +101,7 @@
101
101
  %li
102
102
  rack.input streaming is what makes
103
103
  %a(href="http://upr.bogomips.org/") upload progress,
104
- BOSH, and Web Sockets possible
104
+ and BOSH possible
105
105
  %li
106
106
  rack.input streaming is NOT compatible with current versions of nginx
107
107
  or any proxy that fully buffers request bodies before proxying.
@@ -221,78 +221,91 @@
221
221
  %th.lock
222
222
  %a(href="http://rack.rubyforge.org/doc/Rack/Lock.html") Rack::Lock
223
223
  %th.async async
224
+ %th.ws Web Sockets
224
225
  %tr.comp_row
225
226
  %td.mod Unicorn/Base
226
227
  %td.devfd no-op
227
228
  %td.app_pool no-op
228
229
  %td.lock no-op
229
230
  %td.async lots of RAM :P
231
+ %td.ws no
230
232
  %tr.comp_row
231
233
  %td.mod Revactor
232
234
  %td.devfd no-op
233
235
  %td.app_pool Yes
234
236
  %td.lock No!
235
237
  %td.async Revactor itself
238
+ %td.ws Sunshowers
236
239
  %tr.comp_row
237
240
  %td.mod ThreadPool
238
241
  %td.devfd no-op
239
242
  %td.app_pool Yes
240
243
  %td.lock Yes
241
244
  %td.async standard Ruby
245
+ %td.ws Sunshowers
242
246
  %tr.comp_row
243
247
  %td.mod Rev
244
248
  %td.devfd Yes
245
249
  %td.app_pool no-op
246
250
  %td.lock no-op
247
251
  %td.async DevFdResponse
252
+ %td.ws no
248
253
  %tr.comp_row
249
254
  %td.mod ThreadSpawn
250
255
  %td.devfd no-op
251
256
  %td.app_pool Yes
252
257
  %td.lock Yes
253
258
  %td.async standard Ruby
259
+ %td.ws Sunshowers
254
260
  %tr.comp_row
255
261
  %td.mod EventMachine
256
262
  %td.devfd Yes
257
263
  %td.app_pool no-op
258
264
  %td.lock no-op
259
265
  %td.async async_sinatra
266
+ %td.ws no
260
267
  %tr.comp_row
261
268
  %td.mod RevThreadSpawn
262
269
  %td.devfd Yes
263
270
  %td.app_pool Yes
264
271
  %td.lock Dumb
265
272
  %td.async standard Ruby
273
+ %td.ws no
266
274
  %tr.comp_row
267
275
  %td.mod FiberSpawn
268
276
  %td.devfd Yes
269
277
  %td.app_pool Yes
270
278
  %td.lock No!
271
279
  %td.async Rainbows::Fiber{::IO,.sleep}
280
+ %td.ws Sunshowers
272
281
  %tr.comp_row
273
282
  %td.mod FiberPool
274
283
  %td.devfd Yes
275
284
  %td.app_pool Yes
276
285
  %td.lock No!
277
286
  %td.async Rainbows::Fiber{::IO,.sleep}
287
+ %td.ws Sunshowers
278
288
  %tr.comp_row
279
289
  %td.mod ActorSpawn
280
290
  %td.devfd no-op
281
291
  %td.app_pool Yes
282
292
  %td.lock Yes
283
293
  %td.async standard Ruby
294
+ %td.ws Sunshowers
284
295
  %tr.comp_row
285
296
  %td.mod NeverBlock
286
297
  %td.devfd Yes
287
298
  %td.app_pool Yes*
288
299
  %td.lock Yes*
289
300
  %td.async NeverBlock, async_sinatra
301
+ %td.ws no
290
302
  %tr.comp_row
291
303
  %td.mod RevThreadPool
292
304
  %td.devfd Yes
293
305
  %td.app_pool Yes
294
306
  %td.lock Dumb
295
307
  %td.async standard Ruby
308
+ %td.ws no
296
309
 
297
310
  %ul
298
311
  %li
@@ -1,6 +1,6 @@
1
- % rainbows(1) Unicorn User Manual
2
- % The Unicorn Community <mongrel-unicorn@rubyforge.org>
3
- % September 15, 2009
1
+ % rainbows(1) Rainbows! User Manual
2
+ % Rainbows! Hackers <rainbows-talk@rubyforge.org>
3
+ % December 3, 2009
4
4
 
5
5
  # NAME
6
6
 
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.8.0.GIT
4
+ DEF_VER=v0.9.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -58,7 +58,7 @@ NEWS: GIT-VERSION-FILE
58
58
  $(RAKE) -s news_rdoc > $@+
59
59
  mv $@+ $@
60
60
 
61
- SINCE = 0.6.0
61
+ SINCE = 0.8.0
62
62
  ChangeLog: LOG_VERSION = \
63
63
  $(shell git rev-parse -q "$(GIT_VERSION)" >/dev/null 2>&1 && \
64
64
  echo $(GIT_VERSION) || git describe)
data/README CHANGED
@@ -22,6 +22,7 @@ For network concurrency, models we currently support are:
22
22
  * {FiberSpawn}[link:Rainbows/FiberSpawn.html]
23
23
  * {FiberPool}[link:Rainbows/FiberPool.html]
24
24
  * {NeverBlock}[link:Rainbows/NeverBlock.html]
25
+ * {RevThreadPool}[link:Rainbows/RevThreadPool.html]
25
26
 
26
27
  We have {many more on the way}[link:TODO.html] for handling network
27
28
  concurrency. Additionally, we also use multiple processes (managed by
@@ -57,6 +58,7 @@ network concurrency.
57
58
 
58
59
  \Rainbows is mainly designed for the odd things Unicorn sucks at:
59
60
 
61
+ * Web Sockets (via {Sunshowers}[http://rainbows.rubyforge.org/sunshowers/])
60
62
  * 3rd-party APIs (to services outside your control/LAN)
61
63
  * OpenID consumers (to providers outside your control/LAN)
62
64
  * Reverse proxy implementations with editing/censoring
@@ -66,8 +68,7 @@ network concurrency.
66
68
  * HTTP server push
67
69
  * Long polling
68
70
  * Reverse AJAX
69
- * HTML 5 Web Sockets
70
- * real-time upload processing
71
+ * real-time upload processing (via {upr}[http://upr.bogomips.org/])
71
72
 
72
73
  \Rainbows can also be used to service slow clients directly even with
73
74
  fast applications.
@@ -115,9 +116,10 @@ command-line switch. \Rainbows! accepts all options found in
115
116
  as well as the "\Rainbows!" block, so you can have the following in your
116
117
  config file:
117
118
 
119
+ worker_processes 4 # assuming four CPU cores
118
120
  Rainbows! do
119
- use :Revactor
120
- worker_connections 400
121
+ use :FiberSpawn
122
+ worker_connections 100
121
123
  end
122
124
 
123
125
  See the {Rainbows! configuration documentation}[link:Rainbows.html#M000001]
data/Rakefile CHANGED
@@ -50,7 +50,9 @@ task :news_atom do
50
50
  url = "#{cgit_url}/tag/?id=#{tag[:tag]}"
51
51
  link! :rel => "alternate", :type => "text/html", :href =>url
52
52
  id! url
53
- content({:type => 'text'}, tag[:body])
53
+ message_only = tag[:body].split(/\n.+\(\d+\):\n {6}/s).first.strip
54
+ content({:type =>:text}, message_only)
55
+ content(:type =>:xhtml) { pre tag[:body] }
54
56
  end
55
57
  end
56
58
  end
@@ -154,3 +156,32 @@ task :raa_update do
154
156
  p res
155
157
  puts res.body
156
158
  end
159
+
160
+ desc "post to FM"
161
+ task :fm_update do
162
+ require 'tempfile'
163
+ require 'net/http'
164
+ require 'net/netrc'
165
+ require 'json'
166
+ version = ENV['VERSION'] or abort "VERSION= needed"
167
+ uri = URI.parse('http://freshmeat.net/projects/unicorn/releases.json')
168
+ rc = Net::Netrc.locate('unicorn-fm') or abort "~/.netrc not found"
169
+ api_token = rc.password
170
+ changelog = tags.find { |t| t[:tag] == "v#{version}" }[:body]
171
+ tmp = Tempfile.new('fm-changelog')
172
+ tmp.syswrite(changelog)
173
+ system(ENV["VISUAL"], tmp.path) or abort "#{ENV["VISUAL"]} failed: #$?"
174
+ changelog = File.read(tmp.path).strip
175
+
176
+ req = {
177
+ "auth_code" => api_token,
178
+ "release" => {
179
+ "tag_list" => "Stable",
180
+ "version" => version,
181
+ "changelog" => changelog,
182
+ },
183
+ }.to_json
184
+ Net::HTTP.start(uri.host, uri.port) do |http|
185
+ p http.post(uri.path, req, {'Content-Type'=>'application/json'})
186
+ end
187
+ end
data/TODO CHANGED
@@ -9,6 +9,8 @@ care about.
9
9
 
10
10
  * EventMachine.spawn - should be like Revactor, maybe?
11
11
 
12
+ * EventMachine deferrables
13
+
12
14
  * conditional app.deferred?(env) support
13
15
  Merb uses it, some other servers support it
14
16
 
data/lib/rainbows.rb CHANGED
@@ -77,11 +77,12 @@ module Rainbows
77
77
  :Base => 1, # this one can't change
78
78
  :Revactor => 50,
79
79
  :ThreadSpawn => 30,
80
- :ThreadPool => 10,
80
+ :ThreadPool => 20,
81
81
  :Rev => 50,
82
82
  :RevThreadSpawn => 50,
83
83
  :RevThreadPool => 50,
84
84
  :EventMachine => 50,
85
+ :EventMachineDefer => 50,
85
86
  :FiberSpawn => 50,
86
87
  :FiberPool => 50,
87
88
  :ActorSpawn => 50,
data/lib/rainbows/base.rb CHANGED
@@ -43,6 +43,7 @@ module Rainbows
43
43
  buf << client.readpartial(CHUNK_SIZE)
44
44
  end
45
45
 
46
+ env[CLIENT_IO] = client
46
47
  env[RACK_INPUT] = 0 == hp.content_length ?
47
48
  HttpRequest::NULL_IO :
48
49
  Unicorn::TeeInput.new(client, env, hp, buf)
@@ -3,7 +3,7 @@
3
3
  module Rainbows
4
4
 
5
5
  module Const
6
- RAINBOWS_VERSION = '0.8.0'
6
+ RAINBOWS_VERSION = '0.9.0'
7
7
 
8
8
  include Unicorn::Const
9
9
 
@@ -19,5 +19,11 @@ module Rainbows
19
19
  CONN_ALIVE = "Connection: keep-alive\r\n"
20
20
  LOCALHOST = "127.0.0.1"
21
21
 
22
+ # client IO object that supports reading and writing directly
23
+ # without filtering it through the HTTP chunk parser.
24
+ # Maybe we can get this renamed to "rack.io" if it becomes part
25
+ # of the official spec, but for now it is "hack.io"
26
+ CLIENT_IO = "hack.io".freeze
27
+
22
28
  end
23
29
  end
@@ -19,10 +19,11 @@ module Rainbows
19
19
 
20
20
  def response(e)
21
21
  case e
22
- when EOFError,Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
22
+ when EOFError, Errno::ECONNRESET,Errno::EPIPE,Errno::EINVAL,Errno::EBADF
23
23
  # swallow error if client shuts down one end or disconnects
24
24
  when Unicorn::HttpParserError
25
25
  Const::ERROR_400_RESPONSE # try to tell the client they're bad
26
+ when IOError # HttpParserError is an IOError
26
27
  else
27
28
  app(e)
28
29
  Const::ERROR_500_RESPONSE
@@ -8,6 +8,9 @@ module Rainbows
8
8
  include Rainbows::Const
9
9
  G = Rainbows::G
10
10
 
11
+ # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
12
+ ASYNC_CALLBACK = "async.callback".freeze
13
+
11
14
  def self.setup(klass)
12
15
  klass.const_set(:APP, G.server.app)
13
16
  end
@@ -66,7 +69,6 @@ module Rainbows
66
69
  if @hp.trailers(@env, @buf << data)
67
70
  @input.rewind
68
71
  app_call
69
- @input.close if File === @input
70
72
  end
71
73
  end
72
74
  rescue => e
@@ -35,9 +35,6 @@ module Rainbows
35
35
  include Rainbows::EvCore
36
36
  G = Rainbows::G
37
37
 
38
- # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
39
- ASYNC_CALLBACK = 'async.callback'.freeze
40
-
41
38
  def initialize(io)
42
39
  @_io = io
43
40
  end
@@ -176,7 +173,7 @@ module Rainbows
176
173
  return if CUR.size >= MAX
177
174
  io = Rainbows.accept(@io) or return
178
175
  sig = EM.attach_fd(io.fileno, false)
179
- CUR[sig] = Client.new(sig, io)
176
+ CUR[sig] = CL.new(sig, io)
180
177
  end
181
178
  end
182
179
 
@@ -189,16 +186,18 @@ module Rainbows
189
186
  # enable them both, should be non-fatal if not supported
190
187
  EM.epoll
191
188
  EM.kqueue
192
- logger.info "EventMachine: epoll=#{EM.epoll?} kqueue=#{EM.kqueue?}"
189
+ logger.info "#@use: epoll=#{EM.epoll?} kqueue=#{EM.kqueue?}"
190
+ client_class = Rainbows.const_get(@use).const_get(:Client)
193
191
  Server.const_set(:MAX, worker_connections + LISTENERS.size)
194
- EvCore.setup(Client)
192
+ Server.const_set(:CL, client_class)
193
+ EvCore.setup(client_class)
195
194
  EM.run {
196
195
  conns = EM.instance_variable_get(:@conns) or
197
196
  raise RuntimeError, "EM @conns instance variable not accessible!"
198
197
  Server.const_set(:CUR, conns)
199
198
  EM.add_periodic_timer(1) do
200
199
  unless G.tick
201
- conns.each_value { |client| Client === client and client.quit }
200
+ conns.each_value { |c| client_class === c and c.quit }
202
201
  EM.stop if conns.empty? && EM.reactor_running?
203
202
  end
204
203
  end
@@ -0,0 +1,59 @@
1
+ # -*- encoding: binary -*-
2
+ # :stopdoc:
3
+ # FIXME: fails many tests, experimental
4
+ require 'rainbows/event_machine'
5
+
6
+ module Rainbows
7
+
8
+ # This is currently highly experimental
9
+ module EventMachineDefer
10
+ include Rainbows::EventMachine
11
+
12
+ class Client < Rainbows::EventMachine::Client
13
+ undef_method :app_call
14
+
15
+ def defer_op
16
+ @env[RACK_INPUT] = @input
17
+ @env[REMOTE_ADDR] = @remote_addr
18
+ @env[ASYNC_CALLBACK] = method(:response_write)
19
+ catch(:async) { APP.call(@env.update(RACK_DEFAULTS)) }
20
+ rescue => e
21
+ handle_error(e)
22
+ nil
23
+ end
24
+
25
+ def defer_callback(response)
26
+ # too tricky to support pipelining with :async since the
27
+ # second (pipelined) request could be a stuck behind a
28
+ # long-running async response
29
+ (response.nil? || -1 == response.first) and return @state = :close
30
+
31
+ resume
32
+
33
+ alive = @hp.keepalive? && G.alive
34
+ out = [ alive ? CONN_ALIVE : CONN_CLOSE ] if @hp.headers?
35
+ response_write(response, out, alive)
36
+ if alive
37
+ @env.clear
38
+ @hp.reset
39
+ @state = :headers
40
+ if @hp.headers(@env, @buf)
41
+ EM.next_tick(method(:app_call))
42
+ else
43
+ set_comm_inactivity_timeout(G.kato)
44
+ end
45
+ else
46
+ quit
47
+ end
48
+ end
49
+
50
+ def app_call
51
+ pause
52
+ set_comm_inactivity_timeout(0)
53
+ # defer_callback(defer_op)
54
+ EM.defer(method(:defer_op), method(:defer_callback))
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -82,6 +82,7 @@ module Rainbows
82
82
  buf << (client.read_timeout or return)
83
83
  end
84
84
 
85
+ env[CLIENT_IO] = client
85
86
  env[RACK_INPUT] = 0 == hp.content_length ?
86
87
  HttpRequest::NULL_IO : TeeInput.new(client, env, hp, buf)
87
88
  env[REMOTE_ADDR] = remote_addr
@@ -61,7 +61,12 @@ module Rainbows
61
61
  end
62
62
  mod.setup if mod.respond_to?(:setup)
63
63
  Const::RACK_DEFAULTS['rainbows.model'] = @use = model.to_sym
64
- Const::RACK_DEFAULTS['rack.multithread'] = !!(/Thread/ =~ model.to_s)
64
+
65
+ Const::RACK_DEFAULTS['rack.multithread'] = case model.to_s
66
+ when /Thread/, "EventMachineDefer"; true
67
+ else false
68
+ end
69
+
65
70
  case @use
66
71
  when :Rev, :EventMachine, :NeverBlock
67
72
  Const::RACK_DEFAULTS['rainbows.autochunk'] = true
@@ -34,12 +34,14 @@ module Rainbows
34
34
  G.server.extend(Core)
35
35
  end
36
36
 
37
- module Client
38
-
37
+ module Core
39
38
  def self.setup
40
- const_set(:POOL, ::NB::Pool::FiberPool.new(O[:pool_size]))
41
- Rainbows.const_get(O[:backend]).const_get(:Client).module_eval do
42
- include Rainbows::NeverBlock::Client
39
+ self.const_set(:POOL, ::NB::Pool::FiberPool.new(O[:pool_size]))
40
+ base = O[:backend].to_s.gsub!(/([a-z])([A-Z])/, '\1_\2').downcase!
41
+ require "rainbows/never_block/#{base}"
42
+ Rainbows::NeverBlock.const_get(:Client).class_eval do
43
+ self.superclass.const_set(:APP, G.server.app)
44
+ include Rainbows::NeverBlock::Core
43
45
  alias _app_call app_call
44
46
  undef_method :app_call
45
47
  alias app_call nb_app_call
@@ -60,7 +62,7 @@ module Rainbows
60
62
  module Core
61
63
  def init_worker_process(worker)
62
64
  super
63
- Client.setup
65
+ Core.setup
64
66
  logger.info "NeverBlock/#{O[:backend]} pool_size=#{O[:pool_size]}"
65
67
  end
66
68
  end
@@ -0,0 +1,6 @@
1
+ module Rainbows
2
+ module NeverBlock
3
+ class Client < Rainbows::EventMachine::Client
4
+ end
5
+ end
6
+ end
@@ -7,7 +7,6 @@ module Rainbows
7
7
  module Rev
8
8
  class Server < ::Rev::IO
9
9
  G = Rainbows::G
10
- LOOP = ::Rev::Loop.default
11
10
  # CL and MAX will be defined in the corresponding worker loop
12
11
 
13
12
  def on_readable
@@ -25,10 +24,10 @@ module Rainbows
25
24
  def worker_loop(worker)
26
25
  init_worker_process(worker)
27
26
  mod = self.class.const_get(@use)
27
+ rloop = Server.const_set(:LOOP, ::Rev::Loop.default)
28
28
  Server.const_set(:MAX, @worker_connections)
29
29
  Server.const_set(:CL, mod.const_get(:Client))
30
30
  EvCore.setup(EvCore)
31
- rloop = ::Rev::Loop.default
32
31
  Heartbeat.new(1, true).attach(rloop)
33
32
  LISTENERS.map! { |s| Server.new(s).attach(rloop) }
34
33
  rloop.run
@@ -10,10 +10,6 @@ module Rainbows
10
10
  G = Rainbows::G
11
11
  HH = Rack::Utils::HeaderHash
12
12
 
13
- # we only want to attach to the Rev::Loop belonging to the
14
- # main thread in Ruby 1.9
15
- LOOP = ::Rev::Loop.default
16
-
17
13
  def self.defer!(client, response, out)
18
14
  body = response.last
19
15
  headers = HH.new(response[1])
@@ -36,7 +32,9 @@ module Rainbows
36
32
  out[0] = CONN_CLOSE
37
33
  end
38
34
 
39
- io = new(io, client, do_chunk, body).attach(LOOP)
35
+ # we only want to attach to the Rev::Loop belonging to the
36
+ # main thread in Ruby 1.9
37
+ io = new(io, client, do_chunk, body).attach(Server::LOOP)
40
38
  elsif st.file?
41
39
  headers.delete('Transfer-Encoding')
42
40
  headers['Content-Length'] ||= st.size.to_s
@@ -1,10 +1,6 @@
1
1
  # -*- encoding: binary -*-
2
2
  require 'rainbows/rev'
3
3
 
4
- RUBY_VERSION =~ %r{\A1\.8} && ::Rev::VERSION < "0.3.2" and
5
- warn "Rainbows::RevThreadSpawn + Rev (< 0.3.2)" \
6
- " does not work well under Ruby 1.8"
7
-
8
4
  module Rainbows
9
5
 
10
6
  module Rev
@@ -2,6 +2,9 @@
2
2
  require 'thread'
3
3
  require 'rainbows/rev/master'
4
4
 
5
+ RUBY_VERSION =~ %r{\A1\.8} && Rev::VERSION < "0.3.2" and
6
+ warn "Rev (< 0.3.2) and Threads do not mix well under Ruby 1.8"
7
+
5
8
  module Rainbows
6
9
  module Rev
7
10
 
@@ -11,7 +14,6 @@ module Rainbows
11
14
  KATO.delete(self)
12
15
  disable
13
16
  @env[RACK_INPUT] = @input
14
- @input = nil # not sure why, @input seems to get closed otherwise...
15
17
  app_dispatch # must be implemented by subclass
16
18
  end
17
19
 
@@ -22,7 +22,7 @@ module Rainbows
22
22
  module RevThreadPool
23
23
 
24
24
  DEFAULTS = {
25
- :pool_size => 10, # same default size as ThreadPool (w/o Rev)
25
+ :pool_size => 20, # same default size as ThreadPool (w/o Rev)
26
26
  }
27
27
 
28
28
  def self.setup
@@ -49,6 +49,7 @@ module Rainbows
49
49
  buf << client.read(*rd_args)
50
50
  end
51
51
 
52
+ env[Const::CLIENT_IO] = client
52
53
  env[Const::RACK_INPUT] = 0 == hp.content_length ?
53
54
  HttpRequest::NULL_IO :
54
55
  Rainbows::Revactor::TeeInput.new(client, env, hp, buf)
@@ -0,0 +1,11 @@
1
+ use Rack::ContentLength
2
+ use Rack::ContentType
3
+ run lambda { |env|
4
+ if env['rack.multithread'] == true &&
5
+ EM.reactor_running? &&
6
+ env['rainbows.model'] == :EventMachineDefer
7
+ [ 200, {}, [ env.inspect << "\n" ] ]
8
+ else
9
+ raise "incorrect parameters"
10
+ end
11
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rainbows! hackers
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-02 00:00:00 +00:00
12
+ date: 2009-12-13 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -46,6 +46,7 @@ extra_rdoc_files:
46
46
  - lib/rainbows/error.rb
47
47
  - lib/rainbows/ev_core.rb
48
48
  - lib/rainbows/event_machine.rb
49
+ - lib/rainbows/event_machine_defer.rb
49
50
  - lib/rainbows/fiber.rb
50
51
  - lib/rainbows/fiber/base.rb
51
52
  - lib/rainbows/fiber/io.rb
@@ -55,6 +56,7 @@ extra_rdoc_files:
55
56
  - lib/rainbows/http_response.rb
56
57
  - lib/rainbows/http_server.rb
57
58
  - lib/rainbows/never_block.rb
59
+ - lib/rainbows/never_block/event_machine.rb
58
60
  - lib/rainbows/rev.rb
59
61
  - lib/rainbows/rev/client.rb
60
62
  - lib/rainbows/rev/core.rb
@@ -111,6 +113,7 @@ files:
111
113
  - lib/rainbows/error.rb
112
114
  - lib/rainbows/ev_core.rb
113
115
  - lib/rainbows/event_machine.rb
116
+ - lib/rainbows/event_machine_defer.rb
114
117
  - lib/rainbows/fiber.rb
115
118
  - lib/rainbows/fiber/base.rb
116
119
  - lib/rainbows/fiber/io.rb
@@ -120,6 +123,7 @@ files:
120
123
  - lib/rainbows/http_response.rb
121
124
  - lib/rainbows/http_server.rb
122
125
  - lib/rainbows/never_block.rb
126
+ - lib/rainbows/never_block/event_machine.rb
123
127
  - lib/rainbows/rev.rb
124
128
  - lib/rainbows/rev/client.rb
125
129
  - lib/rainbows/rev/core.rb
@@ -158,6 +162,7 @@ files:
158
162
  - t/sha1.ru
159
163
  - t/simple-http_Base.ru
160
164
  - t/simple-http_EventMachine.ru
165
+ - t/simple-http_EventMachineDefer.ru
161
166
  - t/simple-http_FiberPool.ru
162
167
  - t/simple-http_FiberSpawn.ru
163
168
  - t/simple-http_NeverBlock.ru