Class: Smpp::Transceiver
- Defined in:
- lib/smpp/transceiver.rb
Overview
The SMPP Transceiver maintains a bidirectional connection to an SMSC. Provide a config hash with connection options to get started. See the sample_gateway.rb for examples of config values. The transceiver accepts a delegate object that may implement the following (all optional) methods:
mo_received(transceiver, source_addr, destination_addr, )
delivery_report_received(transceiver, msg_reference, stat, pdu)
(transceiver, , )
bound(transceiver)
unbound(transceiver)
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
-
#initialize(config, delegate, pdr_storage = {}) ⇒ Transceiver
constructor
A new instance of Transceiver.
-
#process_pdu(pdu) ⇒ Object
a PDU is received.
-
#send_bind ⇒ Object
Send BindTransceiverResponse PDU.
-
#send_concat_mt(message_id, source_addr, destination_addr, message, options = {}) ⇒ Object
Send a concatenated message with a body of > 160 characters as multiple messages.
-
#send_mt(message_id, source_addr, destination_addr, short_message, options = {}) ⇒ Object
Send an MT SMS message.
-
#send_multi_mt(message_id, source_addr, destination_addr_arr, short_message, options = {}) ⇒ Object
Send MT SMS message for multiple dest_address Author: Abhishek Parolkar (abhishekparolkar.com) USAGE: $tx.send_multi_mt(123, “9100000000”, [“9199000000000”,“91990000000001”,“9199000000002”], “Message here”).
Methods inherited from Base
#bound?, logger, #logger, logger=, #post_init, #receive_data, #send_unbind, #start_enquire_link_timer, #unbind, #unbound?
Constructor Details
#initialize(config, delegate, pdr_storage = {}) ⇒ Transceiver
Returns a new instance of Transceiver.
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/smpp/transceiver.rb', line 16 def initialize(config, delegate, pdr_storage={}) super(config) @delegate = delegate @pdr_storage = pdr_storage # Array of un-acked MT message IDs indexed by sequence number. # As soon as we receive SubmitSmResponse we will use this to find the # associated message ID, and then create a pending delivery report. @ack_ids = Array.new(512) ed = @config[:enquire_link_delay_secs] || 5 comm_inactivity_timeout = 2 * ed rescue Exception => ex logger.error "Exception setting up transceiver: #{ex} at #{ex.backtrace.join("\n")}" raise end |
Instance Method Details
#process_pdu(pdu) ⇒ Object
a PDU is received. Parse it and invoke delegate methods.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/smpp/transceiver.rb', line 101 def process_pdu(pdu) case pdu when Pdu::DeliverSm write_pdu(Pdu::DeliverSmResponse.new(pdu.sequence_number)) logger.debug "ESM CLASS #{pdu.esm_class}" if pdu.esm_class != 4 # MO message if @delegate.respond_to?(:mo_received) @delegate.mo_received(self, pdu.source_addr, pdu.destination_addr, pdu.) end else # Delivery report if @delegate.respond_to?(:delivery_report_received) @delegate.delivery_report_received(self, pdu.msg_reference.to_s, pdu.stat, pdu) end end when Pdu::BindTransceiverResponse case pdu.command_status when Pdu::Base::ESME_ROK logger.debug "Bound OK." @state = :bound if @delegate.respond_to?(:bound) @delegate.bound(self) end when Pdu::Base::ESME_RINVPASWD logger.warn "Invalid password." # scheduele the connection to close, which eventually will cause the unbound() delegate # method to be invoked. close_connection when Pdu::Base::ESME_RINVSYSID logger.warn "Invalid system id." close_connection else logger.warn "Unexpected BindTransceiverResponse. Command status: #{pdu.command_status}" close_connection end when Pdu::SubmitSmResponse = @ack_ids[pdu.sequence_number] if ! raise "Got SubmitSmResponse for unknown sequence_number: #{pdu.sequence_number}" end if pdu.command_status != Pdu::Base::ESME_ROK logger.error "Error status in SubmitSmResponse: #{pdu.command_status}" else logger.info "Got OK SubmitSmResponse (#{pdu.} -> #{})" if @delegate.respond_to?(:message_accepted) @delegate.(self, , pdu.) end end # Now we got the SMSC message id; create pending delivery report. @pdr_storage[pdu.] = when Pdu::SubmitMultiResponse = @ack_ids[pdu.sequence_number] if ! raise "Got SubmitMultiResponse for unknown sequence_number: #{pdu.sequence_number}" end if pdu.command_status != Pdu::Base::ESME_ROK logger.error "Error status in SubmitMultiResponse: #{pdu.command_status}" else logger.info "Got OK SubmitMultiResponse (#{pdu.} -> #{})" if @delegate.respond_to?(:message_accepted) @delegate.(self, , pdu.) end end else super end end |
#send_bind ⇒ Object
Send BindTransceiverResponse PDU.
171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/smpp/transceiver.rb', line 171 def send_bind raise IOError, 'Receiver already bound.' unless unbound? pdu = Pdu::BindTransceiver.new( @config[:system_id], @config[:password], @config[:system_type], @config[:source_ton], @config[:source_npi], @config[:source_address_range]) write_pdu(pdu) end |
#send_concat_mt(message_id, source_addr, destination_addr, message, options = {}) ⇒ Object
Send a concatenated message with a body of > 160 characters as multiple messages.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/smpp/transceiver.rb', line 50 def send_concat_mt(, source_addr, destination_addr, , = {}) logger.debug "Sending concatenated MT: #{}" if @state == :bound # Split the message into parts of 153 characters. (160 - 7 characters for UDH) parts = [] while .size > 0 do parts << .slice!(0..152) end 0.upto(parts.size-1) do |i| udh = sprintf("%c", 5) # UDH is 5 bytes. udh << sprintf("%c%c", 0, 3) # This is a concatenated message udh << sprintf("%c", ) # The ID for the entire concatenated message udh << sprintf("%c", parts.size) # How many parts this message consists of udh << sprintf("%c", i+1) # This is part i+1 = { :esm_class => 64, # This message contains a UDH header. :udh => udh } pdu = Pdu::SubmitSm.new(source_addr, destination_addr, parts[i], ) write_pdu pdu # This is definately a bit hacky - multiple PDUs are being associated with a single # message_id. @ack_ids[pdu.sequence_number] = end else raise InvalidStateException, "Transceiver is unbound. Connot send MT messages." end end |
#send_mt(message_id, source_addr, destination_addr, short_message, options = {}) ⇒ Object
Send an MT SMS message. Delegate will receive message_accepted callback when SMSC acknowledges.
35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/smpp/transceiver.rb', line 35 def send_mt(, source_addr, destination_addr, , ={}) logger.debug "Sending MT: #{}" if @state == :bound pdu = Pdu::SubmitSm.new(source_addr, destination_addr, , ) write_pdu pdu # keep the message ID so we can associate the SMSC message ID with our message # when the response arrives. @ack_ids[pdu.sequence_number] = else raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages." end end |
#send_multi_mt(message_id, source_addr, destination_addr_arr, short_message, options = {}) ⇒ Object
Send MT SMS message for multiple dest_address Author: Abhishek Parolkar (abhishekparolkar.com) USAGE: $tx.send_multi_mt(123, “9100000000”, [“9199000000000”,“91990000000001”,“9199000000002”], “Message here”)
86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/smpp/transceiver.rb', line 86 def send_multi_mt(, source_addr, destination_addr_arr, , ={}) logger.debug "Sending Multiple MT: #{}" if @state == :bound pdu = Pdu::SubmitMulti.new(source_addr, destination_addr_arr, , ) write_pdu pdu # keep the message ID so we can associate the SMSC message ID with our message # when the response arrives. @ack_ids[pdu.sequence_number] = else raise InvalidStateException, "Transceiver is unbound. Cannot send MT messages." end end |