|
|
require 'cgi'
require 'net/http'
require 'xmlsimple' # gem install xml-simple
require 'digest/md5'
# Hyves API client class.
# v0.1 (Joost Hietbrink, joost@yelloyello.com) MIT License
#
# Usage:
# h = Hyves.new(key, secret)
# h.authorize_token_url(:callback_url => 'http://localhost:3000/hyves/')
# # Now go to the url, login and get an requesttoken
# h.requesttoken = # requesttoken from the url
# h.auth_accesstoken # Sets the access token in h.accesstoken
# h.users_getLoggedin
# friend_uids = h.friends_get['uid'] # Gets the friends for logged-in user
# friends = h.users_get(:uid => friend_uids)
# pids = friends['user'].collect{|friend| friend['pid']}
# friend_avatars = h.photos_get(:pid => pids)
# h.friends_getDistance(:uid => 1)
#
# When you have errors, use h.debug = true to get some info.
class Hyves
class HyvesException < StandardError;end
attr_accessor :api_key, :shared_secret, :version, :host, :debug
# Set the requesttoken you got via the authorize_token_url
attr_accessor :requesttoken
attr_accessor :accesstoken # Hash with all accesstoken attributes: {"expiredate"=>"2007-12-11 10:57:56", "accesstoken"=>"OTA3X_74MOE1NkfqY6-CFRAqjhI=", "uid"=>"1019902"}
attr_reader :output
# Replace this API key & secret with your own
def initialize(api_key='your key here', shared_secret='and a secret here')
@api_key = api_key
@shared_secret = shared_secret
@host = 'http://hyves-api.nl'
@version = '2007.9.4'
@output = 'xml' # 'json'
@debug = false
end
# def request(method, *params)
def request(url)
response = XmlSimple.xml_in(http_get(url), { 'ForceArray' => false })
log "url: #{url}"
log response.inspect
raise HyvesException, "#{response['error_message']} (errorcode: #{response['error_code']})" if response['error_code']
response
end
# Does an HTTP GET on a given URL and returns the response body
def http_get(url)
Net::HTTP.get_response(URI.parse(url)).body.to_s
end
def api_call(options = {})
time = Time.now.to_i # FIXME: Should this be Time.now.utc?
params_hash = {:format => output, :v => version, :api_key => api_key, :ts => time}
params_hash[:accesstoken] = accesstoken['accesstoken'] unless accesstoken.blank? # Add accesstoken if we have one!
params_hash.merge!(options) # Overwrite the defaults with special options
params_hash.stringify_keys!
# NOTE: sorting is needed to generate unique (same) sig as server
# NOTE: oauth signature is based on "param1=a¶m2=b", Hyves signature expects "param1=aparam2=b"
md5_params = to_url_params(params_hash, :seperator => '', :sort => true, :encode => false)
url_params = to_url_params(params_hash)
signature = Digest::MD5.hexdigest(md5_params+shared_secret)
url = "http://hyves-api.nl/?#{url_params}&sig=#{signature}"
return request(url)
end
# For Desktop apps. Webapps should use the authorize_token_url to get this!
# Returns the latest requesttoken OR gets a new one using the Desktop method.
def auth_requesttoken
requesttoken || @requesttoken = self.api_call(:method => 'auth.requesttoken')['requesttoken']
end
# Returns the latest accesstoken OR retreivces new one using the most recent requesttoken.
def auth_accesstoken
accesstoken || @accesstoken = self.api_call(:method => 'auth.accesstoken', :requesttoken => self.auth_requesttoken)
end
# options:
# callback_url = http://www.example.com/callback/
# seperator = '?'
# infinite = 'false'
def authorize_token_url(options = {})
raise ArgumentError, 'Please supply a callback_url!' if options[:callback_url].blank?
url_params = to_url_params(options)
url = "http://www.hyves.nl/authorizeToken/?api_key=#{api_key}"
url += "{url_params}" unless url_params.blank?
end
private
# This method defines all api calls
def method_missing(meth, *args)
hyves_method = meth.to_s.gsub('_', '.')
options = {:method => hyves_method}
options.merge!(args.first) if args.first.is_a?(Hash)
api_call(options)
end
def to_url_params(hash, options={})
options.reverse_merge!({:seperator => '&', :sort => false, :encode => true}) # Default options
keys = (options[:sort] ? hash.keys.sort : hash.keys) # Sort the hash (needed for md5)
keys.collect do |key|
value = hash[key]
value = value.join(',') if value.is_a?(Array)
param = "#{key}=#{value}"
options[:escape] ? URI.escape(param) : param # return escaped / non-escaped param to collect array
end.join(options[:seperator])
end
def log(msg)
puts msg if @debug
end
end
|