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