class UltraHook::Client

Public Instance Methods

error(msg) click to toggle source
# File lib/ultrahook/client.rb, line 185
def error(msg)
  puts "Error: #{msg}"
  exit -1
end
full_path(uri) click to toggle source
# File lib/ultrahook/client.rb, line 114
def full_path(uri)
  return "/" if uri.path == "" && uri.query == ""
  return "/?#{uri.query}" if uri.path == "" && uri.query != ""
  return "#{uri.path}" if uri.path != "" && uri.query == ""
  return "#{uri.path}?#{uri.query}" if uri.path != "" && uri.query != ""
  raise "huh? this is impossible!"
end
http_post(uri, data="", headers={}) click to toggle source
# File lib/ultrahook/client.rb, line 129
def http_post(uri, data="", headers={})
  http = Net::HTTP.new(uri.host, uri.port)
  if uri.scheme == "https"
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  end
  http.post(full_path(uri), data, headers)
end
init_stream() click to toggle source
# File lib/ultrahook/client.rb, line 155
def init_stream
  uri = URI(@stream_url)
  Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
    begin
      request = Net::HTTP::Get.new "#{uri.path}?#{uri.query}"

      http.read_timeout = 3660 # give server an extra 60 seconds to send disconnect
      http.request request do |response|
        io = ""
        response.read_body do |chunk|
          io += chunk

          loop do
            if idx = io.index("\n\n")
              msg = io.slice!(0, idx+2)
              process(msg)
            else
              break
            end
          end
        end
      end

      error "Lost connection to UltraHook server"
    rescue Interrupt
      http.finish
    end
  end
end
parse_destination(dest) click to toggle source
# File lib/ultrahook/client.rb, line 68
def parse_destination(dest)
  if dest =~ /^\d+/
    "http://localhost:#{dest}"
  elsif dest =~ /^[[:alnum:]\.\-]+:\d+$/
    "http://#{dest}"
  elsif dest =~ /^[[:alnum:]\.\-]+$/
    "http://#{dest}"
  elsif dest =~ /^https?:\/\//
    dest
  else
    error "Cannot parse destination url"
  end
end
process(msg) click to toggle source
# File lib/ultrahook/client.rb, line 82
def process(msg)
  begin
    payload = JSON.parse(Base64.decode64(msg).force_encoding("utf-8"))
  rescue
    error "Cannot communicate with server."
  end

  method_name = "process_#{payload["type"]}"
  send(method_name, payload) if respond_to?(method_name)
end
process_error(payload) click to toggle source
# File lib/ultrahook/client.rb, line 98
def process_error(payload)
  error payload["message"]
end
process_init(payload) click to toggle source
# File lib/ultrahook/client.rb, line 93
def process_init(payload)
  puts "Forwarding activated..."
  puts "https://#{@ultrahook_host} -> #{@options["destination"]}"
end
process_message(payload) click to toggle source
# File lib/ultrahook/client.rb, line 106
def process_message(payload)
  puts payload["message"]
end
process_ping(payload) click to toggle source
# File lib/ultrahook/client.rb, line 110
def process_ping(payload)
  # silent ack!
end
process_request(payload) click to toggle source
# File lib/ultrahook/client.rb, line 122
def process_request(payload)
  uri = URI("#{@options["destination"]}#{payload["path"]}?#{payload["query"]}")
  response = http_post(uri, payload["body"], payload["headers"])

  puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] POST #{uri.scheme}://#{uri.host}:#{uri.port}#{full_path(uri)} - #{response.code}"
end
process_warning(payload) click to toggle source
# File lib/ultrahook/client.rb, line 102
def process_warning(payload)
  puts "Warning: "+payload["message"]
end
retrieve_config() click to toggle source
# File lib/ultrahook/client.rb, line 138
def retrieve_config
  response = http_post(URI("https://www.ultrahook.com/init"), "key=#{@options["key"]}&host=#{@options["host"]}&version=#{UltraHook::VERSION}")

  error "Could not retrieve config from server: #{response.code}" if response.code.to_i != 200

  payload = JSON.parse(response.body)
  if payload["success"] == true
    @stream_url = payload["url"]
    @namespace = payload["namespace"]
    @ultrahook_host = payload["host"]

    puts "Authenticated as #{@namespace}"
  else
    error payload["error"]
  end
end
start(*args) click to toggle source
# File lib/ultrahook/client.rb, line 13
def start(*args)
  @options = {}

  optparse = OptionParser.new do |o|
    o.banner = "Usage: ultrahook [options] <subdomain> <destination>"

    o.on("-k", "--key <api key>", String, "API Key") do |key|
      @options["key"] = key
    end

    o.on_tail("-h", "--help", "Display this help") do
      puts o
      exit
    end

    o.on("-V", "--version", "Display client version") do
      puts "UltraHook client version: #{UltraHook::VERSION}"
      exit
    end
  end
  optparse.parse!(args)

  if @options["key"].nil? || @options["key"] == ""
    @options["key"] = ENV["ULTRAHOOK_API_KEY"]
  end

  if @options["key"].nil? || @options["key"] == ""
    path = File.expand_path("~/.ultrahook")
    if File.readable?(path)
      if matchdata = /api_key:\s*([^\s]+)/.match(IO.read(path))
        @options["key"] = matchdata.captures[0]
      end
    end
  end

  if @options["key"].nil? || @options["key"] == ""
    error "An API key must be provided.  Get one from http://www.ultrahook.com"
  end

  if args.size != 2
    puts optparse
    exit
  end

  @options["host"] = args[0].downcase
  error "Subdomain can only contain alphanumeric characters and hyphen (-)" unless @options["host"] =~ /^[[:alnum:]\-]+$/
  error "Subdomain cannot start or end with hyphens" if @options["host"] =~ /^\-/ || @options["host"] =~ /\-$/
  error "Subdomain cannot contain consecutive hyphens" if @options["host"] =~ /\-\-/

  @options["destination"] = parse_destination(args[1])

  retrieve_config
  init_stream
end