# Copyright (c) 2010-2011, Diaspora Inc. This file is # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. require 'typhoeus' require 'active_support/base64' class HydraWrapper OPTS = {:max_redirects => 3, :timeout => 25000, :method => :post, :headers => {'Expect' => '', 'Transfer-Encoding' => ''} } attr_reader :failed_people, :user, :encoded_object_xml attr_accessor :dispatcher_class, :people, :hydra def initialize(user, people, encoded_object_xml, dispatcher_class) @user = user @failed_people = [] @hydra = Typhoeus::Hydra.new @people = people @dispatcher_class = dispatcher_class @encoded_object_xml = encoded_object_xml end # Delegates run to the @hydra def run @hydra.run end # @return [Salmon] def salmon @salmon ||= @dispatcher_class.salmon(@user, Base64.decode64(@encoded_object_xml)) end # Group people on their receiving_urls # @return [Hash] People grouped by receive_url ([String] => [Array]) def grouped_people @people.group_by do |person| @dispatcher_class.receive_url_for(person) end end # Inserts jobs for all @people def enqueue_batch grouped_people.each do |receive_url, people_for_receive_url| if xml = salmon.xml_for(people_for_receive_url.first) self.insert_job(receive_url, xml, people_for_receive_url) end end end # Prepares and inserts job into the @hydra queue # @param url [String] # @param xml [String] # @params people [Array] def insert_job(url, xml, people) request = Typhoeus::Request.new(url, OPTS.merge(:params => {:xml => CGI::escape(xml)})) prepare_request!(request, people) @hydra.queue(request) end # @param request [Typhoeus::Request] # @param person [Person] def prepare_request!(request, people_for_receive_url) request.on_complete do |response| # Save the reference to the pod to the database if not already present Pod.find_or_create_by_url(response.effective_url) if redirecting_to_https?(response) Person.url_batch_update(people_for_receive_url, response.headers_hash['Location']) end unless response.success? Rails.logger.info("event=http_multi_fail sender_id=#{@user.id} url=#{response.effective_url} response_code='#{response.code}'") @failed_people += people_for_receive_url.map{|i| i.id} end end end # @return [Boolean] def redirecting_to_https?(response) if response.code >= 300 && response.code < 400 response.headers_hash['Location'] == response.request.url.sub('http://', 'https://') else false end end end