lib/cachai.rb in cachai-0.0.5 vs lib/cachai.rb in cachai-0.0.7

- old
+ new

@@ -1,9 +1,9 @@ require 'sinatra/base' +require 'sendgrid-ruby' require 'redis' require 'json' -require 'rake' require_relative 'models' require_relative 'akismet' module Cachai @@ -17,25 +17,32 @@ # use Rack::CommonLogger, LOGGER # use Rack::Static, :urls => %w(/css /img /js /favicon.ico), :root => 'public' use ActiveRecord::ConnectionAdapters::ConnectionManagement + CACHE_MINUTES = 10 * 60 # 10 minutes + def initialize(app, opts = nil) opts = opts || {} - @domain = opts.delete(:domain) or raise 'Domain required.' + domain = opts.delete(:domain) or raise 'Domain required.' + redis_host = opts.delete(:redis_host) || 'localhost' + Cachai.domain = domain + Cachai.cache = Redis.new(:host => redis_host) Cachai.load_db! - redis_host = opts.delete(:redis_host) || 'localhost' - @redis = Redis.new(:host => redis_host) - if key = opts.delete(:akismet_key) - @akismet = Akismet.new(:api_key => key, :blog => "http://#{@domain}") + @akismet = Akismet.new(:api_key => key, :blog => "http://#{domain}") else puts "No Akismet key found! Will not check comments for spam." end + if sendgrid_opts = opts.delete(:sendgrid) + @sendgrid = SendGrid::Client.new(sendgrid_opts) + @recipient = opts.delete(:recipient) or raise "No recipient set!" + end + super(app) end get '/pingbacks.?:format?' do # TODO @@ -46,70 +53,76 @@ end get '/comments.?:format?' do check_domain!(params[:domain]) - @redis.del(redis_key(params[:path])) if params[:nocache] - # puts "Comments for: #{params[:domain]}#{params[:path]}" - json_list = get_comments(params[:path]) + json_list = get_comments(params[:path], params[:nocache]) if params[:callback] content_type 'application/javascript' "#{params[:callback]}(#{json_list});" else - json(list) + json(json_list) end end post '/comments.?:format?' do begin data = JSON.parse(request.body.read) check_domain!(data['domain']) - headers['Access-Control-Allow-Origin'] = data['protocol'] + '//' + data['domain'] + halt(400, "Missing params") if data['protocol'].blank? or data['path'].blank? + headers['Access-Control-Allow-Origin'] = data['protocol'] + '//' + data['domain'] permalink = 'http://' + data['domain'] + data['path'] halt(400, "No spam allowed") if is_spam?(data, permalink, request) attrs = { :content => data['content'], :author_name => data['author_name'], :author_email => data['author_email'], :author_url => data['author_url'], - :parent_id => data['parent_id'], + :parent_id => data['parent_id'].to_i, :author_ip => request.ip } post = Post.find_or_create_by_path(data['path']) response = Response.create!(attrs.merge(:post_id => post.id)) + Cachai.clear_cache(data['path']) + notify_new_response(response, data['path']) - @redis.del(redis_key(data['path'])) json({ :status => 'ok', :comment => response }) rescue JSON::ParserError status 400 and json({ :error => 'Invalid JSON.' }) rescue ActiveRecord::RecordInvalid => e status 422 and json({ :error => e.message }) + rescue => e + puts e.message + puts e.backtrace.join("\n") + status 500 and "Something went wrong." end end private +=begin def set_cache(timestamp) return if timestamp.nil? last_modified timestamp cache_control :public, :must_revalidate, :max_age => 60 end def prevent_cache cache_control :public, :no_cache, :no_store, :must_revalidate, :max_age => 0 # expires 1.year.ago end +=end def check_domain!(domain) - halt(400, 'Invalid domain.') unless domain == @domain + halt(400, 'Invalid domain.') unless domain == Cachai.domain end def not_found(message = nil) halt(404, message || 'Not found.') end @@ -117,24 +130,26 @@ def json(obj) content_type 'application/json' return obj.is_a?(String) ? obj : obj.to_json end - def get_comments(path) - key = redis_key(path) - unless json_list = @redis.get(key) + def get_comments(path, nocache = false) + key = Cachai.key_for(path) + + unless !nocache && json_list = Cachai.cache.get(key) puts "Not cached. Getting from DB: #{path}" if post = Post.find_by_path(path) json_list = get_and_sort_comments_for(post).to_json else json_list = '[]' end - @redis.set(key, json_list) - @redis.expire(key, 60 * 60) # one hour + Cachai.cache.set(key, json_list) + Cachai.cache.expire(key, CACHE_MINUTES) end + json_list end def get_and_sort_comments_for(post) result = [] @@ -151,35 +166,45 @@ end result end - def redis_key(path) - "comments:#{@domain}:#{path}" - end - def is_spam?(data, link, request) return false unless @akismet # return true if blacklisted?(name, email, content) comment = { - :user_ip => request.ip, - :referrer => request.referrer, - :user_agent => request.user_agent, - :permalink => link, - :comment_type => 'comment', - :comment_content => data['content'], - :comment_author => data['author_name'], + :user_ip => request.ip, + :referrer => request.referrer, + :user_agent => request.user_agent, + :permalink => link, + :comment_type => 'comment', + :comment_content => data['content'], + :comment_author => data['author_name'], :comment_author_url => data['author_url'], :comment_author_email => data['author_email'] } if resp = @akismet.check_comment(comment) # puts resp.inspect return resp[:spam] end false + end + + def notify_new_response(response, path) + mail = SendGrid::Mail.new do |m| + m.to = @recipient + m.from = 'comments@' + Cachai.domain + m.reply_to = response.author_email + m.subject = "New comment from #{response.author_name} at #{path}" + m.text = "#{response.content}\n\n--\nhttp://#{Cachai.domain}/#{path}" + end + + puts @sendgrid.send(mail) + rescue SendGrid::Exception => e + puts e.inspect end end end