class ContentService DEFAULT_PROTOCOL = 'https'.freeze SOCKET_ERRORS = [EOFError, IOError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE, Errno::EINVAL].freeze def self.query(path, payload) retry_once_on_socket_error do ConnectionManager.ensure_started(uri) request = build_request(path, payload) response = ConnectionManager.connection.request(request) MultiJson.load(response.body) end end class << self private def retry_once_on_socket_error retried = false begin yield rescue *SOCKET_ERRORS raise if retried ConnectionManager.ensure_finished retried = true retry end end def build_request(path, payload) request = Net::HTTP::Post.new("#{uri.path}/#{path}".squeeze('/'), request_headers) request.basic_auth(config['login'], config['api_key']) request.body = MultiJson.dump(payload) request end def uri url = config['url'] url = "#{DEFAULT_PROTOCOL}://#{url}" unless url.match /^http/ URI.parse(url) end def request_headers headers = { 'Content-Type' => 'application/json', 'Accept' => 'application/json', 'User-Agent' => user_agent, } if http_host = config['http_host'] headers['Host'] = http_host end headers end def config RailsConnector::Configuration.content_service end def user_agent @user_agent ||= ( gem_info = Gem.loaded_specs["infopark_cloud_connector"] "#{gem_info.name}-#{gem_info.version}" ) end end module ConnectionManager def self.connection @connection end def self.connection=(conn) @connection = conn end def self.ensure_started(uri) return if @connection && @connection.started? conn = Net::HTTP.new(uri.host, uri.port) if uri.scheme == 'https' conn.use_ssl = true conn.verify_mode = OpenSSL::SSL::VERIFY_PEER end retry_twice_on_socket_error { conn.start } @connection = conn end def self.ensure_finished @connection.finish if @connection && @connection.started? @connection = nil end class << self private def retry_twice_on_socket_error attempt = 0 begin yield rescue *ContentService::SOCKET_ERRORS raise if attempt == 2 attempt += 1 retry end end end end end