rocket_sms 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/scheduler_runner.rb +11 -0
- data/bin/transceiver_runner.rb +10 -0
- data/examples/gateway.rb +7 -0
- data/examples/gateway.yml +40 -0
- data/examples/test.rb +60 -0
- data/lib/rocket_sms.rb +111 -0
- data/lib/rocket_sms/did.rb +25 -0
- data/lib/rocket_sms/gateway.rb +123 -0
- data/lib/rocket_sms/lock.rb +0 -0
- data/lib/rocket_sms/message.rb +30 -0
- data/lib/rocket_sms/scheduler.rb +212 -0
- data/lib/rocket_sms/transceiver.rb +260 -0
- data/lib/rocket_sms/version.rb +3 -0
- data/rocket_sms.gemspec +34 -0
- data/spec/spec_helper.rb +17 -0
- data/vendor/ruby-smpp/CHANGELOG +52 -0
- data/vendor/ruby-smpp/CONTRIBUTORS.txt +11 -0
- data/vendor/ruby-smpp/Gemfile +8 -0
- data/vendor/ruby-smpp/LICENSE +20 -0
- data/vendor/ruby-smpp/README.rdoc +89 -0
- data/vendor/ruby-smpp/Rakefile +53 -0
- data/vendor/ruby-smpp/VERSION +1 -0
- data/vendor/ruby-smpp/config/environment.rb +2 -0
- data/vendor/ruby-smpp/examples/PDU1.example +26 -0
- data/vendor/ruby-smpp/examples/PDU2.example +26 -0
- data/vendor/ruby-smpp/examples/sample_gateway.rb +137 -0
- data/vendor/ruby-smpp/examples/sample_smsc.rb +102 -0
- data/vendor/ruby-smpp/lib/smpp.rb +25 -0
- data/vendor/ruby-smpp/lib/smpp/base.rb +308 -0
- data/vendor/ruby-smpp/lib/smpp/encoding/utf8_encoder.rb +37 -0
- data/vendor/ruby-smpp/lib/smpp/optional_parameter.rb +35 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/base.rb +183 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_base.rb +25 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_receiver.rb +4 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_receiver_response.rb +4 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_resp_base.rb +17 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_transceiver.rb +4 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/bind_transceiver_response.rb +4 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/deliver_sm.rb +142 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/deliver_sm_response.rb +12 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/enquire_link.rb +11 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/enquire_link_response.rb +11 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/generic_nack.rb +20 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/submit_multi.rb +68 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/submit_multi_response.rb +49 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/submit_sm.rb +91 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/submit_sm_response.rb +31 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/unbind.rb +11 -0
- data/vendor/ruby-smpp/lib/smpp/pdu/unbind_response.rb +12 -0
- data/vendor/ruby-smpp/lib/smpp/receiver.rb +27 -0
- data/vendor/ruby-smpp/lib/smpp/server.rb +223 -0
- data/vendor/ruby-smpp/lib/smpp/transceiver.rb +109 -0
- data/vendor/ruby-smpp/lib/sms.rb +9 -0
- data/vendor/ruby-smpp/ruby-smpp.gemspec +96 -0
- data/vendor/ruby-smpp/test/delegate.rb +28 -0
- data/vendor/ruby-smpp/test/encoding_test.rb +232 -0
- data/vendor/ruby-smpp/test/optional_parameter_test.rb +30 -0
- data/vendor/ruby-smpp/test/pdu_parsing_test.rb +111 -0
- data/vendor/ruby-smpp/test/receiver_test.rb +232 -0
- data/vendor/ruby-smpp/test/responsive_delegate.rb +53 -0
- data/vendor/ruby-smpp/test/server.rb +56 -0
- data/vendor/ruby-smpp/test/smpp_test.rb +239 -0
- data/vendor/ruby-smpp/test/submit_sm_test.rb +40 -0
- data/vendor/ruby-smpp/test/transceiver_test.rb +35 -0
- data/vendor/smscsim/License.txt +61 -0
- data/vendor/smscsim/smpp.jar +0 -0
- data/vendor/smscsim/smscsim.jar +0 -0
- data/vendor/smscsim/start.sh +3 -0
- data/vendor/smscsim/users.txt +46 -0
- metadata +299 -0
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module RocketSMS
|
|
2
|
+
class Message
|
|
3
|
+
|
|
4
|
+
attr_reader :params
|
|
5
|
+
|
|
6
|
+
def initialize(params)
|
|
7
|
+
@params = OpenStruct.new(params)
|
|
8
|
+
@params.pass ||= 0
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_json
|
|
12
|
+
MultiJson.dump(@params.marshal_dump)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def add_pass
|
|
16
|
+
@params.pass += 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.from_json(json)
|
|
20
|
+
params = MultiJson.load(json, symbolize_keys: true)
|
|
21
|
+
msg = Message.new(params)
|
|
22
|
+
return msg
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def method_missing(sym, *args, &block)
|
|
26
|
+
@params.send(sym, *args, &block)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
module RocketSMS
|
|
2
|
+
|
|
3
|
+
class Scheduler
|
|
4
|
+
include Singleton
|
|
5
|
+
|
|
6
|
+
attr_accessor :redis_url, :log_location
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@redis_url, @log_location = nil, nil
|
|
10
|
+
@active = true
|
|
11
|
+
@fast = false
|
|
12
|
+
@dids = {}
|
|
13
|
+
@transceivers = {}
|
|
14
|
+
@throughput = 0
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def redis
|
|
18
|
+
@redis ||= EM::Hiredis.connect(@redis_url)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def logger
|
|
22
|
+
@logger ||= Logger.new(@log_location)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def log(msg, level = 'info')
|
|
26
|
+
if EM.reactor_running?
|
|
27
|
+
EM.defer{ logger.send(level, msg) }
|
|
28
|
+
else
|
|
29
|
+
logger.send(level, msg)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def queues
|
|
34
|
+
RocketSMS.queues
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def start
|
|
38
|
+
EM.threadpool_size = 128
|
|
39
|
+
EM.set_max_timers(100_000)
|
|
40
|
+
EM.run do
|
|
41
|
+
log "Starting Scheduler"
|
|
42
|
+
configure
|
|
43
|
+
detect
|
|
44
|
+
# Trap exit-related signals
|
|
45
|
+
Signal.trap("INT") { |signal| stop(signal) }
|
|
46
|
+
Signal.trap("TERM") { |signal| stop(signal) }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def stop(signal = nil)
|
|
51
|
+
if @kill
|
|
52
|
+
log "Forcing Exit. Check your data for losses."
|
|
53
|
+
shutdown
|
|
54
|
+
else
|
|
55
|
+
log "Stopping. Waiting 5 seconds for pending operations to finish."
|
|
56
|
+
@kill = true
|
|
57
|
+
@active = false
|
|
58
|
+
EM::Timer.new(5){ shutdown }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def shutdown
|
|
63
|
+
log "Scheduler DOWN."
|
|
64
|
+
EM.stop
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def configure
|
|
68
|
+
return unless @active
|
|
69
|
+
@configurator = EM::Timer.new(1){ configure }
|
|
70
|
+
redis.keys("gateway:transceivers:*") do |keys|
|
|
71
|
+
if keys
|
|
72
|
+
tids = keys.map{ |key| key.split(':')[2] }.uniq
|
|
73
|
+
@transceivers.keys.each{ |k| @transceivers.delete(k) unless tids.include?(k) }
|
|
74
|
+
tids.each do |tid|
|
|
75
|
+
redis.hget("gateway:transceivers:#{tid}","status") do |resp|
|
|
76
|
+
if resp == 'online'
|
|
77
|
+
redis.hget("gateway:transceivers:#{tid}", "throughput") do |payload|
|
|
78
|
+
if payload
|
|
79
|
+
throughput = payload.to_f
|
|
80
|
+
log "Adding Transceiver #{tid}" if !@transceivers[tid]
|
|
81
|
+
@transceivers[tid] = throughput
|
|
82
|
+
set_throughput
|
|
83
|
+
elsif @transceivers[tid]
|
|
84
|
+
log "Removing Transceiver #{tid}"
|
|
85
|
+
@transceivers.delete(tid)
|
|
86
|
+
set_throughput
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
if @transceivers[tid]
|
|
91
|
+
log "Removing Transceiver #{tid}"
|
|
92
|
+
@transceivers.delete(tid)
|
|
93
|
+
set_throughput
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
@transceivers = {}
|
|
100
|
+
@throughput = 0
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def set_throughput
|
|
106
|
+
@throughput = @transceivers.keys.map{ |tid| @transceivers[tid] }.reduce(&:+).to_f
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def detect
|
|
110
|
+
return unless @active
|
|
111
|
+
interval = @fast ? 0.001 : 1
|
|
112
|
+
@detector = EM::Timer.new(interval){ detect }
|
|
113
|
+
redis.multi
|
|
114
|
+
redis.zrange(queues[:mt][:pending], 0, 0, "WITHSCORES")
|
|
115
|
+
redis.zremrangebyrank(queues[:mt][:pending], 0, 0)
|
|
116
|
+
redis.exec do |response|
|
|
117
|
+
if response
|
|
118
|
+
(payload, score) = response[0]
|
|
119
|
+
if payload and score
|
|
120
|
+
@fast = true
|
|
121
|
+
now = Time.now.to_i
|
|
122
|
+
if score.to_i <= now
|
|
123
|
+
process_payload(payload)
|
|
124
|
+
else
|
|
125
|
+
redis.zadd(queues[:mt][:pending], score, payload)
|
|
126
|
+
@fast = false
|
|
127
|
+
end
|
|
128
|
+
else
|
|
129
|
+
@fast = false
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def process_payload(msg_payload)
|
|
136
|
+
begin
|
|
137
|
+
message = Message.from_json(msg_payload)
|
|
138
|
+
if message.pass > 5
|
|
139
|
+
log "Message #{message.id} has exceeded maximum retries. Send it to Failed queue."
|
|
140
|
+
redis.lpush(queues[:mt][:failure], message.to_json)
|
|
141
|
+
else
|
|
142
|
+
did_number = message.sender
|
|
143
|
+
redis.get("gateway:dids:#{did_number}") do |payload|
|
|
144
|
+
if payload
|
|
145
|
+
log "Scheduling Message #{message.id} to be sent through DID #{did_number}"
|
|
146
|
+
schedule(message, payload)
|
|
147
|
+
else
|
|
148
|
+
log "The DID #{did_number} for message #{message.id} is not configured. Retrying."
|
|
149
|
+
retry_message(message)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
rescue
|
|
154
|
+
log 'Invalid Message.'
|
|
155
|
+
redis.lpush(queues[:mt][:failure])
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def schedule(message, did_payload)
|
|
160
|
+
if @active
|
|
161
|
+
if @transceivers.keys.empty? or @throughput == 0
|
|
162
|
+
retry_message(message)
|
|
163
|
+
else
|
|
164
|
+
did = Did.from_json(did_payload)
|
|
165
|
+
if !@dids[did.number]
|
|
166
|
+
@dids[did.number] = {}
|
|
167
|
+
@dids[did.number][:last_send] = Time.now.to_f + 1
|
|
168
|
+
end
|
|
169
|
+
interval = ((did.throughput.to_f)**-1)*1.1
|
|
170
|
+
last_send = @dids[did.number][:last_send]
|
|
171
|
+
if Time.now.to_f - last_send > interval
|
|
172
|
+
base_time = Time.now.to_f + 1
|
|
173
|
+
else
|
|
174
|
+
base_time = last_send
|
|
175
|
+
end
|
|
176
|
+
message.send_at = base_time + interval
|
|
177
|
+
message.expires_at = message.send_at + 50*interval
|
|
178
|
+
@dids[did.number][:last_send] = message.send_at
|
|
179
|
+
score = (message.send_at * 1000).to_i
|
|
180
|
+
transceiver_id = pick_transceiver
|
|
181
|
+
redis.zadd("gateway:transceivers:#{transceiver_id}:dispatch", score, message.to_json)
|
|
182
|
+
end
|
|
183
|
+
else
|
|
184
|
+
score = message.send_at.to_i + 15
|
|
185
|
+
redis.zadd(queues[:mt][:pending], score, message.to_json)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def pick_transceiver
|
|
190
|
+
tids = []
|
|
191
|
+
@transceivers.each do |k,v|
|
|
192
|
+
weight = (v.to_f/@throughput*100).to_i
|
|
193
|
+
weight.times{ tids << k }
|
|
194
|
+
end
|
|
195
|
+
tids.flatten!
|
|
196
|
+
tids.sample
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def retry_message(message)
|
|
200
|
+
if message.pass > 5
|
|
201
|
+
log "Message #{message.id} has exceeded maximum retries. Send it to Failed queue."
|
|
202
|
+
redis.lpush(queues[:mt][:failure], message.to_json)
|
|
203
|
+
else
|
|
204
|
+
message.add_pass
|
|
205
|
+
score = Time.now.to_i + 15
|
|
206
|
+
redis.zadd(queues[:mt][:pending], score, message.to_json)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
end
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
module RocketSMS
|
|
2
|
+
|
|
3
|
+
class Transceiver
|
|
4
|
+
|
|
5
|
+
def initialize(id, redis_url, log_location)
|
|
6
|
+
@id, @redis_url, @log_location = id, redis_url, log_location
|
|
7
|
+
@active = true
|
|
8
|
+
@online = false
|
|
9
|
+
@fast = false
|
|
10
|
+
@settings = {}
|
|
11
|
+
@mts = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def redis
|
|
15
|
+
@redis ||= EM::Hiredis.connect(@redis_url)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def dredis
|
|
19
|
+
@dredis ||= EM::Hiredis.connect(@redis_url)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def logger
|
|
23
|
+
@logger ||= Logger.new(@log_location)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def log(msg, level = 'info')
|
|
27
|
+
if EM.reactor_running?
|
|
28
|
+
EM.defer{ logger.send(level, msg) }
|
|
29
|
+
else
|
|
30
|
+
logger.send(level, msg)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def queues
|
|
35
|
+
RocketSMS.queues
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def throughput
|
|
39
|
+
@settings && @settings[:throughput] ||= 1.0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def start
|
|
43
|
+
EM.threadpool_size = 128
|
|
44
|
+
EM.set_max_timers(100_000)
|
|
45
|
+
EM.run do
|
|
46
|
+
log "Starting Transceiver #{@id}"
|
|
47
|
+
# Set quantum to 10 milliseconds to support throughputs up to 100 MTs/sec
|
|
48
|
+
EM.set_quantum(10)
|
|
49
|
+
# Detect transceiver configuration from Redis.
|
|
50
|
+
configure
|
|
51
|
+
# Connect
|
|
52
|
+
connect
|
|
53
|
+
# Start detecting and dispatching MTs
|
|
54
|
+
dispatch
|
|
55
|
+
# Trap exit-related signals
|
|
56
|
+
Signal.trap("INT") { |signal| stop(signal) }
|
|
57
|
+
Signal.trap("TERM") { |signal| stop(signal) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def stop(signal = nil)
|
|
62
|
+
if @kill
|
|
63
|
+
log "#{@id} - Forcing Exit. Check your data for losses."
|
|
64
|
+
shutdown
|
|
65
|
+
else
|
|
66
|
+
log "#{@id} - Stopping. Waiting for pending operations to finish."
|
|
67
|
+
@kill = true
|
|
68
|
+
@active = false
|
|
69
|
+
@connection.close_connection_after_writing if @connection
|
|
70
|
+
@dispatcher.cancel if @dispatcher
|
|
71
|
+
@configurator.cancel if @configurator
|
|
72
|
+
@reconnector.cancel if @reconnector
|
|
73
|
+
redis.del("gateways:transceivers:#{@id}")
|
|
74
|
+
cleanup
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def shutdown
|
|
79
|
+
log "Transceiver #{@id} DOWN."
|
|
80
|
+
EM.stop
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def cleanup
|
|
84
|
+
redis.zrangebyscore("gateway:transceivers:#{@id}:dispatch", '-inf', '+inf') do |payloads|
|
|
85
|
+
if payloads and !payloads.empty?
|
|
86
|
+
op = Proc.new do |payload, iter|
|
|
87
|
+
message = Message.from_json(payload)
|
|
88
|
+
message.send_at, message.expires_at = nil, nil
|
|
89
|
+
score = (Time.now.to_f*1000).to_i
|
|
90
|
+
redis.multi
|
|
91
|
+
redis.zrem("gateway:transceivers:#{@id}:dispatch", payload)
|
|
92
|
+
redis.zadd(queues[:mt][:pending], score, payload)
|
|
93
|
+
redis.exec do |resp|
|
|
94
|
+
iter.next
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
cb = Proc.new do |responses|
|
|
98
|
+
EM::Timer.new(3){ shutdown }
|
|
99
|
+
end
|
|
100
|
+
EM::Iterator.new(payloads).each(op,cb)
|
|
101
|
+
else
|
|
102
|
+
EM::Timer.new(3){ shutdown }
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def configure
|
|
108
|
+
return unless @active
|
|
109
|
+
@configurator = EM::Timer.new(1){ configure }
|
|
110
|
+
redis.multi
|
|
111
|
+
redis.hget("gateway:transceivers:#{@id}", "throughput")
|
|
112
|
+
redis.hget("gateway:transceivers:#{@id}", "connection")
|
|
113
|
+
redis.exec do |response|
|
|
114
|
+
if response and !response.flatten.include?(nil)
|
|
115
|
+
throughput_payload = response[0]
|
|
116
|
+
connection_payload = response[1]
|
|
117
|
+
@settings[:throughput] = throughput_payload.to_f
|
|
118
|
+
@settings[:connection] = MultiJson.load(connection_payload, symbolize_keys: true)
|
|
119
|
+
else
|
|
120
|
+
stop
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def connect
|
|
126
|
+
return unless @active
|
|
127
|
+
if @settings and @settings[:connection]
|
|
128
|
+
log "Connecting transceiver #{@id}."
|
|
129
|
+
@connection = EM.connect(
|
|
130
|
+
@settings[:connection][:host],
|
|
131
|
+
@settings[:connection][:port],
|
|
132
|
+
Smpp::Transceiver,
|
|
133
|
+
@settings[:connection],
|
|
134
|
+
self
|
|
135
|
+
)
|
|
136
|
+
else
|
|
137
|
+
EM::Timer.new(1){ connect }
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def dispatch
|
|
142
|
+
return unless @active
|
|
143
|
+
interval = @fast ? ((throughput.to_f)**-1)*1.1 : 0.5
|
|
144
|
+
@dispatcher = EM::Timer.new(interval){ dispatch }
|
|
145
|
+
redis.multi
|
|
146
|
+
redis.zrange("gateway:transceivers:#{@id}:dispatch", 0, 0)
|
|
147
|
+
redis.zremrangebyrank("gateway:transceivers:#{@id}:dispatch", 0, 0)
|
|
148
|
+
redis.exec do |response|
|
|
149
|
+
if response
|
|
150
|
+
payload = response[0][0]
|
|
151
|
+
if payload
|
|
152
|
+
@fast = true
|
|
153
|
+
now = Time.now.to_f
|
|
154
|
+
message = Message.from_json(payload)
|
|
155
|
+
if message.send_at > now
|
|
156
|
+
score = (message.send_at * 1000).to_i
|
|
157
|
+
redis.zadd("gateway:transceivers:#{@id}:dispatch", score , payload)
|
|
158
|
+
elsif message.send_at <= now and now < message.expires_at
|
|
159
|
+
log "Message #{message.id} detected on #{@id}. Sending."
|
|
160
|
+
send_message(message)
|
|
161
|
+
elsif message.expires_at <= now
|
|
162
|
+
log "Message #{message.id} detected on #{@id} but has expired. Retrying."
|
|
163
|
+
message.add_pass
|
|
164
|
+
score = (( Time.now.to_f + 15 ) * 1000).to_i
|
|
165
|
+
redis.zadd(queues[:mt][:pending], score, message.to_json)
|
|
166
|
+
@dispatcher.cancel if @dispatcher
|
|
167
|
+
EM.next_tick{ dispatch }
|
|
168
|
+
end
|
|
169
|
+
else
|
|
170
|
+
@fast = false
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def register
|
|
177
|
+
stat = @online ? 'online' : 'offline'
|
|
178
|
+
redis.hset("gateway:transceivers:#{@id}", 'status', stat)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def send_message(message)
|
|
182
|
+
begin
|
|
183
|
+
if @online
|
|
184
|
+
log "Sending Message #{message.id} through DID #{message.sender} via #{@id}."
|
|
185
|
+
@mts[message.id.to_s] = message
|
|
186
|
+
@connection.send_mt(message.id,message.sender,message.receiver,message.body)
|
|
187
|
+
else
|
|
188
|
+
log "#{@id} is not connected. Pushing message #{message.id} to dispatch queue."
|
|
189
|
+
score = (message.send_at * 1000).to_i
|
|
190
|
+
redis.zadd("gateway:transceivers:#{@id}:dispatch", score , payload)
|
|
191
|
+
end
|
|
192
|
+
rescue Exception
|
|
193
|
+
log "### Error Sending MT #{message.id} with DID #{message.sender} through Transceiver #{@id}. Retrying message."
|
|
194
|
+
message.add_pass
|
|
195
|
+
score = Time.now.to_i + 15
|
|
196
|
+
redis.zadd(queues[:mt][:pending], score, message.to_json)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def mo_received(transceiver, pdu)
|
|
201
|
+
log "#{@id} - Message Received"
|
|
202
|
+
ticket = { pdu: { source_addr: pdu.source_addr, short_message: pdu.short_message, destination_addr: pdu.destination_addr } }
|
|
203
|
+
EM.next_tick { redis.lpush(queues[:mo],MultiJson.dump(ticket)) }
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def delivery_report_received(transceiver, pdu)
|
|
207
|
+
log "#{@id} - DR Received"
|
|
208
|
+
ticket = { pdu: { source_addr: pdu.source_addr, short_message: pdu.short_message, destination_addr: pdu.destination_addr } }
|
|
209
|
+
EM.next_tick { redis.lpush(queues[:dr],MultiJson.dump(ticket)) }
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def message_accepted(transceiver, mt_message_id, pdu)
|
|
213
|
+
message = @mts.delete(mt_message_id.to_s)
|
|
214
|
+
if message
|
|
215
|
+
log "#{@id} - Message #{message.id} - Accepted"
|
|
216
|
+
message.accepted_at = Time.now.to_i
|
|
217
|
+
EM.next_tick { redis.lpush(queues[:mt][:success],message.to_json) }
|
|
218
|
+
else
|
|
219
|
+
log "#{@id} - Untracked MT Accepted #{mt_message_id}"
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def message_rejected(transceiver, mt_message_id, pdu)
|
|
224
|
+
message = @mts.delete(mt_message_id.to_s)
|
|
225
|
+
if message
|
|
226
|
+
log "#{@id} - Message #{message.id} - Rejected"
|
|
227
|
+
message.add_pass
|
|
228
|
+
message.rejected_at = Time.now.to_i
|
|
229
|
+
if message.pass <= 5
|
|
230
|
+
score = Time.now.to_i + 10
|
|
231
|
+
EM.next_tick{ redis.zadd(queues[:mt][:pending], score, message.to_json) }
|
|
232
|
+
else
|
|
233
|
+
EM.next_tick { redis.lpush(queues[:mt][:failure],message.to_json) }
|
|
234
|
+
end
|
|
235
|
+
else
|
|
236
|
+
log "#{@id} - Untracked MT Rejected #{mt_message_id}"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def bound(transceiver)
|
|
241
|
+
log "#{@id} - Transceiver Bound"
|
|
242
|
+
@online = true
|
|
243
|
+
@reconnector = nil
|
|
244
|
+
register
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def unbound(transceiver)
|
|
248
|
+
log "#{@id} - Transceiver Unbound"
|
|
249
|
+
if @active
|
|
250
|
+
log "#{@id} is not connected. Retrying in 10 seconds."
|
|
251
|
+
@reconnector.cancel if @reconnector
|
|
252
|
+
@reconnector = EM::Timer.new(10){ connect }
|
|
253
|
+
end
|
|
254
|
+
@online = false
|
|
255
|
+
register
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|