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