empp 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README +0 -0
- data/README.rdoc +19 -0
- data/lib/empp.rb +2 -0
- data/lib/empp/constants.rb +28 -0
- data/lib/empp/delivery_state.rb +11 -0
- data/lib/empp/empp.rb +375 -0
- data/lib/empp/empp_base.rb +37 -0
- data/lib/empp/empp_connection.rb +90 -0
- data/lib/empp/empp_logger.rb +45 -0
- data/lib/empp/empp_msg_listener.rb +9 -0
- data/lib/empp/empp_parser.rb +176 -0
- data/lib/empp/empp_result_listener.rb +16 -0
- data/lib/empp/msg_active_test.rb +28 -0
- data/lib/empp/msg_active_test_resp.rb +14 -0
- data/lib/empp/msg_connect.rb +52 -0
- data/lib/empp/msg_connect_resp.rb +22 -0
- data/lib/empp/msg_delivery.rb +21 -0
- data/lib/empp/msg_delivery_resp.rb +35 -0
- data/lib/empp/msg_submit.rb +105 -0
- data/lib/empp/msg_submit_resp.rb +23 -0
- data/lib/empp/tcp_connection.rb +103 -0
- data/lib/empp/utils/bytebuffer.rb +39 -0
- data/lib/empp/utils/hashtable.rb +36 -0
- data/lib/empp/utils/utils.rb +120 -0
- data/test/helper.rb +3 -0
- data/test/test_empp.rb +161 -0
- data/test/test_msg_submit.rb +16 -0
- data/test/test_tcp_connection.rb +29 -0
- data/test/test_utils.rb +49 -0
- metadata +157 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 lijianjun
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= empp
|
2
|
+
|
3
|
+
Description goes here.
|
4
|
+
|
5
|
+
== Contributing to empp
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2010 lijianjun. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/lib/empp.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Empp
|
2
|
+
module Constants
|
3
|
+
# defined by documents
|
4
|
+
EMPPCONNECT = 0x00000001
|
5
|
+
EMPP_CONNECT_RESP = 0x80000001
|
6
|
+
|
7
|
+
EMPP_ACTIVE_TEST = 0x00000008
|
8
|
+
EMPP_ACTIVE_TEST_RESP = 0x80000008
|
9
|
+
|
10
|
+
EMPP_SUBMIT = 0x00000004
|
11
|
+
EMPP_SUBMIT_RESP = 0x80000004
|
12
|
+
|
13
|
+
EMPP_DELIVER = 0x00000005
|
14
|
+
EMPP_DELIVER_RESP = 0x80000005
|
15
|
+
|
16
|
+
|
17
|
+
EMPP_CONNECT_OK = 0 # connect OK
|
18
|
+
|
19
|
+
# defined by programme
|
20
|
+
EMPP_CONNECT_ERROR = -1 # broken connect
|
21
|
+
|
22
|
+
EMPP_SUBMIT_STATUS_SUCCESS = 0
|
23
|
+
|
24
|
+
EMPP_DELIVER_SUCCESS = -2
|
25
|
+
EMPP_DELIVER_FAIL = -3
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Empp
|
2
|
+
|
3
|
+
class DeliveryState
|
4
|
+
attr_accessor :msg_id, :state, :submit_time, :done_time, :dest_terminal_id, :sequence_id
|
5
|
+
|
6
|
+
def to_s
|
7
|
+
"msg_id=#{@msg_id}, state=#{@state}, submit_time=#{@submit_time}, done_time=#{@done_time}, dest_terminal_id=#{@dest_terminal_id}, sequence_id=#{@sequence_id}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
data/lib/empp/empp.rb
ADDED
@@ -0,0 +1,375 @@
|
|
1
|
+
require 'empp/empp_connection'
|
2
|
+
require 'empp/constants'
|
3
|
+
require 'empp/msg_active_test'
|
4
|
+
require 'empp/empp_logger'
|
5
|
+
require 'empp/msg_submit'
|
6
|
+
require 'empp/utils/hashtable'
|
7
|
+
require 'empp/utils/utils'
|
8
|
+
require 'empp/empp_parser'
|
9
|
+
require 'empp/msg_delivery_resp'
|
10
|
+
require 'empp/empp_msg_listener'
|
11
|
+
require 'empp/empp_result_listener'
|
12
|
+
|
13
|
+
require 'thread'
|
14
|
+
require 'singleton'
|
15
|
+
|
16
|
+
module Empp
|
17
|
+
|
18
|
+
class Empp
|
19
|
+
|
20
|
+
include Singleton
|
21
|
+
|
22
|
+
@@configuration = {
|
23
|
+
:host => '',
|
24
|
+
:port => -1,
|
25
|
+
:account_id => '',
|
26
|
+
:service_id => '',
|
27
|
+
:password => '',
|
28
|
+
:logger => nil
|
29
|
+
}
|
30
|
+
|
31
|
+
# message state callback list, when state returns
|
32
|
+
# sequence_id => listener
|
33
|
+
@@result_listeners = Utils::Hashtable.new
|
34
|
+
@@msg_listeners = []
|
35
|
+
|
36
|
+
def self.config(configuration = {})
|
37
|
+
@@configuration.merge! configuration
|
38
|
+
|
39
|
+
# config logger: debug by default debug:0 info:1 warn:2 error:3 fatal:4
|
40
|
+
EmppLogger.config(@@configuration)
|
41
|
+
EmppParser::logger = EmppLogger.instance
|
42
|
+
|
43
|
+
self.instance
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.send_msg(terminal_ids, msg_content, result_listener = nil)
|
48
|
+
self.instance.submit_msg(terminal_ids, msg_content, result_listener)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.register_msg_listener(msg_listener)
|
52
|
+
|
53
|
+
if msg_listener && (msg_listener.kind_of?EmppMsgListener)
|
54
|
+
@@msg_listeners << msg_listener
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def alive?
|
60
|
+
@alive
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def initialize
|
65
|
+
|
66
|
+
@alive = false
|
67
|
+
# it's updated every active response returns and set sequence_id to this value
|
68
|
+
@active_test_flag = -1
|
69
|
+
|
70
|
+
@active_keeper = nil
|
71
|
+
@receiver = nil
|
72
|
+
@sender = nil
|
73
|
+
|
74
|
+
@sending_queue = Queue.new
|
75
|
+
@sended_list = Utils::Hashtable.new
|
76
|
+
@listener = nil
|
77
|
+
|
78
|
+
@logger = @@configuration[:logger] || EmppLogger.instance
|
79
|
+
|
80
|
+
# connect to server
|
81
|
+
connect(@@configuration[:host], @@configuration[:port], @@configuration[:account_id], @@configuration[:password], @@configuration[:service_id])
|
82
|
+
|
83
|
+
# automatic reconnect if fails
|
84
|
+
@alive_supervisor = Thread.new { start_supervisor }
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
def connect(host, port, account_id, password, service_id, listener = nil)
|
89
|
+
@logger.debug("Enter EmppApi::connect")
|
90
|
+
|
91
|
+
@host = host
|
92
|
+
@port = port
|
93
|
+
@account_id = account_id
|
94
|
+
@service_id = service_id
|
95
|
+
@password = password
|
96
|
+
|
97
|
+
@empp_connection = EmppConnection.new(host, port, account_id, password, service_id)
|
98
|
+
@alive = @empp_connection.connect
|
99
|
+
|
100
|
+
if @alive
|
101
|
+
start_work
|
102
|
+
end
|
103
|
+
|
104
|
+
@logger.debug("Leave EmppApi::connect")
|
105
|
+
|
106
|
+
@alive
|
107
|
+
end
|
108
|
+
|
109
|
+
public
|
110
|
+
def submit_msg(terminal_ids, message, result_listener = nil)
|
111
|
+
@logger.debug("Enter EmppApi::submitMsg")
|
112
|
+
|
113
|
+
if !terminal_ids
|
114
|
+
@logger.debug("Leave EmppApi::submitMsg with nil terminal_ids")
|
115
|
+
return
|
116
|
+
end
|
117
|
+
|
118
|
+
message ||= ''
|
119
|
+
|
120
|
+
if terminal_ids.kind_of?String
|
121
|
+
terminals = [ terminal_ids ]
|
122
|
+
elsif terminal_ids.kind_of?Array
|
123
|
+
terminals = terminal_ids
|
124
|
+
else
|
125
|
+
@logger.warn("EmppApi::submitMsg: Unsupported param type for terminal_ids:#{terminal_ids}")
|
126
|
+
return
|
127
|
+
end
|
128
|
+
|
129
|
+
terminals.each do |terminal_id|
|
130
|
+
next if terminal_id.length < 11 || terminal_id.length > 14
|
131
|
+
next if terminal_id !~ /^((86)|(\+86))?\d+$/
|
132
|
+
|
133
|
+
msgsubmit = MsgSubmit.new(terminal_id, message, @account_id, @service_id)
|
134
|
+
|
135
|
+
@sending_queue.push(msgsubmit)
|
136
|
+
|
137
|
+
# add result listeners
|
138
|
+
if result_listener && (result_listener.kind_of?EmppResultListener)
|
139
|
+
|
140
|
+
msgsubmit.sequence_ids.each do |sequence_id|
|
141
|
+
@@result_listeners.put(sequence_id, result_listener)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
@logger.info("EmppApi::submitMsg Sending queue size=#{@sending_queue.size}")
|
147
|
+
end
|
148
|
+
|
149
|
+
@logger.debug("Leave EmppApi::submitMsg")
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
def disconnect
|
154
|
+
if @active_keeper
|
155
|
+
@active_keeper.exit
|
156
|
+
end
|
157
|
+
|
158
|
+
if @receiver
|
159
|
+
@receiver.exit
|
160
|
+
end
|
161
|
+
|
162
|
+
if @sender
|
163
|
+
@sender.exit
|
164
|
+
end
|
165
|
+
|
166
|
+
@active_keeper = nil
|
167
|
+
@receiver = nil
|
168
|
+
@sender = nil
|
169
|
+
@empp_connection = nil
|
170
|
+
end
|
171
|
+
|
172
|
+
def reconnect
|
173
|
+
connect(@host, @port, @account_id, @password, @service_id, @listener)
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
def start_work
|
179
|
+
@active_keeper = Thread.new { start_keeper }
|
180
|
+
@receiver = Thread.new { start_receiver }
|
181
|
+
@sender = Thread.new { start_sender }
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
def start_keeper
|
186
|
+
@logger.debug("Enter EmppApi::start_keeper")
|
187
|
+
|
188
|
+
interval = 30 # 3 minutes
|
189
|
+
retry_count = 5
|
190
|
+
|
191
|
+
while @alive && @empp_connection.alive?
|
192
|
+
|
193
|
+
@logger.info("EmppApi::start_keeper: Active test...")
|
194
|
+
old_active_test_flag = @active_test_flag
|
195
|
+
activeTest = MsgActiveTest.new
|
196
|
+
|
197
|
+
@empp_connection.send(activeTest)
|
198
|
+
|
199
|
+
# waiting for confirmation from ESMP
|
200
|
+
sleep interval
|
201
|
+
|
202
|
+
if old_active_test_flag == @active_test_flag
|
203
|
+
retry_count -= 1
|
204
|
+
interval = 3 # change interval to little value
|
205
|
+
|
206
|
+
@logger.warn("EmppApi::start_keeper : No response from ESMP, will retry #{retry_count}")
|
207
|
+
if retry_count == 0
|
208
|
+
@alive = false # connection is broken
|
209
|
+
|
210
|
+
# broke the connections, stop the threads
|
211
|
+
disconnect
|
212
|
+
|
213
|
+
@logger.fatal("EmppApi::start_keeper : Empp connection is broken.")
|
214
|
+
end
|
215
|
+
|
216
|
+
else
|
217
|
+
retry_count = 5
|
218
|
+
interval = 30
|
219
|
+
end
|
220
|
+
|
221
|
+
end # while
|
222
|
+
|
223
|
+
@logger.debug("Leave EmppApi::start_keeper")
|
224
|
+
end
|
225
|
+
|
226
|
+
def start_receiver
|
227
|
+
@logger.debug("Enter EmppApi::start_receiver")
|
228
|
+
|
229
|
+
while @alive && @empp_connection.alive?
|
230
|
+
empp_object = @empp_connection.receive
|
231
|
+
@logger.info("EmppApi::start_receiver: receive object=#{empp_object}")
|
232
|
+
if empp_object
|
233
|
+
processEmppObject(empp_object)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
@logger.debug("Leave EmppApi::start_receiver")
|
238
|
+
end
|
239
|
+
|
240
|
+
####################################################
|
241
|
+
## supervise the connection, if it's broken, this ##
|
242
|
+
## will reconnect automatically ##
|
243
|
+
####################################################
|
244
|
+
def start_supervisor
|
245
|
+
@logger.debug("Enter EmppApi::start_supervisor")
|
246
|
+
|
247
|
+
interval = 60
|
248
|
+
|
249
|
+
while true
|
250
|
+
|
251
|
+
sleep interval
|
252
|
+
|
253
|
+
if !@alive || !@empp_connection.alive?
|
254
|
+
@logger.debug("EmppApi::start_supervisor, connection is broken, begin toreconnect")
|
255
|
+
disconnect
|
256
|
+
reconnect
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
@logger.debug("Leave EmppApi::start_supervisor")
|
262
|
+
end
|
263
|
+
|
264
|
+
def processEmppObject(empp_object)
|
265
|
+
@logger.debug("Enter EmppApi::processEmppObject")
|
266
|
+
|
267
|
+
case empp_object.command_id
|
268
|
+
when Constants::EMPP_ACTIVE_TEST_RESP
|
269
|
+
@active_test_flag = empp_object.sequence_id
|
270
|
+
@logger.info("EmppApi::processEmppObject: Active test response is OK.")
|
271
|
+
|
272
|
+
when Constants::EMPP_SUBMIT_RESP
|
273
|
+
sequence_id = empp_object.sequence_id
|
274
|
+
terminal_id = @sended_list.delete(sequence_id)
|
275
|
+
status = empp_object.status
|
276
|
+
|
277
|
+
if status == 0
|
278
|
+
@logger.debug("EmppApi::processEmppObject: message for #{terminal_id} is correct")
|
279
|
+
else
|
280
|
+
@logger.warn("EmppApi::processEmppObject: message for #{terminal_id} is invalid, status =#{status}")
|
281
|
+
end
|
282
|
+
# if @listener
|
283
|
+
# @listener.onResponse(Constants::EMPP_SUBMIT_RESP, status, terminal_id)
|
284
|
+
# end
|
285
|
+
|
286
|
+
when Constants::EMPP_DELIVER
|
287
|
+
@logger.info("EmppApi::processEmppObject: get delivery object=#{empp_object}")
|
288
|
+
terminal_id = empp_object.src_terminal_id
|
289
|
+
msg_content = empp_object.msg_content
|
290
|
+
registered_delivery = empp_object.registered_delivery
|
291
|
+
msg_id = empp_object.msg_id
|
292
|
+
|
293
|
+
if registered_delivery == 0 # message delivery
|
294
|
+
|
295
|
+
if empp_object.msg_format == 15
|
296
|
+
msg_content = Utils::Utils.convert_gbk_to_utf8(msg_content)
|
297
|
+
elsif empp_object.msg_format == 8
|
298
|
+
msg_content = Utils::Utils.convert_ucs2_to_utf8(msg_content)
|
299
|
+
end
|
300
|
+
|
301
|
+
respond_to_msg_listeners(terminal_id, msg_content)
|
302
|
+
|
303
|
+
else # it's a state devilery
|
304
|
+
|
305
|
+
deliveryState = EmppParser.parseDeliveryState(msg_content)
|
306
|
+
@logger.info("EmppApi::processEmppObject: get delivery state=#{deliveryState}")
|
307
|
+
|
308
|
+
if deliveryState.state.start_with?'DELIV'
|
309
|
+
|
310
|
+
respond_to_result_listeners(deliveryState.sequence_id, terminal_id, true)
|
311
|
+
|
312
|
+
else # fail to delivery
|
313
|
+
|
314
|
+
respond_to_result_listeners(deliveryState.sequence_id, terminal_id, false)
|
315
|
+
|
316
|
+
end
|
317
|
+
|
318
|
+
end # end registered_delivery
|
319
|
+
|
320
|
+
# send response for the delivery
|
321
|
+
msg_delivery_resp = MsgDeliveryResp.new
|
322
|
+
msg_delivery_resp.msg_id = msg_id
|
323
|
+
@empp_connection.send(msg_delivery_resp)
|
324
|
+
|
325
|
+
end # end case
|
326
|
+
|
327
|
+
|
328
|
+
|
329
|
+
@logger.debug("Leave EmppApi::processEmppObject")
|
330
|
+
end
|
331
|
+
|
332
|
+
def start_sender
|
333
|
+
@logger.debug("Enter EmppApi::start_sender")
|
334
|
+
|
335
|
+
while @alive && @empp_connection.alive?
|
336
|
+
@logger.debug("EmppApi::before pop")
|
337
|
+
|
338
|
+
msgObj = @sending_queue.pop
|
339
|
+
@logger.debug("EmppApi::after pop, pop obj=#{msgObj}")
|
340
|
+
@empp_connection.send(msgObj)
|
341
|
+
|
342
|
+
@sended_list.put(msgObj.sequence_id, msgObj.terminal_id)
|
343
|
+
|
344
|
+
sleep 3
|
345
|
+
end
|
346
|
+
|
347
|
+
@logger.debug("Leave EmppApi::start_sender")
|
348
|
+
end
|
349
|
+
|
350
|
+
####################################################
|
351
|
+
## respond to message listeners ##
|
352
|
+
####################################################
|
353
|
+
def respond_to_msg_listeners(terminal_id, msg_content)
|
354
|
+
|
355
|
+
@@msg_listeners.each do | listener |
|
356
|
+
listener.on_message(terminal_id, msg_content)
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
360
|
+
|
361
|
+
########################################################
|
362
|
+
# respond to result listeners ##
|
363
|
+
#########################################################
|
364
|
+
def respond_to_result_listeners(sequence_id, terminal_id, status)
|
365
|
+
|
366
|
+
result_listener = @@result_listeners.delete(sequence_id)
|
367
|
+
if result_listener
|
368
|
+
result_listener.on_result(terminal_id, status)
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
372
|
+
|
373
|
+
end
|
374
|
+
|
375
|
+
end
|