Commit f456f6ed9c1792b17ccbc65b335804a66ec78440

Authored by Adhidarma Hadiwinoto
1 parent 789684cdef
Exists in master

dontResendDelay

Showing 1 changed file with 8 additions and 4 deletions Inline Diff

1 var xmlrpc = require('xmlrpc'); 1 var xmlrpc = require('xmlrpc');
2 var url = require('url'); 2 var url = require('url');
3 var math = require('mathjs'); 3 var math = require('mathjs');
4 var winston = require('winston'); 4 var winston = require('winston');
5 var redis = require('redis'); 5 var redis = require('redis');
6 var resendDelay = require('./resend-delay.js'); 6 var resendDelay = require('./resend-delay.js');
7 var LRU = require('lru-cache'); 7 var LRU = require('lru-cache');
8 8
9 var aaa; 9 var aaa;
10 var logger; 10 var logger;
11 var config; 11 var config;
12 var _callbackReport; 12 var _callbackReport;
13 var redisClient; 13 var redisClient;
14 14
15 var taskHistory = LRU({max: 500, maxAge: 1000 * 3600 * 2}); 15 var taskHistory = LRU({max: 500, maxAge: 1000 * 3600 * 2});
16 16
17 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 17 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
18 18
19 function callbackReport(requestId, responseCode, message) { 19 function callbackReport(requestId, responseCode, message, dontResendDelay) {
20 if (responseCode != '68') { 20 if (responseCode != '68' || dontResendDelay) {
21 resendDelay.cancel(requestId); 21 resendDelay.cancel(requestId);
22 } else { 22 } else {
23 getTaskFromHistory(requestId, function(err, archivedTask) { 23 getTaskFromHistory(requestId, function(err, archivedTask) {
24 if (archivedTask) { 24 if (archivedTask) {
25 logger.verbose('DEBUG', {archivedTask: archivedTask}); 25 logger.verbose('DEBUG', {archivedTask: archivedTask});
26 resendDelay.register(archivedTask); 26 resendDelay.register(archivedTask);
27 } 27 }
28 }); 28 });
29 } 29 }
30 30
31 _callbackReport(requestId, responseCode, message); 31 _callbackReport(requestId, responseCode, message);
32 } 32 }
33 33
34 function createRedisClient(host, port) { 34 function createRedisClient(host, port) {
35 if (!host && !port) { 35 if (!host && !port) {
36 logger.info('Not creating redis client because unspecified host or port'); 36 logger.info('Not creating redis client because unspecified host or port');
37 return; 37 return;
38 } 38 }
39 39
40 try { 40 try {
41 redisClient = redis.createClient(port, host); 41 redisClient = redis.createClient(port, host);
42 } catch(err) { 42 } catch(err) {
43 logger.warn("Error creating redis client to " + host + ':' + port); 43 logger.warn("Error creating redis client to " + host + ':' + port);
44 } 44 }
45 } 45 }
46 46
47 function topupRequest(task) { 47 function topupRequest(task) {
48 aaa.insertTaskToMongoDb(task); 48 aaa.insertTaskToMongoDb(task);
49 49
50 getTaskFromHistory(task, function(err, archivedTask) { 50 getTaskFromHistory(task, function(err, archivedTask) {
51 putTaskToHistory(task); 51 putTaskToHistory(task);
52 52
53 if (archivedTask) { 53 if (archivedTask) {
54 logger.info('Task has been executed before, going to checkStatus', {task: task, archivedTask: archivedTask}); 54 logger.info('Task has been executed before, going to checkStatus', {task: task, archivedTask: archivedTask});
55 checkStatus(task); 55 checkStatus(task);
56 } else { 56 } else {
57 _topupRequest(task); 57 _topupRequest(task);
58 } 58 }
59 }); 59 });
60 } 60 }
61 61
62 function _topupRequest(task) { 62 function _topupRequest(task) {
63 63
64 if (!aaa.isTodayTrx(task)) {
65 callbackReport(task.requestId, '68', 'Terdeteksi transaksi beda hari, batal kirim ke supplier. Silahkan cek webreport', true);
66 return;
67 }
68
64 var partnerUrl = url.parse(config.h2h_out.partner); 69 var partnerUrl = url.parse(config.h2h_out.partner);
65 var clientOptions = { 70 var clientOptions = {
66 host: partnerUrl.hostname, 71 host: partnerUrl.hostname,
67 port: partnerUrl.port, 72 port: partnerUrl.port,
68 path: partnerUrl.pathname 73 path: partnerUrl.pathname
69 }; 74 };
70 logger.info('Preparing XMLRPC client options', {options: clientOptions});
71 75
72 var client; 76 var client;
73 if (partnerUrl.protocol == 'https:') { 77 if (partnerUrl.protocol == 'https:') {
74 client = xmlrpc.createSecureClient(clientOptions); 78 client = xmlrpc.createSecureClient(clientOptions);
75 } else { 79 } else {
76 client = xmlrpc.createClient(clientOptions); 80 client = xmlrpc.createClient(clientOptions);
77 } 81 }
78 82
79 var params = { 83 var params = {
80 MSISDN: config.h2h_out.userid, 84 MSISDN: config.h2h_out.userid,
81 REQUESTID: task['requestId'], 85 REQUESTID: task['requestId'],
82 PIN: config.h2h_out.password, 86 PIN: config.h2h_out.password,
83 NOHP: task['destination'], 87 NOHP: task['destination'],
84 NOM: task['remoteProduct'] 88 NOM: task['remoteProduct']
85 }; 89 };
86 90
87 var methodName = 'topUpRequest'; 91 var methodName = 'topUpRequest';
88 logger.info('Preparing XMLRPC client method', {methodname: methodName, params: params}); 92 logger.info('Preparing XMLRPC request', {methodname: methodName, params: params, partnerUrl: partnerUrl});
89 93
90 client.methodCall(methodName, [ params ], function (error, value) { 94 client.methodCall(methodName, [ params ], function (error, value) {
91 95
92 // Results of the method response 96 // Results of the method response
93 if (error) { 97 if (error) {
94 98
95 logger.warn('XMLRPC Client Error', {requestId: task['requestId'], errorMessage: error}); 99 logger.warn('XMLRPC Client Error', {requestId: task['requestId'], errorMessage: error});
96 callbackReport(task['requestId'], '91', 'Gangguan koneksi ke suplier: ' + error); 100 callbackReport(task['requestId'], '91', 'Gangguan koneksi ke suplier: ' + error);
97 return; 101 return;
98 } 102 }
99 103
100 logger.info('Got XMLRPC response from partner for', {response_method: methodName, response_message: value}); 104 logger.info('Got XMLRPC response from partner for', {response_method: methodName, response_message: value});
101 105
102 if (value['RESPONSECODE'] == '94') { 106 if (value['RESPONSECODE'] == '94') {
103 logger.info('Change RC 94 to 68'); 107 logger.info('Change RC 94 to 68');
104 value['RESPONSECODE'] = '68'; 108 value['RESPONSECODE'] = '68';
105 } 109 }
106 110
107 if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') { 111 if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') {
108 value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE']; 112 value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE'];
109 } 113 }
110 114
111 callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']); 115 callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']);
112 }); 116 });
113 } 117 }
114 118
115 function createServer() { 119 function createServer() {
116 120
117 logger.info('Creating XML-RPC server on port ' + config.h2h_out.listen_port); 121 logger.info('Creating XML-RPC server on port ' + config.h2h_out.listen_port);
118 var serverOptions = { 122 var serverOptions = {
119 port: config.h2h_out.listen_port 123 port: config.h2h_out.listen_port
120 }; 124 };
121 125
122 var server = xmlrpc.createServer(serverOptions); 126 var server = xmlrpc.createServer(serverOptions);
123 127
124 server.on('NotFound', function (method, params) { 128 server.on('NotFound', function (method, params) {
125 logger.warn('Unknown method recevied on XMLRPC server', {xmlrpc_method: method, xmlrpc_params: params}); 129 logger.warn('Unknown method recevied on XMLRPC server', {xmlrpc_method: method, xmlrpc_params: params});
126 }); 130 });
127 131
128 server.on('topUpReport', function (err, params, callback) { 132 server.on('topUpReport', function (err, params, callback) {
129 133
130 logger.info('Got XMLRPC topUpReport request from partner', {xmlrpc_method: 'topUpReport', xmlrpc_params: params}); 134 logger.info('Got XMLRPC topUpReport request from partner', {xmlrpc_method: 'topUpReport', xmlrpc_params: params});
131 135
132 var paramscount = params.length; 136 var paramscount = params.length;
133 for (var i = 0; i < paramscount; i++) { 137 for (var i = 0; i < paramscount; i++) {
134 var value = params[i]; 138 var value = params[i];
135 139
136 if (value['RESPONSECODE'] == '94') { 140 if (value['RESPONSECODE'] == '94') {
137 logger.info('Change RC 94 to 68'); 141 logger.info('Change RC 94 to 68');
138 value['RESPONSECODE'] = '68'; 142 value['RESPONSECODE'] = '68';
139 } 143 }
140 144
141 if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') { 145 if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') {
142 value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE']; 146 value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE'];
143 } 147 }
144 148
145 callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']); 149 callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']);
146 } 150 }
147 151
148 callback(null, 'ACK REPORT OK'); 152 callback(null, 'ACK REPORT OK');
149 }) 153 })
150 154
151 } 155 }
152 156
153 function getBalanceFromMessage(message, balance_regex) { 157 function getBalanceFromMessage(message, balance_regex) {
154 if (!balance_regex) { 158 if (!balance_regex) {
155 if (config && config.globals && config.globals.balance_regex) { 159 if (config && config.globals && config.globals.balance_regex) {
156 balance_regex = config.globals.balance_regex; 160 balance_regex = config.globals.balance_regex;
157 } 161 }
158 } 162 }
159 163
160 if (!balance_regex) { 164 if (!balance_regex) {
161 return; 165 return;
162 } 166 }
163 167
164 try { 168 try {
165 var re = new RegExp(balance_regex); 169 var re = new RegExp(balance_regex);
166 var matches = message.match(re); 170 var matches = message.match(re);
167 171
168 var result = matches[1]; 172 var result = matches[1];
169 result = result.replace(/\./g, ''); 173 result = result.replace(/\./g, '');
170 result = result.replace(/,/g, ''); 174 result = result.replace(/,/g, '');
171 175
172 176
173 return Number(result); 177 return Number(result);
174 } 178 }
175 catch(err) { 179 catch(err) {
176 return; 180 return;
177 } 181 }
178 } 182 }
179 183
180 function updateBalance(message) { 184 function updateBalance(message) {
181 var balance = getBalanceFromMessage(message); 185 var balance = getBalanceFromMessage(message);
182 if (balance) { 186 if (balance) {
183 logger.info('Balance: ' + balance); 187 logger.info('Balance: ' + balance);
184 aaa.updateBalance(balance); 188 aaa.updateBalance(balance);
185 } 189 }
186 } 190 }
187 191
188 function checkStatus(task) { 192 function checkStatus(task) {
189 var partnerUrl = url.parse(config.h2h_out.partner); 193 var partnerUrl = url.parse(config.h2h_out.partner);
190 var clientOptions = { 194 var clientOptions = {
191 host: partnerUrl.hostname 195 host: partnerUrl.hostname
192 , port: partnerUrl.port 196 , port: partnerUrl.port
193 , path: partnerUrl.pathname 197 , path: partnerUrl.pathname
194 }; 198 };
195 logger.info('XMLRPC client options:'); 199 logger.info('XMLRPC client options:');
196 logger.info(clientOptions); 200 logger.info(clientOptions);
197 201
198 var client; 202 var client;
199 if (partnerUrl.protocol == 'https:') { 203 if (partnerUrl.protocol == 'https:') {
200 client = xmlrpc.createSecureClient(clientOptions); 204 client = xmlrpc.createSecureClient(clientOptions);
201 } else { 205 } else {
202 client = xmlrpc.createClient(clientOptions); 206 client = xmlrpc.createClient(clientOptions);
203 } 207 }
204 208
205 var methodName = 'topUpInquiry'; 209 var methodName = 'topUpInquiry';
206 210
207 var params = { 211 var params = {
208 REQUESTID: task['requestId'], 212 REQUESTID: task['requestId'],
209 MSISDN: config.h2h_out.userid, 213 MSISDN: config.h2h_out.userid,
210 PIN: config.h2h_out.password, 214 PIN: config.h2h_out.password,
211 NOHP: task['destination'] 215 NOHP: task['destination']
212 }; 216 };
213 217
214 logger.info('Requesting topUpInquiry', {params: params}); 218 logger.info('Requesting topUpInquiry', {params: params});
215 219
216 client.methodCall(methodName, [ params ], function (error, value) { 220 client.methodCall(methodName, [ params ], function (error, value) {
217 // Results of the method response 221 // Results of the method response
218 if (error) { 222 if (error) {
219 logger.warn('Error requesting topUpInquiry: ', {err: error, params: params}); 223 logger.warn('Error requesting topUpInquiry: ', {err: error, params: params});
220 callbackReport(task.requestId, '68', 'Error requesting topUpInquiry: ' + error); 224 callbackReport(task.requestId, '68', 'Error requesting topUpInquiry: ' + error);
221 return; 225 return;
222 } 226 }
223 logger.info('Method response for \'' + methodName, {response: value}); 227 logger.info('Method response for \'' + methodName, {response: value});
224 228
225 callbackReport(task.requestId, value['RESPONSECODE'], value['MESSAGE']); 229 callbackReport(task.requestId, value['RESPONSECODE'], value['MESSAGE']);
226 }); 230 });
227 } 231 }
228 232
229 function start(options) { 233 function start(options) {
230 if (!options) { 234 if (!options) {
231 console.log('Undefined options, terminating....'); 235 console.log('Undefined options, terminating....');
232 process.exit(1); 236 process.exit(1);
233 } 237 }
234 238
235 if (options.config) { 239 if (options.config) {
236 config = options.config; 240 config = options.config;
237 } else { 241 } else {
238 console.log('Undefined options.config, terminating....') 242 console.log('Undefined options.config, terminating....')
239 process.exit(1); 243 process.exit(1);
240 } 244 }
241 245
242 if (options.aaa) { 246 if (options.aaa) {
243 aaa = options.aaa; 247 aaa = options.aaa;
244 _callbackReport = options.aaa.callbackReportWithPushToMongoDb; 248 _callbackReport = options.aaa.callbackReportWithPushToMongoDb;
245 } else { 249 } else {
246 console.log('Undefined options.aaa, terminating....') 250 console.log('Undefined options.aaa, terminating....')
247 process.exit(1); 251 process.exit(1);
248 } 252 }
249 253
250 if (options && options.logger) { 254 if (options && options.logger) {
251 logger = options.logger; 255 logger = options.logger;
252 } else { 256 } else {
253 logger = new winston.Logger({ 257 logger = new winston.Logger({
254 transports: [ 258 transports: [
255 new (winston.transports.Console)() 259 new (winston.transports.Console)()
256 ] 260 ]
257 }); 261 });
258 } 262 }
259 263
260 createRedisClient(config.globals.redis_host, config.globals.redis_port); 264 createRedisClient(config.globals.redis_host, config.globals.redis_port);
261 createServer(); 265 createServer();
262 266
263 resendDelay.init({ 267 resendDelay.init({
264 config: config, 268 config: config,
265 topupRequest: topupRequest, 269 topupRequest: topupRequest,
266 logger: logger 270 logger: logger
267 }); 271 });
268 } 272 }
269 273
270 function parseSN(message, _config) { 274 function parseSN(message, _config) {
271 275
272 if (!_config) { 276 if (!_config) {
273 _config = config; 277 _config = config;
274 } 278 }
275 279
276 var sn_regex = new RegExp(_config.h2h_out.sn_pattern); 280 var sn_regex = new RegExp(_config.h2h_out.sn_pattern);
277 var sn_match = message.match(sn_regex); 281 var sn_match = message.match(sn_regex);
278 282
279 if (sn_match <= 0) { 283 if (sn_match <= 0) {
280 logger.info('SN Not found: ' + message); 284 logger.info('SN Not found: ' + message);
281 return ''; 285 return '';
282 } 286 }
283 287
284 var match_index = 0; 288 var match_index = 0;
285 if (_config.h2h_out.sn_match_index) { 289 if (_config.h2h_out.sn_match_index) {
286 match_index = Number(_config.h2h_out.sn_match_index); 290 match_index = Number(_config.h2h_out.sn_match_index);
287 } 291 }
288 292
289 var sn = sn_match[match_index]; 293 var sn = sn_match[match_index];
290 294
291 if (_config.h2h_out.sn_remove_whitespace) { 295 if (_config.h2h_out.sn_remove_whitespace) {
292 sn = sn.replace(/\s/g, ''); 296 sn = sn.replace(/\s/g, '');
293 } 297 }
294 298
295 var sn_remove_patterns = []; 299 var sn_remove_patterns = [];
296 if (_config.h2h_out.sn_remove_patterns && _config.h2h_out.sn_remove_patterns_separator) { 300 if (_config.h2h_out.sn_remove_patterns && _config.h2h_out.sn_remove_patterns_separator) {
297 sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator); 301 sn_remove_patterns = _config.h2h_out.sn_remove_patterns.split(_config.h2h_out.sn_remove_patterns_separator);
298 } 302 }
299 var count = sn_remove_patterns.length; 303 var count = sn_remove_patterns.length;
300 304
301 for(var i = 0; i < count; i++) { 305 for(var i = 0; i < count; i++) {
302 306
303 //sn = sn.replace(sn_remove_patterns[i], ''); 307 //sn = sn.replace(sn_remove_patterns[i], '');
304 308
305 var re = new RegExp(sn_remove_patterns[i], 'g'); 309 var re = new RegExp(sn_remove_patterns[i], 'g');
306 sn = sn.replace(re, ''); 310 sn = sn.replace(re, '');
307 } 311 }
308 312
309 //sn = paddingSN(sn, _config); 313 //sn = paddingSN(sn, _config);
310 314
311 return sn.trim(); 315 return sn.trim();
312 } 316 }
313 317
314 function getTaskKey(task, chipInfo) { 318 function getTaskKey(task, chipInfo) {
315 var requestId; 319 var requestId;
316 320
317 if (typeof task === 'string') { 321 if (typeof task === 'string') {
318 requestId = task; 322 requestId = task;
319 } else { 323 } else {
320 try { 324 try {
321 requestId = task.requestId; 325 requestId = task.requestId;
322 } 326 }
323 catch(e) { 327 catch(e) {
324 logger.warn('Something wrong', {task: task}); 328 logger.warn('Something wrong', {task: task});
325 console.trace('Cekidot'); 329 console.trace('Cekidot');
326 process.exit(1); 330 process.exit(1);
327 } 331 }
328 332
329 } 333 }
330 334
331 if (!chipInfo && config && config.globals && config.globals.gateway_name) { 335 if (!chipInfo && config && config.globals && config.globals.gateway_name) {
332 chipInfo = config.globals.gateway_name; 336 chipInfo = config.globals.gateway_name;
333 } 337 }
334 338
335 return chipInfo + '.hitachi.rid:' + requestId; 339 return chipInfo + '.hitachi.rid:' + requestId;
336 } 340 }
337 341
338 342
339 function putTaskToHistory(task, cb) { 343 function putTaskToHistory(task, cb) {
340 var key = getTaskKey(task, config.globals.gateway_name); 344 var key = getTaskKey(task, config.globals.gateway_name);
341 logger.verbose('Saving task to history LRU', {key: key, task: task}); 345 logger.verbose('Saving task to history LRU', {key: key, task: task});
342 346
343 try { 347 try {
344 taskHistory.set(key, JSON.parse(JSON.stringify(task))); 348 taskHistory.set(key, JSON.parse(JSON.stringify(task)));
345 } catch (e) { } 349 } catch (e) { }
346 350
347 putTaskToRedis(task, cb); 351 putTaskToRedis(task, cb);
348 } 352 }
349 353
350 function putTaskToRedis(task, cb) { 354 function putTaskToRedis(task, cb) {
351 if (!redisClient) { 355 if (!redisClient) {
352 logger.verbose('Not saving to redis because of undefined redisClient') 356 logger.verbose('Not saving to redis because of undefined redisClient')
353 if (cb) { cb(); } 357 if (cb) { cb(); }
354 return; 358 return;
355 } 359 }
356 360
357 var key = getTaskKey(task, config.globals.gateway_name); 361 var key = getTaskKey(task, config.globals.gateway_name);
358 logger.verbose('Saving task to redis', {key: key, task: task}); 362 logger.verbose('Saving task to redis', {key: key, task: task});
359 363
360 redisClient.set(key, JSON.stringify(task), function() { 364 redisClient.set(key, JSON.stringify(task), function() {
361 redisClient.expire(key, 3600*24*30); 365 redisClient.expire(key, 3600*24*30);
362 if (cb) { 366 if (cb) {
363 cb(); 367 cb();
364 } 368 }
365 }); 369 });
366 } 370 }
367 371
368 function getTaskFromHistory(task, cb) { 372 function getTaskFromHistory(task, cb) {
369 logger.verbose('Getting task from history', {task: task}); 373 logger.verbose('Getting task from history', {task: task});
370 var key = getTaskKey(task, config.globals.gateway_name); 374 var key = getTaskKey(task, config.globals.gateway_name);
371 var archive = taskHistory.get(key); 375 var archive = taskHistory.get(key);
372 376
373 if (archive) { 377 if (archive) {
374 if (cb) { cb(null, archive); } 378 if (cb) { cb(null, archive); }
375 } 379 }
376 else { 380 else {
377 getTaskFromRedis(task, cb); 381 getTaskFromRedis(task, cb);
378 } 382 }
379 } 383 }
380 384
381 function getTaskFromRedis(task, cb) { 385 function getTaskFromRedis(task, cb) {
382 if (!redisClient) { 386 if (!redisClient) {
383 if (cb) { cb(null, null); } 387 if (cb) { cb(null, null); }
384 return; 388 return;
385 } 389 }
386 390
387 var key = getTaskKey(task, config.globals.gateway_name); 391 var key = getTaskKey(task, config.globals.gateway_name);
388 redisClient.get(key, function(err, result) { 392 redisClient.get(key, function(err, result) {
389 if (err) { 393 if (err) {
390 logger.warn('Error retrieving task from redis', {err: err}); 394 logger.warn('Error retrieving task from redis', {err: err});
391 cb(err, null); 395 cb(err, null);
392 return; 396 return;
393 } 397 }
394 398
395 var task; 399 var task;
396 try { 400 try {
397 task = JSON.parse(result); 401 task = JSON.parse(result);
398 } 402 }
399 catch(e) { 403 catch(e) {
400 logger.warn('Exception on parsing redis result as a json', {err: e}); 404 logger.warn('Exception on parsing redis result as a json', {err: e});
401 } 405 }
402 406
403 cb(null, task); 407 cb(null, task);
404 }) 408 })
405 } 409 }
406 410
407 exports.start = start; 411 exports.start = start;
408 exports.topupRequest = topupRequest; 412 exports.topupRequest = topupRequest;
409 exports.getBalanceFromMessage = getBalanceFromMessage; 413 exports.getBalanceFromMessage = getBalanceFromMessage;
410 exports.checkStatus = checkStatus; 414 exports.checkStatus = checkStatus;