class Smess::Ipx

Attributes

account_name[RW]
password[RW]
results[RW]
service_meta_data_t_mobile_us[RW]
service_meta_data_verizon[RW]
service_name[RW]
shortcode[RW]
sms[R]
sms_url[RW]
username[RW]

Public Instance Methods

deliver() click to toggle source
# File lib/smess/outputs/ipx.rb, line 24
def deliver
  set_originator(sms.originator)
  perform_operator_adaptation(sms.to)

  parts.each_with_index do |part, i|
    populate_soap_body(part, i)
    results << send_one_sms

    # halt and use fallback on error...
    if last_result_was_error
      logger.info "IPX_ERROR: #{results.last}"
      return fallback_to_twilio || results.first
    end
  end

  # we don't actually return the status for any of additional messages which is cheating
  results.first
end
validate_config() click to toggle source
# File lib/smess/outputs/ipx.rb, line 6
def validate_config
  @sms_url                       = config.fetch(:sms_url)
  @username                      = config.fetch(:username)
  @password                      = config.fetch(:password)
  @shortcode                     = config.fetch(:shortcode)
  @account_name                  = config.fetch(:account_name)
  @service_name                  = config.fetch(:service_name)
  @service_meta_data_verizon     = config.fetch(:service_meta_data_verizon, "")
  @service_meta_data_t_mobile_us = config.fetch(:service_meta_data_t_mobile_us, "")

  @results = []
  @endpoint = sms_url
  @credentials = {
    name: username,
    pass: password
  }
end

Private Instance Methods

concatenation_udh(num, total) click to toggle source

{050003}{ff}{02}{01} {concat-command}{id to link all parts}{total num parts}{num of current part}

# File lib/smess/outputs/ipx.rb, line 134
def concatenation_udh(num, total)
  "050003#{ref_id}#{total.to_s(16).rjust(2,'0')}#{(num).to_s(16).rjust(2,'0')}"
end
fallback_to_twilio() click to toggle source

Delivery reliability, particularly in the US, is appalling and being able to reduce non-deliveries by more than half is a big deal when sending transactional messages.

# File lib/smess/outputs/ipx.rb, line 99
def fallback_to_twilio
  sms.output = :twilio
  sms.deliver
end
get_message_id_from(hash) click to toggle source
# File lib/smess/outputs/ipx.rb, line 108
def get_message_id_from hash
  hash[:message_id] rescue ''
end
get_response_hash_from(response) click to toggle source
# File lib/smess/outputs/ipx.rb, line 104
def get_response_hash_from(response)
  response.to_hash[:submit_rsp]
end
last_result_was_error() click to toggle source
# File lib/smess/outputs/ipx.rb, line 164
def last_result_was_error
  results.last.fetch(:response_code, '').to_s != "0"
end
normal_result(response) click to toggle source
# File lib/smess/outputs/ipx.rb, line 190
def normal_result(response)
  hash = response.to_hash[:send_response]
  message_id = ""
  message_id = hash[:message_id] if hash.has_key? :message_id
  response_code = hash[:response_code]

  {
    message_id: message_id,
    response_code: response_code,
    response: hash,
    destination_address: sms.to,
    data: result_data
  }
end
parse_sms_response(response) click to toggle source
# File lib/smess/outputs/ipx.rb, line 168
def parse_sms_response(response)
  if response.http_error? || response.soap_fault?
    e = Struct.new(:code, :message).new("-1", response.http_error || response.soap_fault.to_hash)
    result = result_for_error(e)
  else
    result = normal_result(response)
  end
  result
end
parts() click to toggle source
# File lib/smess/outputs/ipx.rb, line 125
def parts
  @parts ||= split_parts
end
perform_operator_adaptation(msisdn) click to toggle source

Called before final message assembly used to look up the operator and make changes to the SOAP data for some carriers

# File lib/smess/outputs/ipx.rb, line 215
def perform_operator_adaptation(msisdn)
end
populate_soap_body(part, i) click to toggle source
# File lib/smess/outputs/ipx.rb, line 142
def populate_soap_body(part, i)
  # if we have several parts, send them as concatenated sms using UDH codes
  soap_body["userDataHeader"] = concatenation_udh(i+1, parts.length) if parts.length > 1
  soap_body["userData"] = part
  soap_body["correlationId"] = Time.now.strftime('%Y%m%d%H%M%S') + sms.to + (i+1).to_s
end
ref_id() click to toggle source
# File lib/smess/outputs/ipx.rb, line 138
def ref_id
  @ref_id ||= Random.new.rand(255).to_s(16).rjust(2,"0")
end
result_data() click to toggle source
# File lib/smess/outputs/ipx.rb, line 205
def result_data
  data = soap_body.dup
  data.delete "password"
  data["userData"] = sms.message.strip_nongsm_chars
  data
end
result_for_error(e) click to toggle source
# File lib/smess/outputs/ipx.rb, line 178
def result_for_error(e)
  {
    response_code: '-1',
    response: {
      temporaryError: 'true',
      responseCode: '-1',
      responseText: e.message
    },
    data: result_data
  }
end
send_one_sms() click to toggle source
# File lib/smess/outputs/ipx.rb, line 149
def send_one_sms
  client = soap_client
  soap_body_var = soap_body
  begin
    response = client.request "SendRequest", "xmlns" => xmlns do
      soap.body = soap_body_var
    end
    result = parse_sms_response(response)
  rescue => e
    result = result_for_error(e)
    # LOG error here?
  end
  result
end
set_originator(originator) click to toggle source
# File lib/smess/outputs/ipx.rb, line 112
def set_originator(originator)
  soap_body["originatingAddress"] = originator
  soap_body["originatorTON"] = (originator.length == 5 && originator.to_i.to_s == originator) ? "0" : "1"
end
soap_body() click to toggle source
# File lib/smess/outputs/ipx.rb, line 48
def soap_body
  @soap_body ||= {
    "correlationId" => Time.now.strftime('%Y%m%d%H%M%S') + sms.to,
    "originatingAddress" => shortcode,
    "originatorTON" => "0",
    "destinationAddress" => sms.to,
    "userData" => "",
    "userDataHeader" => "#NULL#",
    "DCS" => "-1",
    "PID" => "-1",
    "relativeValidityTime" => "-1",
    "deliveryTime" => "#NULL#",
    "statusReportFlags" => "1", # 1
    "accountName" => account_name,
    "tariffClass" => "USD0", # needs to be extracted and variable per country
    "VAT" => "-1",
    "referenceId" => "#NULL#",
    "serviceName" =>  service_name,
    "serviceCategory" => "#NULL#",
    "serviceMetaData" => "#NULL#",
    "campaignName" => "#NULL#",
    "username" => username,
    "password" => password
  }
end
soap_client() click to toggle source
# File lib/smess/outputs/ipx.rb, line 75
def soap_client
  Savon.configure do |config|
    config.log_level = :info
    config.raise_errors = false
  end

  endpoint = @endpoint
  mm7ns = wsdl_namespace
  credentials = @credentials

  client = Savon::Client.new do |wsdl, http|
    wsdl.endpoint = endpoint
    wsdl.namespace = mm7ns

    http.open_timeout = 15
    http.read_timeout = 60 # Won't set read timeout to 10 minutes!! (IPX are crazy)
    http.auth.basic  credentials[:name], credentials[:pass] unless credentials.nil?
  end
  client
end
split_parts() click to toggle source
# File lib/smess/outputs/ipx.rb, line 129
def split_parts
  Smess.split_sms(sms.message.strip_nongsm_chars).reject {|s| s.empty? }
end
wsdl_namespace() click to toggle source
# File lib/smess/outputs/ipx.rb, line 121
def wsdl_namespace
  "http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-2"
end
xmlns() click to toggle source
# File lib/smess/outputs/ipx.rb, line 117
def xmlns
  "http://www.ipx.com/api/services/smsapi52/types"
end