hgmnz/keikokuc

View on GitHub
lib/keikokuc/client.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'rest-client'
require 'keikokuc/okjson'
require 'timeout'

# Internal: Handles HTTP requests/responses to the keikoku API
#
# This class is meant to be used internally by Keikokuc
class Keikokuc::Client
  include HandlesTimeout

  InvalidNotification = Class.new
  Unauthorized = Class.new

  attr_accessor :username, :api_key

  # Internal: Initialize a Client
  #
  # opts = a hash containing two possible attributes:
  #   api_key - the user's or producer's API key (required)
  #   username - the producer's username (only required for publishers)
  def initialize(opts = {})
    @api_key  = opts.fetch(:api_key)
    @username = opts[:username]
  end

  # Internal: posts a new notification to keikoku
  #
  # attributes - a hash containing notification attributes
  #
  # Examples
  #
  #   client = Keikokuc::Client.new(username: 'heroku-postgres',
  #                                  api_key: 'abcd')
  #   response, error = client.post_notification(message: 'hello')
  #
  # Returns
  #
  # two objects:
  #   The response as a hash
  #   The error if any (nil if no error)
  #
  # Possible errors include:
  #
  # * `Client::Timeout` if the request takes longer than 5 seconds
  # * `Client::InvalidNotification` if the response indicates
  #   invalid notification attributes
  # * `Client::Unauthorized` if API key auth fails
  def post_notification(attributes)
    begin
      response = notifications_api.post(encode_json(attributes))
      [parse_json(response), nil]
    rescue RestClient::UnprocessableEntity => e
      [parse_json(e.response), InvalidNotification]
    rescue RestClient::Unauthorized
      [{}, Unauthorized]
    end
  end
  handle_timeout :post_notification

  # Internal: gets all active notifications for a user
  #
  # Examples
  #
  #   client = Keikokuc::Client.new(api_key: 'api-key')
  #   response, error = client.get_notifications
  #
  # Returns
  #
  # two objects:
  #   The response as a hash
  #   The error if any (nil if no error)
  #
  # Possible errors include:
  #
  # * `Client::Timeout` if the request takes longer than 5 seconds
  # * `Client::Unauthorized` if HTTP Basic auth fails
  def get_notifications
    begin
      response = notifications_api.get
      [parse_json(response), nil]
    rescue RestClient::Unauthorized
      [{}, Unauthorized]
    end
  end
  handle_timeout :get_notifications

  # Public: Marks a notification as read
  #
  # remote_id - the keikoku id for the notification to mark as read
  #
  # Returns
  #
  # two objects:
  #   The response as a hash
  #   The error if any (nil if no error)
  #
  # Possible errors include:
  #
  # * `Client::Timeout` if the request takes longer than 5 seconds
  # * `Client::Unauthorized` if HTTP Basic auth fails
  def read_notification(remote_id)
    begin
      response = notifications_api["/#{remote_id}/read"].post ''
      parsed_response = parse_json(response)
      [parsed_response, nil]
    rescue RestClient::Unauthorized
      [{}, Unauthorized]
    end
  end
  handle_timeout :read_notification

private
  def notifications_api # :nodoc:
    @notifications_api ||= RestClient::Resource.new(
      api_url,
      :user     => username || '',
      :password => api_key
    )
  end

  def api_url # :nodoc:
    "https://keikoku.herokuapp.com/api/v1/notifications"
  end

  def encode_json(hash) # :nodoc:
    Keikokuc::OkJson.encode(stringify_hash_keys(hash))
  end

  def parse_json(data) # :nodoc:
    symbolize_keys(Keikokuc::OkJson.decode(data)) if data
  end

  def symbolize_keys(object) # :nodoc:
    case object
    when Hash
      symbolize_hash_keys(object)
    when Array
      object.map { |item| symbolize_hash_keys(item) }
    end
  end

  def symbolize_hash_keys(hash)
    hash.inject({}) do |result, (k, v)|
      result[k.to_sym] = v
      result
    end
  end

  def stringify_hash_keys(hash)
    hash.inject({}) do |result, (k, v)|
      result[k.to_s] = v
      result
    end
  end
end