def deliver(message, device, stack = nil)
      message = Pling._convert(message, :message)
      device  = Pling._convert(device,  :device)

      stack ||= [] + configuration[:middlewares].initialize!

      return deliver!(message, device) if stack.empty?

      stack.shift.deliver(message, device) do |m, d|
        deliver(m, d, stack)
      end
    rescue Pling::Error => error
      callback = configuration[:on_exception]
      callback && callback.respond_to?(:call) ? callback.call(error) : raise
    end
def deliver(message, device, stack = nil)
      message = Pling._convert(message, :message)
      device  = Pling._convert(device,  :device)

      stack ||= [] + configuration[:middlewares].initialize!

      return deliver!(message, device) if stack.empty?

      stack.shift.deliver(message, device) do |m, d|
        deliver(m, d, stack)
      end
    rescue Pling::Error => error
      callback = configuration[:on_exception]
      callback && callback.respond_to?(:call) ? callback.call(error) : raise
    end
Delivers the given message to the given device using the given stack.
 If the :on_exception callback is configured it'll rescue all Pling::Errors
 and pass them to the given callback.

 @param message [#to_pling_message]
 @param device [#to_pling_device]
 @param stack [Array] The stack to use (Default: configuration[:middlewares])
 @raise [Pling::DeliveryError] unless configuration[:on_exception] callback is set