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