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 to_json "[#{map { |e| e.to_json }.join(',')}]" end end class Hash def formatted out = self.dup out.each_pair { |k, v| out[k] = v.formatted } out 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 } 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)) else DataProviders::DATA_SOURCES_CLASSES.each_pair do |k, v| settings[k] = v.default_settings end File.open(WEBSTATS_PATH, "w") do |f| YAML.dump(settings, f) end end DataProviders.setup(settings) class Webstats < WEBrick::HTTPServlet::AbstractServlet def do_GET(req, res) WEBrick::HTTPAuth.basic_auth(req, res, "Webstats") { |user, pass| user == 'webstats' and pass == ARGV[0] } unless ARGV.empty? body = "" if req.path_info == '/' body << <<-EOF