# frozen_string_literal: true module SoapyCake class Response include Helper SHORT_ELEMENT_DEPTH = 3 ELEMENTS_DEPTH = 5 attr_reader :body, :short_response, :time_converter def initialize(body, short_response, time_converter) @body = body @short_response = short_response @time_converter = time_converter end def to_enum check_errors! return typed_element(sax.at_depth(SHORT_ELEMENT_DEPTH).first) if short_response Enumerator.new do |y| sax.at_depth(ELEMENTS_DEPTH).each do |element| y << typed_element(element) end end end def to_xml check_errors! (empty? ? [] : [body.to_s]).to_enum end private def empty? sax.at_depth(ELEMENTS_DEPTH).first.nil? end def typed_element(element) walk_tree(element) do |value, key| ResponseValue.new(key, value, time_converter).parse end end def sax @sax ||= Saxerator.parser(StringIO.new(body)) do |config| config.symbolize_keys! config.ignore_namespaces! end end def check_errors! # If we get a lot of data in our response, we can assume there was no error. # This saves a lot of time because we don't have to scan the whole XML tree for errors. return if body.length > 8192 error_check_fault! return if error_check_special_case? error_check_success! end def error_check_fault! fault = sax.for_tag(:fault).first raise RequestFailed, fault[:reason][:text] if fault end def error_check_success! return if sax.for_tag(:success).first == 'true' raise RateLimitError if error_message == 'Restricted' raise RequestFailed, error_message end def error_check_special_case? # Don't ask... # As you might imagine, CAKE simply does not return the success element # for this specific request. Also, this is the only request with a tag depth # of 4, not 3 or 5 like ALL OTHER requests. # BTW: There is a 10$ reward if anyone can find a worse designed API. return true if sax.for_tag(:MediaType).count.positive? false end def error_message @error_message ||= sax.for_tag(:message).first || sax.for_tag(:Text).first || 'Unknown error' end end end