Commit 517105a6b1e1e5ccb2d940987693755d5dc16766
1 parent
4c33c17227
Exists in
master
epic
Showing 1 changed file with 9 additions and 0 deletions Inline Diff
main.py
1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
2 | 2 | ||
3 | import logging | 3 | import logging |
4 | from logging.handlers import TimedRotatingFileHandler | 4 | from logging.handlers import TimedRotatingFileHandler |
5 | import ConfigParser | 5 | import ConfigParser |
6 | import json | 6 | import json |
7 | from os import getpid | 7 | from os import getpid |
8 | import re | 8 | import re |
9 | import signal | 9 | import signal |
10 | import sys | 10 | import sys |
11 | 11 | ||
12 | config = ConfigParser.RawConfigParser() | 12 | config = ConfigParser.RawConfigParser() |
13 | config.read('config.ini') | 13 | config.read('config.ini') |
14 | 14 | ||
15 | PORT = config.get('globals','PORT') | 15 | PORT = config.get('globals','PORT') |
16 | BAUDRATE = config.getint('globals', 'BAUDRATE') | 16 | BAUDRATE = config.getint('globals', 'BAUDRATE') |
17 | PIN = None # SIM card PIN (if any) | 17 | PIN = None # SIM card PIN (if any) |
18 | PIN_TRX = config.get('globals', 'PIN_TRX') | 18 | PIN_TRX = config.get('globals', 'PIN_TRX') |
19 | 19 | ||
20 | BASE_CHIPINFO = config.get('globals', 'BASE_CHIPINFO') | 20 | BASE_CHIPINFO = config.get('globals', 'BASE_CHIPINFO') |
21 | CHIPINFO = BASE_CHIPINFO | 21 | CHIPINFO = BASE_CHIPINFO |
22 | 22 | ||
23 | AAA_HOST = config.get('globals', 'AAA_HOST') | 23 | AAA_HOST = config.get('globals', 'AAA_HOST') |
24 | CITY = config.get('globals', 'CITY') | 24 | CITY = config.get('globals', 'CITY') |
25 | PRODUCTS = config.get('globals', 'PRODUCTS') | 25 | PRODUCTS = config.get('globals', 'PRODUCTS') |
26 | 26 | ||
27 | REDIS_HOST = config.get('globals', 'REDIS_HOST') | 27 | REDIS_HOST = config.get('globals', 'REDIS_HOST') |
28 | REDIS_PORT = config.getint('globals', 'REDIS_PORT') | 28 | REDIS_PORT = config.getint('globals', 'REDIS_PORT') |
29 | REDIS_TTL = config.getint('globals', 'REDIS_TTL') | 29 | REDIS_TTL = config.getint('globals', 'REDIS_TTL') |
30 | REDIS_DISABLE_PULL_TTL = config.getint('globals', 'REDIS_DISABLE_PULL_TTL') | 30 | REDIS_DISABLE_PULL_TTL = config.getint('globals', 'REDIS_DISABLE_PULL_TTL') |
31 | 31 | ||
32 | PULL_INTERVAL = config.getint('globals', 'PULL_INTERVAL') | 32 | PULL_INTERVAL = config.getint('globals', 'PULL_INTERVAL') |
33 | SLEEP_AFTER_TOPUP = config.getint('globals', 'SLEEP_AFTER_TOPUP') | 33 | SLEEP_AFTER_TOPUP = config.getint('globals', 'SLEEP_AFTER_TOPUP') |
34 | SLEEP_BETWEEN_BALANCE_N_TOPUP = config.getint('globals', 'SLEEP_BETWEEN_BALANCE_N_TOPUP') | 34 | SLEEP_BETWEEN_BALANCE_N_TOPUP = config.getint('globals', 'SLEEP_BETWEEN_BALANCE_N_TOPUP') |
35 | TOPUP_USSD_TIMEOUT = config.getint('globals', 'TOPUP_USSD_TIMEOUT') | 35 | TOPUP_USSD_TIMEOUT = config.getint('globals', 'TOPUP_USSD_TIMEOUT') |
36 | SLEEP_AFTER_USSD_ERROR = 180 | 36 | SLEEP_AFTER_USSD_ERROR = 180 |
37 | 37 | ||
38 | MIN_SIGNAL_STRENGTH = 0 | 38 | MIN_SIGNAL_STRENGTH = 0 |
39 | try: | 39 | try: |
40 | MIN_SIGNAL_STRENGTH = config.getint('globals', 'MIN_SIGNAL_STRENGTH') | 40 | MIN_SIGNAL_STRENGTH = config.getint('globals', 'MIN_SIGNAL_STRENGTH') |
41 | except: | 41 | except: |
42 | pass | 42 | pass |
43 | if not MIN_SIGNAL_STRENGTH: | 43 | if not MIN_SIGNAL_STRENGTH: |
44 | MIN_SIGNAL_STRENGTH = 13 | 44 | MIN_SIGNAL_STRENGTH = 13 |
45 | 45 | ||
46 | MIN_BALANCE = config.getint('globals', 'MIN_BALANCE') | 46 | MIN_BALANCE = config.getint('globals', 'MIN_BALANCE') |
47 | 47 | ||
48 | PULL_COUNT = 0 | 48 | PULL_COUNT = 0 |
49 | MSISDN = '' | 49 | MSISDN = '' |
50 | BALANCE = 0 | 50 | BALANCE = 0 |
51 | 51 | ||
52 | DISABLE_SEM=0 | 52 | DISABLE_SEM=0 |
53 | DISABLE_SEM_ON_TRX=60 | 53 | DISABLE_SEM_ON_TRX=60 |
54 | 54 | ||
55 | TERMINATING=False | 55 | TERMINATING=False |
56 | 56 | ||
57 | LAST_REQUEST_ID = None | 57 | LAST_REQUEST_ID = None |
58 | LAST_SN = None | 58 | LAST_SN = None |
59 | LAST_PRODUCT = '' | 59 | LAST_PRODUCT = '' |
60 | 60 | ||
61 | PULSA = 0 | 61 | PULSA = 0 |
62 | MASA_AKTIF = "" | 62 | MASA_AKTIF = "" |
63 | 63 | ||
64 | logger = None | 64 | logger = None |
65 | 65 | ||
66 | from gsmmodem.modem import GsmModem | 66 | from gsmmodem.modem import GsmModem |
67 | from gsmmodem.exceptions import TimeoutException | 67 | from gsmmodem.exceptions import TimeoutException |
68 | 68 | ||
69 | from time import sleep | 69 | from time import sleep |
70 | from time import strftime | 70 | from time import strftime |
71 | 71 | ||
72 | import redis | 72 | import redis |
73 | import requests | 73 | import requests |
74 | 74 | ||
75 | import sate24 | 75 | import sate24 |
76 | import xltunai | 76 | import xltunai |
77 | 77 | ||
78 | redis_client = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=0) | 78 | redis_client = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=0) |
79 | 79 | ||
80 | def signalHandler(signum, frame): | 80 | def signalHandler(signum, frame): |
81 | global TERMINATING | 81 | global TERMINATING |
82 | 82 | ||
83 | if signum == signal.SIGINT or signum == signal.SIGTERM: | 83 | if signum == signal.SIGINT or signum == signal.SIGTERM: |
84 | logger.info('Signal ({0}) received, waiting for next loop to terminate. Terminating...'.format(signum)) | 84 | logger.info('Signal ({0}) received, waiting for next loop to terminate. Terminating...'.format(signum)) |
85 | TERMINATING = True | 85 | TERMINATING = True |
86 | 86 | ||
87 | def handleSms(sms): | 87 | def handleSms(sms): |
88 | global CHIPINFO | ||
88 | global DISABLE_SEM | 89 | global DISABLE_SEM |
89 | global PRODUCTS | 90 | global PRODUCTS |
90 | global LAST_PRODUCT | 91 | global LAST_PRODUCT |
91 | global LAST_REQUEST_ID | 92 | global LAST_REQUEST_ID |
92 | 93 | ||
93 | logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text)) | 94 | logger.info(u'Incoming SMS from: {0}; Time: {1}; Message: {2}'.format(sms.number, sms.time, sms.text)) |
94 | 95 | ||
96 | try: | ||
97 | epic_key = 'epic.msgin.gw:' + BASE_CHIPINFO | ||
98 | redis_client.publish(epic_key + '.message', u'{0}: {1} ({2})'.format(sms.number, sms.text, CHIPINFO)) | ||
99 | except: | ||
100 | logger.warning('Fail to publish epic message to redis') | ||
101 | |||
95 | if not xltunai.isValidSender(sms.number): | 102 | if not xltunai.isValidSender(sms.number): |
96 | logger.info('Ignoring incoming SMS from invalid sender') | 103 | logger.info('Ignoring incoming SMS from invalid sender') |
97 | return | 104 | return |
98 | 105 | ||
99 | if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0: | 106 | if sms.text.find('Terimakasih, transaksi CASH IN ke akun') >= 0: |
100 | logger.info('handleSms: CASH IN, aktivasi pull jika non aktif') | 107 | logger.info('handleSms: CASH IN, aktivasi pull jika non aktif') |
101 | enablePull() | 108 | enablePull() |
102 | return | 109 | return |
103 | 110 | ||
104 | if sms.text.find('Maaf, transaksi gagal') >= 0: | 111 | if sms.text.find('Maaf, transaksi gagal') >= 0: |
105 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) | 112 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) |
106 | return | 113 | return |
107 | 114 | ||
108 | elif sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0: | 115 | elif sms.text.find('PIN yang Anda masukkan salah. Silahkan ulangi kembali') >= 0: |
109 | pushTopupStatus(LAST_REQUEST_ID, '91', sms.text) | 116 | pushTopupStatus(LAST_REQUEST_ID, '91', sms.text) |
110 | return | 117 | return |
111 | 118 | ||
112 | elif sms.text.find('Maaf, saldo XL-Tunai anda tidak cukup') >= 0: | 119 | elif sms.text.find('Maaf, saldo XL-Tunai anda tidak cukup') >= 0: |
113 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) | 120 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) |
114 | return | 121 | return |
115 | 122 | ||
116 | elif sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0: | 123 | elif sms.text.find('Maaf, layanan ini hanya untuk nomor tujuan prabayar XL') >= 0: |
117 | pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) | 124 | pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) |
118 | return | 125 | return |
119 | 126 | ||
120 | elif sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0: | 127 | elif sms.text.find('Mohon maaf, nomor yang Anda masukkan tidak valid') >= 0: |
121 | pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) | 128 | pushTopupStatus(LAST_REQUEST_ID, '14', sms.text) |
122 | return | 129 | return |
123 | 130 | ||
124 | elif sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0: | 131 | elif sms.text.find('Mohon maaf, transaksi Anda melebihi limit nominal bulanan') >= 0: |
125 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) | 132 | pushTopupStatus(LAST_REQUEST_ID, '40', sms.text) |
126 | 133 | ||
127 | logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT)) | 134 | logger.info('Monthly limit for "{0}" detected, removing from product list'.format(LAST_PRODUCT)) |
128 | PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT) | 135 | PRODUCTS = sate24.removeProduct(PRODUCTS, LAST_PRODUCT) |
129 | logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS)) | 136 | logger.warning('Monthly limit for "{0}" exceeded. New active products: "{1}"'.format(LAST_PRODUCT, PRODUCTS)) |
130 | return | 137 | return |
131 | 138 | ||
132 | elif sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0: | 139 | elif sms.text.find('Maaf, transaksi Anda masih dalam proses') >= 0: |
133 | pushTopupStatus(LAST_REQUEST_ID, '68', sms.text) | 140 | pushTopupStatus(LAST_REQUEST_ID, '68', sms.text) |
134 | return | 141 | return |
135 | 142 | ||
136 | destination = xltunai.getDestinationFromMessage(sms.text) | 143 | destination = xltunai.getDestinationFromMessage(sms.text) |
137 | if destination == '': | 144 | if destination == '': |
138 | logger.warning('handleSms: gagal parsing nomor tujuan') | 145 | logger.warning('handleSms: gagal parsing nomor tujuan') |
139 | return | 146 | return |
140 | 147 | ||
141 | nominal = xltunai.getNominalFromMessage(sms.text) | 148 | nominal = xltunai.getNominalFromMessage(sms.text) |
142 | if nominal == '': | 149 | if nominal == '': |
143 | logger.warning('handleSms: gagal parsing nominal') | 150 | logger.warning('handleSms: gagal parsing nominal') |
144 | return | 151 | return |
145 | 152 | ||
146 | sn = xltunai.getSNFromMessage(sms.text) | 153 | sn = xltunai.getSNFromMessage(sms.text) |
147 | if sn == '': | 154 | if sn == '': |
148 | logger.warning('handleSms: gagal parsing SN') | 155 | logger.warning('handleSms: gagal parsing SN') |
149 | 156 | ||
150 | 157 | ||
151 | DISABLE_SEM = 0 | 158 | DISABLE_SEM = 0 |
152 | 159 | ||
153 | response_code = xltunai.getResponseCodeByMessage(sms.text) | 160 | response_code = xltunai.getResponseCodeByMessage(sms.text) |
154 | 161 | ||
155 | request_id = getRequestIdByNominalDestination(nominal, destination) | 162 | request_id = getRequestIdByNominalDestination(nominal, destination) |
156 | if not request_id: | 163 | if not request_id: |
157 | logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination)) | 164 | logger.info('Unknown request id for nominal:{0} destination:{1}'.format(nominal, destination)) |
158 | return | 165 | return |
159 | 166 | ||
160 | pushTopupStatus(request_id, response_code, sms.text) | 167 | pushTopupStatus(request_id, response_code, sms.text) |
161 | try: | 168 | try: |
162 | deleteMultipleStoredSms(2) | 169 | deleteMultipleStoredSms(2) |
163 | except: | 170 | except: |
164 | #logger.warning('Failed on delete SMS') | 171 | #logger.warning('Failed on delete SMS') |
165 | pass | 172 | pass |
166 | 173 | ||
167 | 174 | ||
168 | def getRequestIdByNominalDestination(nominal, destination): | 175 | def getRequestIdByNominalDestination(nominal, destination): |
176 | global CHIPINFO | ||
177 | |||
169 | redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination) | 178 | redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, destination) |
170 | #return redis_client.spop(redis_key) | 179 | #return redis_client.spop(redis_key) |
171 | return redis_client.rpop(redis_key) | 180 | return redis_client.rpop(redis_key) |
172 | 181 | ||
173 | def pushTopupStatus(request_id, response_code, _message, dontparsesn = False): | 182 | def pushTopupStatus(request_id, response_code, _message, dontparsesn = False): |
174 | global BALANCE | 183 | global BALANCE |
175 | global CHIPINFO | 184 | global CHIPINFO |
176 | global LAST_SN | 185 | global LAST_SN |
177 | 186 | ||
178 | redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' | 187 | redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' |
179 | if response_code == '00': | 188 | if response_code == '00': |
180 | redis_client.set(redis_key, response_code) | 189 | redis_client.set(redis_key, response_code) |
181 | else: | 190 | else: |
182 | redis_response_code = redis_client.get(redis_key) | 191 | redis_response_code = redis_client.get(redis_key) |
183 | if redis_response_code == '00': | 192 | if redis_response_code == '00': |
184 | logger.info('Ignoring message from success trx ') | 193 | logger.info('Ignoring message from success trx ') |
185 | return | 194 | return |
186 | 195 | ||
187 | message = "{0} -- Prev balance: {1}".format(_message, BALANCE) | 196 | message = "{0} -- Prev balance: {1}".format(_message, BALANCE) |
188 | 197 | ||
189 | timestamp = strftime('%Y%m%d%H%M%S') | 198 | timestamp = strftime('%Y%m%d%H%M%S') |
190 | 199 | ||
191 | if response_code == '00' and not dontparsesn: | 200 | if response_code == '00' and not dontparsesn: |
192 | sn = xltunai.getSNFromMessage(message) | 201 | sn = xltunai.getSNFromMessage(message) |
193 | LAST_SN = sn | 202 | LAST_SN = sn |
194 | message = 'SN={0};{1}'.format(sn, message) | 203 | message = 'SN={0};{1}'.format(sn, message) |
195 | 204 | ||
196 | push_message = CHIPINFO + '$' + message | 205 | push_message = CHIPINFO + '$' + message |
197 | 206 | ||
198 | payload = { | 207 | payload = { |
199 | 'trans_id': request_id, | 208 | 'trans_id': request_id, |
200 | 'trans_date': timestamp, | 209 | 'trans_date': timestamp, |
201 | 'resp_code': response_code, | 210 | 'resp_code': response_code, |
202 | 'ussd_msg': push_message | 211 | 'ussd_msg': push_message |
203 | } | 212 | } |
204 | 213 | ||
205 | url = AAA_HOST + '/topup' | 214 | url = AAA_HOST + '/topup' |
206 | 215 | ||
207 | try: | 216 | try: |
208 | logger.info('Sending topup status to AAA') | 217 | logger.info('Sending topup status to AAA') |
209 | logger.info(payload) | 218 | logger.info(payload) |
210 | r = requests.get(url, params=payload) | 219 | r = requests.get(url, params=payload) |
211 | except: | 220 | except: |
212 | logger.warning('Error sending topup status to AAA') | 221 | logger.warning('Error sending topup status to AAA') |
213 | 222 | ||
214 | try: | 223 | try: |
215 | # publish echi topup report ke redis | 224 | # publish echi topup report ke redis |
216 | echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO | 225 | echi_key = 'echi.topup_report.gw:' + BASE_CHIPINFO |
217 | 226 | ||
218 | redis_client.publish(echi_key + '.json', json.dumps(payload)) | 227 | redis_client.publish(echi_key + '.json', json.dumps(payload)) |
219 | 228 | ||
220 | echi_message = timestamp + ' - ' + response_code + ' - ' + message | 229 | echi_message = timestamp + ' - ' + response_code + ' - ' + message |
221 | redis_client.publish(echi_key + '.message', echi_message) | 230 | redis_client.publish(echi_key + '.message', echi_message) |
222 | except: | 231 | except: |
223 | logger.warning('Error publishing topup report to redis') | 232 | logger.warning('Error publishing topup report to redis') |
224 | 233 | ||
225 | def getIsDisableRedisKey(): | 234 | def getIsDisableRedisKey(): |
226 | return CHIPINFO + '.pulldisable' | 235 | return CHIPINFO + '.pulldisable' |
227 | 236 | ||
228 | def isPullEnable(): | 237 | def isPullEnable(): |
229 | redis_key = getIsDisableRedisKey() | 238 | redis_key = getIsDisableRedisKey() |
230 | result = 'FALSE' | 239 | result = 'FALSE' |
231 | 240 | ||
232 | try: | 241 | try: |
233 | result = redis_client.get(redis_key) | 242 | result = redis_client.get(redis_key) |
234 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) | 243 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) |
235 | except: | 244 | except: |
236 | return False | 245 | return False |
237 | 246 | ||
238 | if not result: | 247 | if not result: |
239 | return True | 248 | return True |
240 | 249 | ||
241 | return result == 'FALSE' | 250 | return result == 'FALSE' |
242 | 251 | ||
243 | def enablePull(): | 252 | def enablePull(): |
244 | logger.info('Enabling Pull on products {0}'.format(PRODUCTS)) | 253 | logger.info('Enabling Pull on products {0}'.format(PRODUCTS)) |
245 | redis_key = getIsDisableRedisKey() | 254 | redis_key = getIsDisableRedisKey() |
246 | try: | 255 | try: |
247 | redis_client.set(redis_key, 'FALSE') | 256 | redis_client.set(redis_key, 'FALSE') |
248 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) | 257 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) |
249 | except: | 258 | except: |
250 | return | 259 | return |
251 | 260 | ||
252 | def disablePull(): | 261 | def disablePull(): |
253 | global DISABLE_SEM | 262 | global DISABLE_SEM |
254 | global DISABLE_SEM_ON_TRX | 263 | global DISABLE_SEM_ON_TRX |
255 | 264 | ||
256 | logger.info('Disabling Pull') | 265 | logger.info('Disabling Pull') |
257 | redis_key = getIsDisableRedisKey() | 266 | redis_key = getIsDisableRedisKey() |
258 | try: | 267 | try: |
259 | redis_client.set(redis_key, 'TRUE') | 268 | redis_client.set(redis_key, 'TRUE') |
260 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) | 269 | redis_client.expire(redis_key, REDIS_DISABLE_PULL_TTL) |
261 | except: | 270 | except: |
262 | return | 271 | return |
263 | 272 | ||
264 | def adviceLastSN(requestId, modem): | 273 | def adviceLastSN(requestId, modem): |
265 | global DISABLE_SEM | 274 | global DISABLE_SEM |
266 | global LAST_SN | 275 | global LAST_SN |
267 | global TOPUP_USSD_TIMEOUT | 276 | global TOPUP_USSD_TIMEOUT |
268 | 277 | ||
269 | if not LAST_SN: | 278 | if not LAST_SN: |
270 | message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama' | 279 | message = 'Tidak ada trx sebelumnya untuk perbandingan SN. Silahkan bandingkan prev balance dengan trx berikutnya di chip yang sama' |
271 | pushTopupStatus(requestId, '68', message) | 280 | pushTopupStatus(requestId, '68', message) |
272 | DISABLE_SEM = 0 | 281 | DISABLE_SEM = 0 |
273 | return | 282 | return |
274 | 283 | ||
275 | ussd_command = xltunai.getHistoryUSSDCommand() | 284 | ussd_command = xltunai.getHistoryUSSDCommand() |
276 | 285 | ||
277 | logger.info(u'Executing advice {0}'.format(ussd_command)) | 286 | logger.info(u'Executing advice {0}'.format(ussd_command)) |
278 | try: | 287 | try: |
279 | response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) | 288 | response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) |
280 | 289 | ||
281 | message = response.message.strip() | 290 | message = response.message.strip() |
282 | logger.info(u'USSD response: {0}'.format(message)) | 291 | logger.info(u'USSD response: {0}'.format(message)) |
283 | 292 | ||
284 | lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message) | 293 | lastSNFromHistory = xltunai.getLastSNFromHistoryMessage(message) |
285 | 294 | ||
286 | if response.sessionActive: | 295 | if response.sessionActive: |
287 | response.cancel() | 296 | response.cancel() |
288 | 297 | ||
289 | if not lastSNFromHistory: | 298 | if not lastSNFromHistory: |
290 | if DISABLE_SEM: | 299 | if DISABLE_SEM: |
291 | logger.info('Failed to get last sn from history, retrying in 15 secs') | 300 | logger.info('Failed to get last sn from history, retrying in 15 secs') |
292 | sleep(15) | 301 | sleep(15) |
293 | adviceLastSN(requestid, modem) | 302 | adviceLastSN(requestid, modem) |
294 | 303 | ||
295 | elif lastSNFromHistory == 'P2P TRANSFER': | 304 | elif lastSNFromHistory == 'P2P TRANSFER': |
296 | topupMessage = "Topup gagal berdasarkan advice. Trx terakhir adalah P2P Transfer." | 305 | topupMessage = "Topup gagal berdasarkan advice. Trx terakhir adalah P2P Transfer." |
297 | pushTopupStatus(requestId, '40', topupMessage) | 306 | pushTopupStatus(requestId, '40', topupMessage) |
298 | DISABLE_SEM = 0 | 307 | DISABLE_SEM = 0 |
299 | 308 | ||
300 | elif lastSNFromHistory == LAST_SN: | 309 | elif lastSNFromHistory == LAST_SN: |
301 | topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message) | 310 | topupMessage = "Topup gagal berdasarkan advice. {0} = {1}. {2}".format(lastSNFromHistory, LAST_SN, message) |
302 | pushTopupStatus(requestId, '40', topupMessage) | 311 | pushTopupStatus(requestId, '40', topupMessage) |
303 | DISABLE_SEM = 0 | 312 | DISABLE_SEM = 0 |
304 | 313 | ||
305 | 314 | ||
306 | else: | 315 | else: |
307 | topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message) | 316 | topupMessage = "SN={0}; Topup berhasil berdasarkan advice. {1}".format(lastSNFromHistory, message) |
308 | LAST_SN = lastSNFromHistory | 317 | LAST_SN = lastSNFromHistory |
309 | pushTopupStatus(requestId, '00', topupMessage, True) | 318 | pushTopupStatus(requestId, '00', topupMessage, True) |
310 | DISABLE_SEM = 0 | 319 | DISABLE_SEM = 0 |
311 | 320 | ||
312 | except: | 321 | except: |
313 | message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength) | 322 | message = "USSD Error: Something wrong when executing USSD advice. Signal strength: {0}".format(modem.signalStrength) |
314 | logger.warning(message) | 323 | logger.warning(message) |
315 | pushTopupStatus(requestId, '68', message) | 324 | pushTopupStatus(requestId, '68', message) |
316 | 325 | ||
317 | sleep(60) | 326 | sleep(60) |
318 | adviceLastSN(requestId, modem) | 327 | adviceLastSN(requestId, modem) |
319 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) | 328 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) |
320 | return | 329 | return |
321 | 330 | ||
322 | 331 | ||
323 | 332 | ||
324 | def topupTask(task, modem): | 333 | def topupTask(task, modem): |
325 | global LAST_REQUEST_ID | 334 | global LAST_REQUEST_ID |
326 | global LAST_PRODUCT | 335 | global LAST_PRODUCT |
327 | 336 | ||
328 | if not task: | 337 | if not task: |
329 | return | 338 | return |
330 | 339 | ||
331 | if task['status'] != 'OK': | 340 | if task['status'] != 'OK': |
332 | return | 341 | return |
333 | 342 | ||
334 | LAST_REQUEST_ID = task['requestId'] | 343 | LAST_REQUEST_ID = task['requestId'] |
335 | LAST_PRODUCT = task['product'].upper() | 344 | LAST_PRODUCT = task['product'].upper() |
336 | 345 | ||
337 | redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId']) | 346 | redis_key = sate24.keyByRequestId(CHIPINFO, task['requestId']) |
338 | redis_client.set(redis_key, task) | 347 | redis_client.set(redis_key, task) |
339 | redis_client.expire(redis_key, REDIS_TTL) | 348 | redis_client.expire(redis_key, REDIS_TTL) |
340 | 349 | ||
341 | nominal = xltunai.getNominalFromProduct(task['product']) | 350 | nominal = xltunai.getNominalFromProduct(task['product']) |
342 | intl_destination = xltunai.toInternationalNumber(task['destination']) | 351 | intl_destination = xltunai.toInternationalNumber(task['destination']) |
343 | 352 | ||
344 | redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination) | 353 | redis_key = sate24.keyByNominalDestination(CHIPINFO, nominal, intl_destination) |
345 | #redis_client.sadd(redis_key, task['requestId']) | 354 | #redis_client.sadd(redis_key, task['requestId']) |
346 | try: | 355 | try: |
347 | redis_client.rpush(redis_key, task['requestId']) | 356 | redis_client.rpush(redis_key, task['requestId']) |
348 | except: | 357 | except: |
349 | redis_client.delete(redis_key) | 358 | redis_client.delete(redis_key) |
350 | redis_client.rpush(redis_key, task['requestId']) | 359 | redis_client.rpush(redis_key, task['requestId']) |
351 | finally: | 360 | finally: |
352 | redis_client.expire(redis_key, REDIS_TTL) | 361 | redis_client.expire(redis_key, REDIS_TTL) |
353 | 362 | ||
354 | #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator') | 363 | #pushTopupStatus(task['requestId'], '68', 'Siap mengirimkan trx ke operator') |
355 | 364 | ||
356 | message = 'Executing USSD' | 365 | message = 'Executing USSD' |
357 | response_code = '68' | 366 | response_code = '68' |
358 | 367 | ||
359 | ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX) | 368 | ussd_command = xltunai.getTopupUSSDCommand(task['destination'], task['product'], PIN_TRX) |
360 | 369 | ||
361 | logger.info(u'Executing {0}'.format(ussd_command)) | 370 | logger.info(u'Executing {0}'.format(ussd_command)) |
362 | try: | 371 | try: |
363 | response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) | 372 | response = modem.sendUssd(ussd_command, TOPUP_USSD_TIMEOUT) |
364 | 373 | ||
365 | message = response.message.strip() | 374 | message = response.message.strip() |
366 | logger.info(u'USSD response: {0}'.format(message)) | 375 | logger.info(u'USSD response: {0}'.format(message)) |
367 | 376 | ||
368 | response_code = xltunai.getResponseCodeByUSSDResponse(message) | 377 | response_code = xltunai.getResponseCodeByUSSDResponse(message) |
369 | 378 | ||
370 | if response.sessionActive: | 379 | if response.sessionActive: |
371 | response.cancel() | 380 | response.cancel() |
372 | 381 | ||
373 | except TimeoutException: | 382 | except TimeoutException: |
374 | message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) | 383 | message = "USSD Error: Timeout when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) |
375 | logger.warning(message) | 384 | logger.warning(message) |
376 | pushTopupStatus(task['requestId'], '68', message) | 385 | pushTopupStatus(task['requestId'], '68', message) |
377 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) | 386 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) |
378 | sleep(15) | 387 | sleep(15) |
379 | adviceLastSN(task['requestId'], modem) | 388 | adviceLastSN(task['requestId'], modem) |
380 | return | 389 | return |
381 | except: | 390 | except: |
382 | message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) | 391 | message = "USSD Error: Something wrong when executing USSD topup. Signal strength: {0}".format(modem.signalStrength) |
383 | logger.warning(message) | 392 | logger.warning(message) |
384 | pushTopupStatus(task['requestId'], '68', message) | 393 | pushTopupStatus(task['requestId'], '68', message) |
385 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) | 394 | #waitForResultSmsAfterUssdError(modem, task['requestId'], message) |
386 | sleep(15) | 395 | sleep(15) |
387 | adviceLastSN(task['requestId'], modem) | 396 | adviceLastSN(task['requestId'], modem) |
388 | return | 397 | return |
389 | 398 | ||
390 | DISABLE_SEM = DISABLE_SEM_ON_TRX | 399 | DISABLE_SEM = DISABLE_SEM_ON_TRX |
391 | pushTopupStatus(task['requestId'], response_code, message) | 400 | pushTopupStatus(task['requestId'], response_code, message) |
392 | 401 | ||
393 | def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''): | 402 | def waitForResultSmsAfterUssdError(modem, request_id, last_error_message = ''): |
394 | logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR)) | 403 | logger.info('Sleeping for {0} seconds after an USSD error'.format(SLEEP_AFTER_USSD_ERROR)) |
395 | sleep(SLEEP_AFTER_USSD_ERROR) | 404 | sleep(SLEEP_AFTER_USSD_ERROR) |
396 | 405 | ||
397 | redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' | 406 | redis_key = sate24.keyByRequestId(CHIPINFO, request_id) + '.response_code' |
398 | response_code = redis_client.get(redis_key) | 407 | response_code = redis_client.get(redis_key) |
399 | 408 | ||
400 | if response_code == '68' or response_code == None: | 409 | if response_code == '68' or response_code == None: |
401 | 410 | ||
402 | prev_balance = BALANCE | 411 | prev_balance = BALANCE |
403 | current_balance = checkBalance(modem, do_not_update = True, return_result = True) | 412 | current_balance = checkBalance(modem, do_not_update = True, return_result = True) |
404 | 413 | ||
405 | if current_balance == 0: | 414 | if current_balance == 0: |
406 | return | 415 | return |
407 | 416 | ||
408 | if current_balance < prev_balance: | 417 | if current_balance < prev_balance: |
409 | delta = prev_balance - current_balance | 418 | delta = prev_balance - current_balance |
410 | pushTopupStatus( | 419 | pushTopupStatus( |
411 | request_id, | 420 | request_id, |
412 | '00', | 421 | '00', |
413 | 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format( | 422 | 'Transaksi dianggap sukses karena saldo berkurang {0}. Last error message: {1}'.format( |
414 | delta, | 423 | delta, |
415 | last_error_message | 424 | last_error_message |
416 | ) | 425 | ) |
417 | ) | 426 | ) |
418 | else: | 427 | else: |
419 | pushTopupStatus( | 428 | pushTopupStatus( |
420 | request_id, | 429 | request_id, |
421 | '40', | 430 | '40', |
422 | 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message) | 431 | 'Transaksi dianggap gagal karena saldo tidak berkurang. Last error message: {0}'.format(last_error_message) |
423 | ) | 432 | ) |
424 | 433 | ||
425 | def _saveBalanceToRedis(balance_key, balance_value): | 434 | def _saveBalanceToRedis(balance_key, balance_value): |
426 | try: | 435 | try: |
427 | redis_client.set(balance_key, balance_value) | 436 | redis_client.set(balance_key, balance_value) |
428 | redis_client.expire(balance_key, 3600*24*60) | 437 | redis_client.expire(balance_key, 3600*24*60) |
429 | except: | 438 | except: |
430 | logger.warning('Failed to save balance to redis') | 439 | logger.warning('Failed to save balance to redis') |
431 | 440 | ||
432 | def saveBalanceToRedis(balance): | 441 | def saveBalanceToRedis(balance): |
433 | global BASE_CHIPINFO | 442 | global BASE_CHIPINFO |
434 | global CHIPINFO | 443 | global CHIPINFO |
435 | global MSISDN | 444 | global MSISDN |
436 | 445 | ||
437 | try: | 446 | try: |
438 | balance = int(balance) | 447 | balance = int(balance) |
439 | except ValueError: | 448 | except ValueError: |
440 | return | 449 | return |
441 | 450 | ||
442 | 451 | ||
443 | data = { | 452 | data = { |
444 | 'balance.gw:' + BASE_CHIPINFO: balance, | 453 | 'balance.gw:' + BASE_CHIPINFO: balance, |
445 | 'balance.gw:' + CHIPINFO: balance, | 454 | 'balance.gw:' + CHIPINFO: balance, |
446 | 'balance.gw:' + MSISDN: balance | 455 | 'balance.gw:' + MSISDN: balance |
447 | } | 456 | } |
448 | 457 | ||
449 | redis_pipe = redis_client.pipeline() | 458 | redis_pipe = redis_client.pipeline() |
450 | 459 | ||
451 | try: | 460 | try: |
452 | redis_pipe.mset(data) | 461 | redis_pipe.mset(data) |
453 | 462 | ||
454 | for k in data: | 463 | for k in data: |
455 | redis_pipe.expire(k, 3600 * 24 * 60) | 464 | redis_pipe.expire(k, 3600 * 24 * 60) |
456 | 465 | ||
457 | except: | 466 | except: |
458 | logger.warning('Failed to save balance to redis') | 467 | logger.warning('Failed to save balance to redis') |
459 | finally: | 468 | finally: |
460 | redis_pipe.execute() | 469 | redis_pipe.execute() |
461 | 470 | ||
462 | def saveSignalStrengthToRedis(value): | 471 | def saveSignalStrengthToRedis(value): |
463 | global BASE_CHIPINFO | 472 | global BASE_CHIPINFO |
464 | global CHIPINFO | 473 | global CHIPINFO |
465 | global MSISDN | 474 | global MSISDN |
466 | 475 | ||
467 | try: | 476 | try: |
468 | redis_pipe = redis_client.pipeline() | 477 | redis_pipe = redis_client.pipeline() |
469 | redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value) | 478 | redis_client.set('balance.gw:' + BASE_CHIPINFO + '.signal', value) |
470 | redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60) | 479 | redis_client.expire('balance.gw:' + BASE_CHIPINFO + '.signal', 15 * 60) |
471 | except: | 480 | except: |
472 | logger.warning('Failed to save signal strength to redis') | 481 | logger.warning('Failed to save signal strength to redis') |
473 | 482 | ||
474 | 483 | ||
475 | def pull(modem): | 484 | def pull(modem): |
476 | global PRODUCTS | 485 | global PRODUCTS |
477 | global PULL_COUNT | 486 | global PULL_COUNT |
478 | global BALANCE | 487 | global BALANCE |
479 | global DISABLE_SEM | 488 | global DISABLE_SEM |
480 | global MIN_SIGNAL_STRENGTH | 489 | global MIN_SIGNAL_STRENGTH |
481 | 490 | ||
482 | if not PRODUCTS: | 491 | if not PRODUCTS: |
483 | return | 492 | return |
484 | 493 | ||
485 | signalStrength = modem.signalStrength | 494 | signalStrength = modem.signalStrength |
486 | if signalStrength < MIN_SIGNAL_STRENGTH: | 495 | if signalStrength < MIN_SIGNAL_STRENGTH: |
487 | #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH)) | 496 | #logger.warn('Signal strength {0} < {1}, skipping pull'.format(signalStrength, MIN_SIGNAL_STRENGTH)) |
488 | return | 497 | return |
489 | 498 | ||
490 | pull_per_minute = 60 / PULL_INTERVAL | 499 | pull_per_minute = 60 / PULL_INTERVAL |
491 | 500 | ||
492 | PULL_COUNT += 1 | 501 | PULL_COUNT += 1 |
493 | if PULL_COUNT % (5 * pull_per_minute) == 0: | 502 | if PULL_COUNT % (5 * pull_per_minute) == 0: |
494 | checkBalance(modem) | 503 | checkBalance(modem) |
495 | sleep(15) | 504 | sleep(15) |
496 | PULL_COUNT = 0 | 505 | PULL_COUNT = 0 |
497 | 506 | ||
498 | if DISABLE_SEM > 0: | 507 | if DISABLE_SEM > 0: |
499 | logger.info('SEMAPHORE is still on, delaying pull') | 508 | logger.info('SEMAPHORE is still on, delaying pull') |
500 | DISABLE_SEM -= 1 | 509 | DISABLE_SEM -= 1 |
501 | return | 510 | return |
502 | 511 | ||
503 | if not isPullEnable(): | 512 | if not isPullEnable(): |
504 | return | 513 | return |
505 | 514 | ||
506 | r = None | 515 | r = None |
507 | url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS | 516 | url = AAA_HOST + '/pull?city=' + CITY + '&nom=' + PRODUCTS |
508 | try: | 517 | try: |
509 | r = requests.get(url) | 518 | r = requests.get(url) |
510 | except: | 519 | except: |
511 | logger.warning("Error requesting to AAA") | 520 | logger.warning("Error requesting to AAA") |
512 | return | 521 | return |
513 | 522 | ||
514 | if not r: | 523 | if not r: |
515 | return | 524 | return |
516 | 525 | ||
517 | task = sate24.parsePullMessage(r.text) | 526 | task = sate24.parsePullMessage(r.text) |
518 | 527 | ||
519 | if task['status'] == 'OK': | 528 | if task['status'] == 'OK': |
520 | 529 | ||
521 | logger.info('PULL ' + url + ' => ' + r.text) | 530 | logger.info('PULL ' + url + ' => ' + r.text) |
522 | publishAAATaskToRedis(task) | 531 | publishAAATaskToRedis(task) |
523 | 532 | ||
524 | if not checkBalance(modem) or BALANCE == 0: | 533 | if not checkBalance(modem) or BALANCE == 0: |
525 | pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance') | 534 | pushTopupStatus(task['requestId'], '91', 'Transaksi dibatalkan karena gagal check balance') |
526 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) | 535 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) |
527 | return | 536 | return |
528 | 537 | ||
529 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) | 538 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) |
530 | 539 | ||
531 | topupTask(task, modem) | 540 | topupTask(task, modem) |
532 | sleep(SLEEP_AFTER_TOPUP) | 541 | sleep(SLEEP_AFTER_TOPUP) |
533 | 542 | ||
534 | def publishAAATaskToRedis(task): | 543 | def publishAAATaskToRedis(task): |
535 | try: | 544 | try: |
536 | key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO | 545 | key = 'kimochi.aaa_pull.gw:' + BASE_CHIPINFO |
537 | plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination']; | 546 | plain_text = task['timestamp'] + ' - ' + task['member'] + ' isi ' + task['product'] + ' ke ' + task['destination']; |
538 | 547 | ||
539 | redis_client.publish(key + '.json', json.dumps(task)) | 548 | redis_client.publish(key + '.json', json.dumps(task)) |
540 | redis_client.publish(key + '.text', plain_text); | 549 | redis_client.publish(key + '.text', plain_text); |
541 | except: | 550 | except: |
542 | logger.warning('Error publishing kimochi') | 551 | logger.warning('Error publishing kimochi') |
543 | 552 | ||
544 | def publishMessageToRedis(): | 553 | def publishMessageToRedis(): |
545 | pass | 554 | pass |
546 | 555 | ||
547 | def pullLoop(modem): | 556 | def pullLoop(modem): |
548 | global TERMINATING | 557 | global TERMINATING |
549 | 558 | ||
550 | while True: | 559 | while True: |
551 | signalStrength = modem.signalStrength | 560 | signalStrength = modem.signalStrength |
552 | saveSignalStrengthToRedis(signalStrength) | 561 | saveSignalStrengthToRedis(signalStrength) |
553 | 562 | ||
554 | if TERMINATING: | 563 | if TERMINATING: |
555 | logger.info('Terminated by request signal') | 564 | logger.info('Terminated by request signal') |
556 | sys.exit(0) | 565 | sys.exit(0) |
557 | 566 | ||
558 | pull(modem) | 567 | pull(modem) |
559 | 568 | ||
560 | sleep(PULL_INTERVAL) | 569 | sleep(PULL_INTERVAL) |
561 | 570 | ||
562 | def checkSignal(modem): | 571 | def checkSignal(modem): |
563 | logger.info('Signal: {0}'.format(modem.signalStrength)) | 572 | logger.info('Signal: {0}'.format(modem.signalStrength)) |
564 | try: | 573 | try: |
565 | redis_client.set(CHIPINFO + '.signal', modem.signalStrength) | 574 | redis_client.set(CHIPINFO + '.signal', modem.signalStrength) |
566 | redis_client.expire(CHIPINFO + '.signal', 3600*24) | 575 | redis_client.expire(CHIPINFO + '.signal', 3600*24) |
567 | except: | 576 | except: |
568 | logger.warning("Can not save signal strength to redis") | 577 | logger.warning("Can not save signal strength to redis") |
569 | 578 | ||
570 | def checkAccount(modem): | 579 | def checkAccount(modem): |
571 | try: | 580 | try: |
572 | ussd_string = '*123*120*8*3#' | 581 | ussd_string = '*123*120*8*3#' |
573 | response = modem.sendUssd(ussd_string, 30) | 582 | response = modem.sendUssd(ussd_string, 30) |
574 | logger.info('Account Info: {0}'.format(response.message)) | 583 | logger.info('Account Info: {0}'.format(response.message)) |
575 | 584 | ||
576 | if response.sessionActive: | 585 | if response.sessionActive: |
577 | response.cancel() | 586 | response.cancel() |
578 | except: | 587 | except: |
579 | logger.warning('Error when requesting account info') | 588 | logger.warning('Error when requesting account info') |
580 | return False | 589 | return False |
581 | 590 | ||
582 | def checkBalance(modem, do_not_update = False, return_result = False): | 591 | def checkBalance(modem, do_not_update = False, return_result = False): |
583 | global BALANCE | 592 | global BALANCE |
584 | 593 | ||
585 | _BALANCE = 0 | 594 | _BALANCE = 0 |
586 | 595 | ||
587 | try: | 596 | try: |
588 | 597 | ||
589 | ussd_string = '*123*120#' | 598 | ussd_string = '*123*120#' |
590 | response = modem.sendUssd(ussd_string, 30) | 599 | response = modem.sendUssd(ussd_string, 30) |
591 | _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message) | 600 | _BALANCE = xltunai.getBalanceFromUSSDResponse(response.message) |
592 | 601 | ||
593 | if not do_not_update: | 602 | if not do_not_update: |
594 | BALANCE = _BALANCE | 603 | BALANCE = _BALANCE |
595 | saveBalanceToRedis(BALANCE) | 604 | saveBalanceToRedis(BALANCE) |
596 | 605 | ||
597 | logger.info('Balance: {0}'.format(_BALANCE)) | 606 | logger.info('Balance: {0}'.format(_BALANCE)) |
598 | if response.sessionActive: | 607 | if response.sessionActive: |
599 | response.cancel() | 608 | response.cancel() |
600 | 609 | ||
601 | if _BALANCE != 0 and _BALANCE < MIN_BALANCE: | 610 | if _BALANCE != 0 and _BALANCE < MIN_BALANCE: |
602 | logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE)) | 611 | logger.info('Disabling pull, balance {0} < {1}'.format(_BALANCE, MIN_BALANCE)) |
603 | disablePull() | 612 | disablePull() |
604 | 613 | ||
605 | except: | 614 | except: |
606 | logger.warning('Error when requesting BALANCE by USSD') | 615 | logger.warning('Error when requesting BALANCE by USSD') |
607 | if return_result: | 616 | if return_result: |
608 | return 0 | 617 | return 0 |
609 | else: | 618 | else: |
610 | return False | 619 | return False |
611 | 620 | ||
612 | try: | 621 | try: |
613 | redis_client.set(CHIPINFO + '.balance', BALANCE) | 622 | redis_client.set(CHIPINFO + '.balance', BALANCE) |
614 | except: | 623 | except: |
615 | logger.warning('Failed to save balance to redis') | 624 | logger.warning('Failed to save balance to redis') |
616 | 625 | ||
617 | if return_result: | 626 | if return_result: |
618 | return _BALANCE | 627 | return _BALANCE |
619 | else: | 628 | else: |
620 | return True | 629 | return True |
621 | 630 | ||
622 | def getPulsaInfo(modem): | 631 | def getPulsaInfo(modem): |
623 | global PULSA | 632 | global PULSA |
624 | global MASA_AKTIF | 633 | global MASA_AKTIF |
625 | 634 | ||
626 | try: | 635 | try: |
627 | ussd_string = "*123#" | 636 | ussd_string = "*123#" |
628 | response = modem.sendUssd(ussd_string) | 637 | response = modem.sendUssd(ussd_string) |
629 | 638 | ||
630 | message = response.message.strip() | 639 | message = response.message.strip() |
631 | logger.info('PULSA: {0}'.format(message)) | 640 | logger.info('PULSA: {0}'.format(message)) |
632 | if response.sessionActive: | 641 | if response.sessionActive: |
633 | response.cancel() | 642 | response.cancel() |
634 | 643 | ||
635 | PULSA = xltunai.getPulsaFromUssdResponseMessage(message) | 644 | PULSA = xltunai.getPulsaFromUssdResponseMessage(message) |
636 | MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message) | 645 | MASA_AKTIF =xltunai.getMasaAktifFromUssdResponseMessage(message) |
637 | logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF)) | 646 | logger.info('PULSA: {0} -- MASA AKTIF: {1}'.format(PULSA, MASA_AKTIF)) |
638 | 647 | ||
639 | return message | 648 | return message |
640 | 649 | ||
641 | except: | 650 | except: |
642 | logger.warning('Error when requesting pulsa info by USSD') | 651 | logger.warning('Error when requesting pulsa info by USSD') |
643 | return '' | 652 | return '' |
644 | 653 | ||
645 | def getSIMCardInfo(modem): | 654 | def getSIMCardInfo(modem): |
646 | try: | 655 | try: |
647 | ussd_string = xltunai.getSIMCardInfoUSSDCommand() | 656 | ussd_string = xltunai.getSIMCardInfoUSSDCommand() |
648 | response = modem.sendUssd(ussd_string) | 657 | response = modem.sendUssd(ussd_string) |
649 | 658 | ||
650 | message = response.message.strip() | 659 | message = response.message.strip() |
651 | logger.info('SIM INFO: {0}'.format(message)) | 660 | logger.info('SIM INFO: {0}'.format(message)) |
652 | if response.sessionActive: | 661 | if response.sessionActive: |
653 | response.cancel() | 662 | response.cancel() |
654 | 663 | ||
655 | return message | 664 | return message |
656 | 665 | ||
657 | except: | 666 | except: |
658 | logger.warning('Error when requesting SIM card info by USSD') | 667 | logger.warning('Error when requesting SIM card info by USSD') |
659 | return '' | 668 | return '' |
660 | 669 | ||
661 | def updateChipInfo(msisdn): | 670 | def updateChipInfo(msisdn): |
662 | global BASE_CHIPINFO | 671 | global BASE_CHIPINFO |
663 | global CHIPINFO | 672 | global CHIPINFO |
664 | global MSISDN | 673 | global MSISDN |
665 | 674 | ||
666 | MSISDN = msisdn | 675 | MSISDN = msisdn |
667 | if CHIPINFO.find(msisdn) == -1: | 676 | if CHIPINFO.find(msisdn) == -1: |
668 | CHIPINFO = BASE_CHIPINFO + '-' + msisdn | 677 | CHIPINFO = BASE_CHIPINFO + '-' + msisdn |
669 | 678 | ||
670 | logger.info('CHIPINFO: {0}'.format(CHIPINFO)) | 679 | logger.info('CHIPINFO: {0}'.format(CHIPINFO)) |
671 | 680 | ||
672 | def main(): | 681 | def main(): |
673 | global logger | 682 | global logger |
674 | 683 | ||
675 | log_format = '%(asctime)s %(levelname)s: %(message)s' | 684 | log_format = '%(asctime)s %(levelname)s: %(message)s' |
676 | 685 | ||
677 | logging.basicConfig(format=log_format, level=logging.INFO) | 686 | logging.basicConfig(format=log_format, level=logging.INFO) |
678 | logger = logging.getLogger(__name__) | 687 | logger = logging.getLogger(__name__) |
679 | 688 | ||
680 | logger_formatter = logging.Formatter(log_format) | 689 | logger_formatter = logging.Formatter(log_format) |
681 | logger_handler = TimedRotatingFileHandler('logs/log', when='midnight') | 690 | logger_handler = TimedRotatingFileHandler('logs/log', when='midnight') |
682 | logger_handler.setFormatter(logger_formatter) | 691 | logger_handler.setFormatter(logger_formatter) |
683 | logger.addHandler(logger_handler) | 692 | logger.addHandler(logger_handler) |
684 | 693 | ||
685 | requests_logger = logging.getLogger('requests') | 694 | requests_logger = logging.getLogger('requests') |
686 | requests_logger.setLevel(logging.WARNING) | 695 | requests_logger.setLevel(logging.WARNING) |
687 | 696 | ||
688 | logger.info('Initializing modem...') | 697 | logger.info('Initializing modem...') |
689 | 698 | ||
690 | modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms) | 699 | modem = GsmModem(PORT, BAUDRATE, smsReceivedCallbackFunc=handleSms) |
691 | modem.smsTextMode = True | 700 | modem.smsTextMode = True |
692 | modem.connect(PIN) | 701 | modem.connect(PIN) |
693 | 702 | ||
694 | logger.info('Waiting for network coverage...') | 703 | logger.info('Waiting for network coverage...') |
695 | modem.waitForNetworkCoverage(10) | 704 | modem.waitForNetworkCoverage(10) |
696 | 705 | ||
697 | logger.info('Modem ready') | 706 | logger.info('Modem ready') |
698 | 707 | ||
699 | getPulsaInfo(modem) | 708 | getPulsaInfo(modem) |
700 | sleep(2) | 709 | sleep(2) |
701 | 710 | ||
702 | simcard_info = getSIMCardInfo(modem) | 711 | simcard_info = getSIMCardInfo(modem) |
703 | msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info) | 712 | msisdn = xltunai.getMSISDNFromSIMCardInfo(simcard_info) |
704 | 713 | ||
705 | if not msisdn: | 714 | if not msisdn: |
706 | logger.warning('Gagal mendapatkan msisdn, terminating') | 715 | logger.warning('Gagal mendapatkan msisdn, terminating') |
707 | sleep(5) | 716 | sleep(5) |
708 | sys.exit(2) | 717 | sys.exit(2) |
709 | 718 | ||
710 | imsi = modem.imsi | 719 | imsi = modem.imsi |
711 | logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi)) | 720 | logger.info('MSISDN: {0} -- IMSI: {1}'.format(msisdn, imsi)) |
712 | 721 | ||
713 | updateChipInfo(msisdn) | 722 | updateChipInfo(msisdn) |
714 | saveSimCardInfo(imsi, msisdn) | 723 | saveSimCardInfo(imsi, msisdn) |
715 | 724 | ||
716 | sleep(2) | 725 | sleep(2) |
717 | 726 | ||
718 | saveSignalStrengthToRedis(modem.signalStrength) | 727 | saveSignalStrengthToRedis(modem.signalStrength) |
719 | 728 | ||
720 | logger.info('Process stored SMS') | 729 | logger.info('Process stored SMS') |
721 | try: | 730 | try: |
722 | modem.processStoredSms() | 731 | modem.processStoredSms() |
723 | except: | 732 | except: |
724 | logger.warning('Failed on Process stored SMS') | 733 | logger.warning('Failed on Process stored SMS') |
725 | 734 | ||
726 | logger.info('Delete stored SMS') | 735 | logger.info('Delete stored SMS') |
727 | try: | 736 | try: |
728 | modem.deleteMultipleStoredSms() | 737 | modem.deleteMultipleStoredSms() |
729 | except: | 738 | except: |
730 | #logger.warning('Failed on delete SMS') | 739 | #logger.warning('Failed on delete SMS') |
731 | pass | 740 | pass |
732 | 741 | ||
733 | sleep(2) | 742 | sleep(2) |
734 | 743 | ||
735 | checkAccount(modem) | 744 | checkAccount(modem) |
736 | sleep(5) | 745 | sleep(5) |
737 | 746 | ||
738 | enablePull() | 747 | enablePull() |
739 | 748 | ||
740 | checkBalance(modem) | 749 | checkBalance(modem) |
741 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) | 750 | sleep(SLEEP_BETWEEN_BALANCE_N_TOPUP) |
742 | 751 | ||
743 | pullLoop(modem) | 752 | pullLoop(modem) |
744 | logger.info('Waiting for SMS message...') | 753 | logger.info('Waiting for SMS message...') |
745 | try: | 754 | try: |
746 | modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal | 755 | modem.rxThread.join(2**31) # Specify a (huge) timeout so that it essentially blocks indefinitely, but still receives CTRL+C interrupt signal |
747 | finally: | 756 | finally: |
748 | modem.close(); | 757 | modem.close(); |
749 | 758 | ||
750 | def saveSimCardInfo(imsi, msisdn): | 759 | def saveSimCardInfo(imsi, msisdn): |
751 | logger.info('Save sim card info to redis') | 760 | logger.info('Save sim card info to redis') |
752 | 761 | ||
753 | data = { | 762 | data = { |
754 | 'gw': BASE_CHIPINFO, | 763 | 'gw': BASE_CHIPINFO, |
755 | 'imsi': imsi, | 764 | 'imsi': imsi, |
756 | 'msisdn': msisdn, | 765 | 'msisdn': msisdn, |
757 | 'pulsa': PULSA, | 766 | 'pulsa': PULSA, |
758 | 'masa_aktif': MASA_AKTIF | 767 | 'masa_aktif': MASA_AKTIF |
759 | } | 768 | } |
760 | 769 | ||
761 | json_data = json.dumps(data) | 770 | json_data = json.dumps(data) |
762 | 771 | ||
763 | with open('simcardinfo.txt', 'w') as f: | 772 | with open('simcardinfo.txt', 'w') as f: |
764 | f.write(json_data) | 773 | f.write(json_data) |
765 | f.closed | 774 | f.closed |
766 | 775 | ||
767 | 776 | ||
768 | map_data = { | 777 | map_data = { |
769 | BASE_CHIPINFO + '.simcardinfo': json_data, | 778 | BASE_CHIPINFO + '.simcardinfo': json_data, |
770 | 'simcardinfo.gw:' + BASE_CHIPINFO: json_data, | 779 | 'simcardinfo.gw:' + BASE_CHIPINFO: json_data, |
771 | 'simcardinfo.imsi:' + imsi: json_data, | 780 | 'simcardinfo.imsi:' + imsi: json_data, |
772 | 'simcardinfo.msisdn:' + msisdn: json_data | 781 | 'simcardinfo.msisdn:' + msisdn: json_data |
773 | } | 782 | } |
774 | 783 | ||
775 | logger.info(map_data) | 784 | logger.info(map_data) |
776 | 785 | ||
777 | redis_pipe = redis_client.pipeline() | 786 | redis_pipe = redis_client.pipeline() |
778 | 787 | ||
779 | try: | 788 | try: |
780 | redis_pipe.mset(map_data) | 789 | redis_pipe.mset(map_data) |
781 | 790 | ||
782 | for k in data: | 791 | for k in data: |
783 | redis_pipe.expire(k, 3600 * 24 * 60) | 792 | redis_pipe.expire(k, 3600 * 24 * 60) |
784 | 793 | ||
785 | except: | 794 | except: |
786 | logger.warning('Failed to save simcardinfo to redis') | 795 | logger.warning('Failed to save simcardinfo to redis') |
787 | finally: | 796 | finally: |
788 | redis_pipe.execute() | 797 | redis_pipe.execute() |
789 | 798 | ||
790 | if __name__ == '__main__': | 799 | if __name__ == '__main__': |
791 | pidfile = open('pid.txt', 'w') | 800 | pidfile = open('pid.txt', 'w') |
792 | pidfile.write(str(getpid())) | 801 | pidfile.write(str(getpid())) |
793 | pidfile.close() | 802 | pidfile.close() |
794 | 803 | ||
795 | # trap CTRL-C | 804 | # trap CTRL-C |
796 | signal.signal(signal.SIGINT, signalHandler) | 805 | signal.signal(signal.SIGINT, signalHandler) |
797 | # trap supervisor stop | 806 | # trap supervisor stop |
798 | signal.signal(signal.SIGTERM, signalHandler) | 807 | signal.signal(signal.SIGTERM, signalHandler) |
799 | 808 | ||
800 | main() | 809 | main() |
801 | 810 |