require "timeout"
require "net/http"
require "uri"
# A simple client for the Oso URL shortener.
class Oso
include Timeout
# Raised for any error.
Error = Class.new StandardError
# Duh.
VERSION = "2.0.0"
# :nodoc:
def self.instance
@instance ||= new
end
# A static helper if you don't want to create new instances of the
# Oso class. Set the OSO_URL environment variable to
# control the server location. See +initialize+ for more
# information.
def self.shorten *args
instance.shorten(*args)
end
# See #shorten! for more information.
def self.shorten! *args
instance.shorten!(*args)
end
# A URI. Where does the Oso server live? If unspecified during
# initialization it'll default to the contents of the
# OSO_URL environment variable. If that's unset, it's
# "http://localhost:9292".
attr_reader :url
# Create a new instance, optionally specifying the server +url+. See
# the +url+ property for defaults and fallbacks.
def initialize url = nil
url = url || ENV["OSO_URL"] || "http://localhost:9292"
url = "http://#{url}" unless /^http/ =~ url
@url = URI.parse url
@url.path = "/" if @url.path.empty?
end
# Create a short URL for +url+. Pass a :life option
# (integer, in seconds) to control how long the short URL will be
# active. Pass a :limit option to control how many times
# the URL can be hit before it's deactivated. Pass a :name
# option to explicitly set the shortened URL.
#
# +shorten!+ will raise an Oso::Error if network or server
# conditions keep +url+ from being shortened in one second.
def shorten! url, options = {}
params = options.merge :url => url
params[:life] &&= params[:life].to_i
params[:limit] &&= params[:limit].to_i
timeout 1, Oso::Error do
begin
res = Net::HTTP.post_form @url, params
rescue Errno::ECONNREFUSED
raise Oso::Error, "Connection to #@url refused."
rescue Timeout::Error
raise Oso::Error, "Connection to #@url timed out."
rescue Errno::EINVAL, Errno::ECONNRESET, EOFError => e
raise Oso::Error, "Connection to #@url failed. (#{e.class.name})"
rescue Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError => e
raise Oso::Error, "#@url provided a bad response. (#{e.class.name})"
end
case res.code.to_i
when 201 then return res.body
else raise Oso::Error, "Unsuccessful shorten #{res.code}: #{res.body}"
end
end
end
# Create a short URL like #shorten!, but return the original URL if
# an error is raised.
def shorten url, options = {}
shorten! url, options rescue url
end
end