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