require 'webrick' require 'yaml' if $DEBUG Thread.abort_on_exception else exit if fork $stdout = File.new('/dev/null', 'w') $stderr = File.new('/dev/null', 'w') end Thread.new do while(true) sleep(300) GC.start end end class NilClass def to_json; "null"; end end class TrueClass def to_json; "true"; end end class FalseClass def to_json; "false"; end end class String def underscore self.gsub(/::/, '/'). gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2'). gsub(/([a-z\d])([A-Z])/,'\1_\2'). tr("-", "_"). downcase end alias_method :to_json, :inspect end class Numeric def formatted(precision = 1) rounded_number = (Float(self) * (10 ** precision)).round.to_f / 10 ** precision parts = ("%01.#{precision}f" % rounded_number).to_s.split('.') parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,") parts.join(".") end alias_method :to_json, :inspect end class Array def formatted! each_with_index do |v, i| if v.is_a? Numeric self[i] = v.formatted elsif v.is_a? Hash or v.is_a? Array self[i] = self[i].dup.formatted! end end end def symbolize_keys! each_with_index { |v, i| self[i] = self[i].dup.symbolize_keys! if v.is_a? Hash } end def stringify_keys! each_with_index { |v, i| self[i] = self[i].dup.stringify_keys! if v.is_a? Hash } end def to_json "[#{map { |e| e.to_json }.join(',')}]" end end class Hash def formatted! each_pair do |k, v| if v.is_a? Numeric self[k] = v.formatted elsif v.is_a? Hash or v.is_a? Array self[k] = self[k].dup.formatted! end end end def symbolize_keys! keys.each { |key| self[key.to_sym] = delete(key) } each_pair { |k, v| self[k] = self[k].dup.symbolize_keys! if v.is_a? Hash } end def stringify_keys! keys.each { |key| self[key.to_s] = delete(key) } each_pair { |k, v| self[k] = self[k].dup.stringify_keys! if v.is_a? Hash } end alias_method :undecorated_get, :[] def [](key) undecorated_get(key) or undecorated_get(key.is_a?(String) ? key.to_sym : key.to_s) end def to_json arr = [] each_pair { |k, v| arr << "#{k.to_json}:#{v.to_json}" } "{#{arr.join(',')}}" end end class Symbol def to_json to_s.inspect end end module DataProviders DATA_SOURCES_CLASSES = {} DATA_SOURCES = {} def self.preload Dir.glob("#{File.dirname(__FILE__)}/data_providers/*.rb").each { |file| load file unless file =~ /extconf.rb$/ } DataProviders.constants.each do |c| c = DataProviders.const_get(c) DATA_SOURCES_CLASSES[c.to_s.gsub(/^DataProviders::/, '').underscore] = c if c.is_a? Class end end def self.setup(settings) DATA_SOURCES_CLASSES.each_pair { |k, v| DATA_SOURCES[k] = v.new(settings[k]) } end end DataProviders.preload WEBSTATS_PATH = File.expand_path("~/.webstats") $settings = {} if File.exists?(WEBSTATS_PATH) $settings = YAML.load(IO.read(WEBSTATS_PATH)).symbolize_keys! else $settings['webstats'] = { 'password' => nil } DataProviders::DATA_SOURCES_CLASSES.each_pair { |k, v| $settings[k.to_s] = v.default_settings.stringify_keys! } File.open(WEBSTATS_PATH, "w") { |f| YAML.dump($settings, f) } end DataProviders.setup($settings) class Webstats < WEBrick::HTTPServlet::AbstractServlet def do_GET(req, res) WEBrick::HTTPAuth.basic_auth(req, res, "Webstats") { |u, p| u == 'webstats' and p == $settings[:webstats][:password] } unless $settings[:webstats][:password].nil? body = "" if req.path_info == '/' body << <<-EOF