1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
| | # based on async_examples/async_app.ru by James Tucker
class DeferrableChunkBody
include EventMachine::Deferrable
def call(*body)
body.each do |chunk|
@body_callback.call("#{chunk.size.to_s(16)}\r\n")
@body_callback.call(chunk)
@body_callback.call("\r\n")
end
end
def each(&block)
@body_callback = block
end
def finish
@body_callback.call("0\r\n\r\n")
end
end if defined?(EventMachine)
class AsyncChunkApp
def call(env)
headers = {
'Content-Type' => 'text/plain',
'Transfer-Encoding' => 'chunked',
}
delay = env["HTTP_X_DELAY"].to_i
case env["rainbows.model"]
when :EventMachine, :NeverBlock
body = DeferrableChunkBody.new
body.callback { body.finish }
task = lambda {
env['async.callback'].call([ 200, headers, body ])
EM.add_timer(1) {
body.call "Hello "
EM.add_timer(1) {
body.call "World #{env['PATH_INFO']}\n"
body.succeed
}
}
}
delay == 0 ? EM.next_tick(&task) : EM.add_timer(delay, &task)
when :Coolio
# Cool.io only does one-shot responses due to the lack of the
# equivalent of EM::Deferrables
body = [ "Hello ", "World #{env['PATH_INFO']}\n", '' ].map do |chunk|
"#{chunk.size.to_s(16)}\r\n#{chunk}\r\n"
end
next_tick = Coolio::TimerWatcher.new(delay, false)
next_tick.on_timer { env['async.callback'].call([ 200, headers, body ]) }
next_tick.attach(Coolio::Loop.default)
else
raise "Not supported: #{env['rainbows.model']}"
end
nil
end
end
run AsyncChunkApp.new
|