middleware: avoid capturing block variable
[raindrops.git] / lib / raindrops / middleware.rb
blob2eb4e66c87e405121d8fe96de57438466bab7bad
1 # -*- encoding: binary -*-
2 require 'raindrops'
4 # Raindrops middleware should be loaded at the top of Rack
5 # middleware stack before other middlewares for maximum accuracy.
6 class Raindrops::Middleware < Struct.new(:app, :stats, :path, :tcp, :unix)
8   # :stopdoc:
9   Stats = Raindrops::Struct.new(:calling, :writing)
10   PATH_INFO = "PATH_INFO"
11   # :startdoc:
13   def initialize(app, opts = {})
14     super(app, opts[:stats] || Stats.new, opts[:path] || "/_raindrops")
15     tmp = opts[:listeners]
16     if tmp.nil? && defined?(Unicorn) && Unicorn.respond_to?(:listener_names)
17       tmp = Unicorn.listener_names
18     end
20     if tmp
21       self.tcp = tmp.grep(/\A[^:]+:\d+\z/)
22       self.unix = tmp.grep(%r{\A/})
23       self.tcp = nil if tcp.empty?
24       self.unix = nil if unix.empty?
25     end
26   end
28   # standard Rack endpoint
29   def call(env)
30     env[PATH_INFO] == path ? stats_response : dup._call(env)
31   end
33   def _call(env)
34     stats.incr_calling
35     status, headers, self.app = app.call(env)
37     # the Rack server will start writing headers soon after this method
38     stats.incr_writing
39     [ status, headers, self ]
40     ensure
41       stats.decr_calling
42   end
44   # yield to the Rack server here for writing
45   def each
46     app.each { |x| yield x }
47   end
49   # the Rack server should call this after #each (usually ensure-d)
50   def close
51     stats.decr_writing
52     app.close if app.respond_to?(:close)
53   end
55   def stats_response
56     body = "calling: #{stats.calling}\n" \
57            "writing: #{stats.writing}\n"
59     if defined?(Raindrops::Linux)
60       Raindrops::Linux.tcp_listener_stats(tcp).each do |addr,stats|
61         body << "#{addr} active: #{stats.active}\n" \
62                 "#{addr} queued: #{stats.queued}\n"
63       end if tcp
64       Raindrops::Linux.unix_listener_stats(unix).each do |addr,stats|
65         body << "#{addr} active: #{stats.active}\n" \
66                 "#{addr} queued: #{stats.queued}\n"
67       end if unix
68     end
70     headers = {
71       "Content-Type" => "text/plain",
72       "Content-Length" => body.size.to_s,
73     }
74     [ 200, headers, [ body ] ]
75   end
76 end