doc: switch bogomips.org to yhbt.net
[rainbows.git] / t / async_examples / async_tailer.ru
blobc1447209291b24a580645a57e983b50f6726d76f
1 #!/usr/bin/env rackup -s thin
3 #  async_tailer.ru
4 #  raggi/thin
6 #  Tested with 150 spawned tails on OS X
8 #  Created by James Tucker on 2008-06-18.
9 #  Copyright 2008 James Tucker <raggi@rubyforge.org>.
11 # Uncomment if appropriate for you..
12 # EM.epoll
13 # EM.kqueue
15 tail_log_file = ENV["TAIL_LOG_FILE"] or abort "TAIL_LOG_FILE= env must be set"
16 unless ::File.file?(tail_log_file) && ::File.readable?(tail_log_file)
17   abort "#{tail_log_file} must be a readable regular file"
18 end
20 class DeferrableBody
21   include EventMachine::Deferrable
23   def initialize
24     @queue = []
25     # make sure to flush out the queue before closing the connection
26     callback{
27       until @queue.empty?
28         @queue.shift.each{|chunk| @body_callback.call(chunk) }
29       end
30     }
31   end
33   def schedule_dequeue
34     return unless @body_callback
35     EventMachine::next_tick do
36       next unless body = @queue.shift
37       body.each do |chunk|
38         @body_callback.call(chunk)
39       end
40       schedule_dequeue unless @queue.empty?
41     end
42   end
44   def call(body)
45     @queue << body
46     schedule_dequeue
47   end
49   def each &blk
50     @body_callback = blk
51     schedule_dequeue
52   end
54 end
56 module TailRenderer
57   attr_accessor :callback
59   def receive_data(data)
60     @callback.call([data])
61   end
63   def unbind
64     @callback.succeed
65   end
66 end
68 class AsyncTailer
70   AsyncResponse = [-1, {}, []].freeze
72   def call(env)
74     body = DeferrableBody.new
76     EventMachine::next_tick do
78       env['async.callback'].call [200, {'Content-Type' => 'text/html'}, body]
80       body.call ["<h1>Async Tailer</h1><pre>"]
82     end
84     EventMachine::popen("tail -f #{ENV["TAIL_LOG_FILE"]}", TailRenderer) do |t|
86       t.callback = body
88       # If for some reason we 'complete' body, close the tail.
89       body.callback do
90         t.close_connection
91       end
93       # If for some reason the client disconnects, close the tail.
94       body.errback do
95         t.close_connection
96       end
98     end
100     AsyncResponse
101   end
105 run AsyncTailer.new