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