require "social_avatar_proxy/facebook_avatar" require "social_avatar_proxy/twitter_avatar" require "social_avatar_proxy/routes" require "rack" module SocialAvatarProxy class App def self.call(env, options = {}) new(options).call(env) end def self.routes(options = {}) new(options).routes end attr_reader :options, :request def initialize(options = {}) @options = { expires: 86400, # 1 day from now cache_control: { max_age: 86400, # store for 1 day, after that re-request max_stale: 86400, # allow cache to be a day stale public: true # allow proxy caching } }.merge(options) end def call(env) @request = Rack::Request.new(env) # return the response response.finish end def path_prefix (options[:path_prefix] || (request && request.env["SCRIPT_NAME"]) || "").gsub(/\/$/, "") end def response # ensure this is a valid avatar request unless request.path =~ /^#{path_prefix}\/(facebook|twitter)\/([\w\-\.]+)(\.(jpe?g|png|gif|bmp))?$/i return not_found end # load the avatar avatar = load_avatar($1, $2) # if it exists if avatar.exist? # render the avatar to the response Rack::Response.new do |response| # set the last modified header response["Last-Modified"] = avatar.last_modified # set the content type header response["Content-Type"] = avatar.content_type # if we want to expire in a set time, calculate the header if options[:expires] response["Expires"] = (Time.now + options[:expires]).httpdate end # if we want to set cache control settings if cc = options[:cache_control] directives = [] directives << "no-cache" if cc[:no_cache] directives << "max-stale=#{cc[:max_stale]}" if cc[:max_stale] directives << "max-age=#{cc[:max_age]}" if cc[:max_age] directives << (cc[:public] ? "public" : "private") response["Cache-Control"] = directives.join("; ") end # set the data response.write(avatar.body) end # if the avatar doesn't exist else not_found end end def not_found Rack::Response.new("Not Found", 404) end def routes Routes.new(self) end private def load_avatar(service, id) # titleize the service name service = service.gsub(/[\_\-]/, " ").gsub(/\b([a-z])/) do |match| match.upcase end # pass it onto the SocialAvatarProxy.const_get("#{service}Avatar").new(id) end end end