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