lib/thumbs.rb in thumbs-0.0.9 vs lib/thumbs.rb in thumbs-1.0.0.beta.1

- old
+ new

@@ -1,74 +1,133 @@ require "rubygems" -require "rack" -require "rack/contrib" +require "bundler/setup" -module Thumbs - autoload :Server, 'thumbs/server' - autoload :Image, 'thumbs/image' - autoload :NotFound, 'thumbs/middleware/not_found' - autoload :ServerName, 'thumbs/middleware/server_name' - autoload :CacheControl, 'thumbs/middleware/cache_control' - autoload :Download, 'thumbs/middleware/download' - autoload :Resize, 'thumbs/middleware/resize' - autoload :Config, 'thumbs/middleware/config' - autoload :CacheWrite, 'thumbs/middleware/cache_write' - autoload :CacheRead, 'thumbs/middleware/cache_read' - autoload :Logger, 'thumbs/middleware/logger' - autoload :ContentType, 'thumbs/middleware/content_type' +require 'goliath' +require 'em-http' +require 'em-synchrony/em-http' +require 'digest/sha1' +require "em-files" +require 'rack/mime' +require 'lumberjack' + +require File.join(File.dirname(__FILE__), '/thumbs/evented_magick') +require File.join(File.dirname(__FILE__), '/thumbs/image') +require File.join(File.dirname(__FILE__), '/thumbs/middleware/content_type') + +class Thumbs < Goliath::API - def self.new(args) - options = { - :thumbs_folder => false, - :etag => true, - :cache => true, - :cache_original => true, - :cache_control => { - :ttl => 86400, - :last_modified => true - }, - :server_name => "Thumbs/0.0.6", - :url_map => "/:size/:original_url", - :image_not_found => File.join(File.dirname(__FILE__), "thumbs", "images", "image_not_found.jpg"), - :runtime => false, - :logfile => false - }.merge!(args) - - Rack::Builder.new do - - use Rack::Runtime if options[:runtime] - - use Rack::Config do |env| - env['thumbs.thumbs_folder'] = options[:thumbs_folder] - end - - use Rack::ShowExceptions + use ::Rack::Runtime - use Thumbs::Config, options[:url_map] - - use Thumbs::Logger, options[:logfile] if options[:logfile] + use Goliath::Rack::Heartbeat # respond to /status with 200, OK (monitoring, etc) + use ContentType - use Thumbs::ServerName, options[:server_name] if options[:server_name] - use Thumbs::CacheControl, options[:cache_control] if options[:cache_control] - use Rack::ETag if options[:etag] + def initialize + @logger = Lumberjack::Logger.new("logs/thumbs.log", :time_format => "%Y-%m-%d %H:%M:%S", :roll => :daily, :flush_seconds => 5) + end - use Thumbs::ContentType - - if options[:cache] && options[:thumbs_folder] && File.exist?(File.expand_path(options[:thumbs_folder])) - use Thumbs::CacheRead, "resized" - use Thumbs::CacheWrite, "resized" + def response(env) + start_time = Time.now.to_f + log_message = [] + url_pattern, keys = compile(env.url_map) + status, headers, boady = [-1, {}, ""] + + if match = url_pattern.match(env['PATH_INFO']) + values = match.captures.to_a + params = keys.zip(values).inject({}) do |hash,(k,v)| + hash[k.to_sym] = v + hash end - - use Thumbs::Resize + image = Image.new(params.merge(:thumbs_folder => env.thumbs_folder)) + log_message << image.url + log_message << image.size + else + log_message << "invalid_url" + return not_found + end - use Thumbs::CacheWrite, "original" if options[:cache_original] && options[:thumbs_folder] && File.exist?(File.expand_path(options[:thumbs_folder])) + #cache_resized_read + if env.cache + begin + status, body = 200, File.read(image.resized_path) + log_message << "resized_cache" + write_log log_message, start_time + return [status, headers, body] + rescue Errno::ENOENT, IOError => e + end + end - use Thumbs::NotFound, options[:image_not_found] if options[:image_not_found] && File.exist?(File.expand_path(options[:image_not_found])) + #cache_original_read + if env.cache_original + begin + status, body = 200, File.read(image.original_path) + log_message << "original_cache" + rescue Errno::ENOENT, IOError => e + end + end - use Thumbs::CacheRead, "original" if options[:cache_original] - use Thumbs::Download + if status < 200 + #download + log_message << "download" + original_response = EM::HttpRequest.new(image.remote_url).get :connection_timeout => 5, :inactivity_timeout => 10, :redirects => 0 + status = original_response.response_header.status + if status >= 200 && status < 300 + status, body = 200, original_response.response + #cache_original_write + if cache_original + path = image.original_path + tries = 0 + begin + EM::File.open(path, "wb") {|f| f.write(body) } + rescue Errno::ENOENT, IOError + Dir.mkdir(File.dirname(path), 0755) + retry if (tries += 1) == 1 + end + end + else + status, heders, body = not_found + end - run Thumbs::Server.new end + + #resize + if status > 0 + thumb = EventedMagick::Image.from_blob(body) + thumb.resize image.size + body = thumb.to_blob + end + + #cache_resized_write + if env.cache && status >= 200 && status < 300 + path = image.resized_path + tries = 0 + begin + EM::File.open(path, "wb") {|f| f.write(body) } + rescue Errno::ENOENT, IOError + Dir.mkdir(File.dirname(path), 0755) + retry if (tries += 1) == 1 + end + end + write_log log_message, start_time + [status, headers, body] end - + + private + + def compile(url_map) + keys = [] + pattern = url_map.gsub(/((:\w+))/) do |match| + keys << $2[1..-1] + "(.+?)" + end + [/^#{pattern}$/, keys] + end + + def not_found + [404, {}, File.read(File.expand_path("thumbs/images/image_not_found.jpg", __FILE__))] + end + + def write_log(message, start_time) + message << "#{((Time.now.to_f - start_time)*1000).round}ms" + @logger.info message.join("\t") + end + end