#!/usr/bin/env ruby
require 'net/http'
require 'uri'

$sleep_interval = 1 # 1 second between iterations

## very basic single-page fetcher, will follow redirection but only fetches initial response
## does not go back and fetch linked resources like css, images, js files, etc.
class HttpFetcher 
  
  def fetch2(uri_str, limit = 10)
    raise ArgumentError, 'HTTP redirect too deep' if limit == 0
    response = Net::HTTP.get_response(URI.parse(uri_str))
    case response
    when Net::HTTPSuccess     then 
      response 
      puts "success "
    when Net::HTTPRedirection then 
      print "redirect "
      fetch2(response['location'], limit - 1)
    when Net::HTTPClientError then
      response 
      puts "client error"
    when Net::HTTPServerError then
      response 
      puts "server error"
    else
      response.error!
    end
    #puts "** NEW REQUEST\n#{response.body}"    
  end  
end

## this is what ramps up the requests to multple threads
## each thread looping through and fetching each url in the array once
## future enhancement might be pass in param for number of times each thread runs through array of URL's
class HttpLoadRunner
  
  def fetch_in_threads(uri_strs, num_threads, loops_per_thread)
    $cnt = 0
    tt = []    
    num_threads.times  do
      $cnt += 1
      thread = Thread.new do
		currthread = $cnt
        begin
          x = HttpFetcher.new
		  loops_per_thread.times do |iter|
	          uri_strs.each do |uri_str|
	            puts "Thread #{currthread} Iteration #{iter} ** #{uri_str} ** starting"
	            x.fetch2(uri_str, 2)
	            puts "Thread #{currthread} Iteration #{iter} ** #{uri_str} ** done"
	          end
		  end
		  sleep($sleep_interval)
        rescue
          puts "Exception"
        end
      end
      tt << thread
    end
    tt.each {|thr| thr.join }
  end
  
end

## next line checks to see if this script is being run itself or run as library
## only runs this tuff if standalone
if __FILE__ == $0  
  if ARGV.length != 3 then
    puts "Usage: #{$0} num-threads url-file loops-per-thread"
    puts "\twhere num-threads is an integer indicating number of simulated users (threads)"
    puts "\tand url-file is path/filename to a text file containing 1 URL per line"	
    puts "\tand loops-per-thread is number of times each thread runs through list of URLs"	
    exit
  end
  
  numthreads = (ARGV.first == nil) ? 1 : ARGV.first.to_i
  puts "Number of threads to run: #{numthreads}"
  
  filename = ARGV[1]
  puts "URL filename: #{filename}"
 
  numloops = ARGV[2].to_i
  puts "Number of loops/thread: #{numloops}"
  
  test_urls = []
  File.new(filename, "r").each { |line| test_urls << line }
  puts "URLS:\n -> #{test_urls.join("\n -> ")}"
  
  lr = HttpLoadRunner.new
  lr.fetch_in_threads(test_urls, numthreads, numloops)
end