module Shodanz::API::Utils

Utils provides simply get, post, and slurp_stream functionality to the client. Under the hood they support both async and non-async usage. You should basically never need to use these methods directly.

@author Kent 'picat' Gruber

Constants

ACCESSDENIED
INVALIDKEY
NOINFO
NOQUERY
RATELIMIT

Public Instance Methods

get(path, **params) click to toggle source

Perform a direct GET HTTP request to the REST API.

# File lib/shodanz/apis/utils.rb, line 16
def get(path, **params)
  return sync_get(path, **params) unless Async::Task.current?

  async_get(path, **params)
end
post(path, body: nil, **params) click to toggle source

Perform a direct POST HTTP request to the REST API.

# File lib/shodanz/apis/utils.rb, line 23
def post(path, body: nil, **params)
  return sync_post(path, params: params, body: body) unless Async::Task.current?

  async_post(path, params: params, body: body)
end
slurp_stream(path, **params) { |result| ... } click to toggle source

Perform the main function of consuming the streaming API.

# File lib/shodanz/apis/utils.rb, line 30
def slurp_stream(path, **params)
  if Async::Task.current?
    async_slurp_stream(path, **params) do |result|
      yield result
    end
  else
    sync_slurp_stream(path, **params) do |result|
      yield result
    end
  end
end
turn_into_facets(**facets) click to toggle source
# File lib/shodanz/apis/utils.rb, line 50
def turn_into_facets(**facets)
  return {} if facets.nil?

  filters = facets.reject { |key, _| key == :facets }
  facets[:facets] = []
  filters.each do |key, value|
    facets[:facets] << "#{key}:#{value}"
  end
  facets[:facets] = facets[:facets].join(',')
  facets.select { |key, _| key == :facets }
end
turn_into_query(**params) click to toggle source
# File lib/shodanz/apis/utils.rb, line 42
def turn_into_query(**params)
  filters = params.reject { |key, _| key == :query }
  filters.each do |key, value|
    params[:query] << " #{key}:#{value}"
  end
  params.select { |key, _| key == :query }
end

Private Instance Methods

async_get(path, **params) click to toggle source
# File lib/shodanz/apis/utils.rb, line 164
def async_get(path, **params)
  Async::Task.current.async do
    getter(path, **params)
  end
end
async_post(path, params: nil, body: nil) click to toggle source
# File lib/shodanz/apis/utils.rb, line 176
def async_post(path, params: nil, body: nil)
  Async::Task.current.async do
    poster(path, params: params, body: body)
  end
end
async_slurp_stream(path, **params) { |data| ... } click to toggle source
# File lib/shodanz/apis/utils.rb, line 188
def async_slurp_stream(path, **params)
  Async::Task.current.async do
    slurper(path, **params) { |data| yield data }
  end
end
getter(path, **params) click to toggle source
# File lib/shodanz/apis/utils.rb, line 81
def getter(path, **params)
  # param keys should all be strings
  params = params.transform_keys(&:to_s)
  # build up url string based on special params
  url = "/#{path}?key=#{@key}"
  # special params
  params.each do |param,value|
    next if value.is_a?(String) && value.empty?
    value = URI.encode_www_form_component("#{value}")
    url += "&#{param}=#{value}"
  end

  resp = @client.get(url)

  if resp.success?
    # parse all lines in the response body as JSON
    json = JSON.parse(resp.body.join)

    handle_any_json_errors(json)

    return json
  else
    raise "Got response status #{resp.status}"
  end
ensure
  @client.pool.close
  resp&.close
end
handle_any_json_errors(json) click to toggle source
# File lib/shodanz/apis/utils.rb, line 70
def handle_any_json_errors(json)
  if json.is_a?(Hash) && json.key?('error')
    raise Shodanz::Errors::RateLimited if json['error'].casecmp(RATELIMIT) >= 0
    raise Shodanz::Errors::NoInformation if json['error'].casecmp(NOINFO) >= 0
    raise Shodanz::Errors::NoQuery if json['error'].casecmp(NOQUERY) >= 0
    raise Shodanz::Errors::AccessDenied if json['error'].casecmp(ACCESSDENIED) >= 0
    raise Shodanz::Errors::InvalidKey if json['error'].casecmp(INVALIDKEY) >= 0
  end
  return json
end
poster(path, one_shot: false, params: nil, body: nil) click to toggle source
# File lib/shodanz/apis/utils.rb, line 110
def poster(path, one_shot: false, params: nil, body: nil)
  # param keys should all be strings
  params = params.transform_keys(&:to_s)
  # and the key param is constant
  params["key"] = @key
  # encode as a URL string
  params = URI.encode_www_form(params)
  # optional JSON body string
  json_body = body.nil? ? nil : JSON.dump(body)
  # build URL path
  path = "/#{path}?#{params}" 

  # make POST request to server
  resp = @client.post(path, nil, json_body)

  if resp.success?
    json = JSON.parse(resp.body.join)

    handle_any_json_errors(json)

    return json
  else
    raise "Got response status #{resp.status}"
  end
ensure
  @client.pool.close
  resp&.close
end
slurper(path, **params) { |parse| ... } click to toggle source
# File lib/shodanz/apis/utils.rb, line 139
def slurper(path, **params)
  # param keys should all be strings
  params = params.transform_keys(&:to_s)
  # check if limit
  if (limit = params.delete('limit'))
    counter = 0
  end
  # make GET request to server
  resp = @client.get("/#{path}?key=#{@key}", params)
  # read body line-by-line
  until resp.body.nil? || resp.body.empty?
    resp.body.read.each_line do |line|
      next if line.strip.empty?

      yield JSON.parse(line)
      if limit
        counter += 1
        resp.close if counter == limit
      end
    end
  end
ensure
  resp&.close
end
sync_get(path, **params) click to toggle source
# File lib/shodanz/apis/utils.rb, line 170
def sync_get(path, **params)
  Async do
    getter(path, **params)
  end.wait
end
sync_post(path, params: nil, body: nil) click to toggle source
# File lib/shodanz/apis/utils.rb, line 182
def sync_post(path, params: nil, body: nil)
  Async do
    poster(path, params: params, body: body)
  end.wait
end
sync_slurp_stream(path, **params) { |data| ... } click to toggle source
# File lib/shodanz/apis/utils.rb, line 194
def sync_slurp_stream(path, **params)
  Async do
    slurper(path, **params) { |data| yield data }
  end.wait
end