Commit 0e6fd5e929ac232a9dd12dea1e55ec0ad8332d2c

Authored by Adhidarma Hadiwinoto
1 parent 4ee545787f
Exists in master

responseObject

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

1 var xml2js = require('xml2js'); 1 var xml2js = require('xml2js');
2 var request = require('request'); 2 var request = require('request');
3 var http = require('http'); 3 var http = require('http');
4 var redis = require('redis'); 4 var redis = require('redis');
5 var resendDelay = require('sate24/resend-delay.js'); 5 var resendDelay = require('sate24/resend-delay.js');
6 var LRU = require('lru-cache'); 6 var LRU = require('lru-cache');
7 7
8 var aaa; 8 var aaa;
9 var _callbackReport; 9 var _callbackReport;
10 var config; 10 var config;
11 var logger; 11 var logger;
12 var redisClient; 12 var redisClient;
13 13
14 var xmlBuilder = new xml2js.Builder(); 14 var xmlBuilder = new xml2js.Builder();
15 var taskHistory = LRU({max: 500, maxAge: 1000 * 3600 * 2}); 15 var taskHistory = LRU({max: 500, maxAge: 1000 * 3600 * 2});
16 var alreadyPending = LRU({max: 500, maxAge: 1000 * 3600 * 2}); 16 var alreadyPending = LRU({max: 500, maxAge: 1000 * 3600 * 2});
17 17
18 function start(options) { 18 function start(options) {
19 if (!options) { 19 if (!options) {
20 console.log('Undefined options, terminating....'); 20 console.log('Undefined options, terminating....');
21 process.exit(1); 21 process.exit(1);
22 } 22 }
23 23
24 if (options.config) { 24 if (options.config) {
25 config = options.config; 25 config = options.config;
26 } else { 26 } else {
27 console.log('Undefined options.config, terminating....') 27 console.log('Undefined options.config, terminating....')
28 process.exit(1); 28 process.exit(1);
29 } 29 }
30 30
31 if (options.aaa) { 31 if (options.aaa) {
32 aaa = options.aaa; 32 aaa = options.aaa;
33 _callbackReport = options.aaa.callbackReportWithPushToMongoDb; 33 _callbackReport = options.aaa.callbackReportWithPushToMongoDb;
34 } else { 34 } else {
35 console.log('Undefined options.aaa, terminating....') 35 console.log('Undefined options.aaa, terminating....')
36 process.exit(1); 36 process.exit(1);
37 } 37 }
38 38
39 if (options && options.logger) { 39 if (options && options.logger) {
40 logger = options.logger; 40 logger = options.logger;
41 } else { 41 } else {
42 console.log('Undefined options.logger, terminating....') 42 console.log('Undefined options.logger, terminating....')
43 process.exit(1); 43 process.exit(1);
44 } 44 }
45 45
46 createRedisClient(config.globals.redis_host, config.globals.redis_port); 46 createRedisClient(config.globals.redis_host, config.globals.redis_port);
47 createServer(); 47 createServer();
48 48
49 resendDelay.init({ 49 resendDelay.init({
50 config: config, 50 config: config,
51 topupRequest: topupStatus, 51 topupRequest: topupStatus,
52 logger: logger 52 logger: logger
53 }); 53 });
54 } 54 }
55 55
56 function topupRequest(task) { 56 function topupRequest(task) {
57 aaa.insertTaskToMongoDb(task); 57 aaa.insertTaskToMongoDb(task);
58 58
59 getTaskFromHistory(task, function(err, archivedTask) { 59 getTaskFromHistory(task, function(err, archivedTask) {
60 putTaskToHistory(task); 60 putTaskToHistory(task);
61 61
62 if (archivedTask) { 62 if (archivedTask) {
63 logger.info('Task has been executed before, going to checkStatus', {task: task, archivedTask: archivedTask}); 63 logger.info('Task has been executed before, going to checkStatus', {task: task, archivedTask: archivedTask});
64 topupStatus(task); 64 topupStatus(task);
65 } else { 65 } else {
66 _topupRequest(task); 66 _topupRequest(task);
67 } 67 }
68 }); 68 });
69 } 69 }
70 70
71 function _topupRequest(task) { 71 function _topupRequest(task) {
72 72
73 var payload = composeTopupMessage( 73 var payload = composeTopupMessage(
74 config.h2h_out.pin, 74 config.h2h_out.pin,
75 task.remoteProduct, 75 task.remoteProduct,
76 task.destination, 76 task.destination,
77 task.requestId 77 task.requestId
78 ); 78 );
79 79
80 var reqOpts = { 80 var reqOpts = {
81 url: config.h2h_out.partner, 81 url: config.h2h_out.partner,
82 method: "POST", 82 method: "POST",
83 body: payload, 83 body: payload,
84 headers: { 84 headers: {
85 'Content-Type': 'text/xml', 85 'Content-Type': 'text/xml',
86 } 86 }
87 }; 87 };
88 88
89 logger.verbose('Requesting TOPUP to partner', {reqOpts: reqOpts, payload: payload}); 89 logger.verbose('Requesting TOPUP to partner', {reqOpts: reqOpts, payload: payload});
90 request(reqOpts, function (err, response, body) { 90 request(reqOpts, function (err, response, body) {
91 if (err) { 91 if (err) {
92 var msg = 'Error requesting TOPUP to partner: ' + err; 92 var msg = 'Error requesting TOPUP to partner: ' + err;
93 logger.warn(msg, {task: task, err: err}); 93 logger.warn(msg, {task: task, err: err});
94 callbackReport(task.requestId, '68', msg); 94 callbackReport(task.requestId, '68', msg);
95 return; 95 return;
96 } 96 }
97 97
98 logger.verbose('Got a direct response from TOPUP', {response: body, task: task}); 98 logger.verbose('Got a direct response from TOPUP', {response: body, task: task});
99 topupResponseHandler(body, task.requestId, callbackReport); 99 topupResponseHandler(body, task.requestId, callbackReport);
100 }); 100 });
101 } 101 }
102 102
103 function topupStatus(task) { 103 function topupStatus(task) {
104 var payload = composeTopupStatusMessage( 104 var payload = composeTopupStatusMessage(
105 config.h2h_out.pin, 105 config.h2h_out.pin,
106 task.requestId 106 task.requestId
107 ); 107 );
108 108
109 var reqOpts = { 109 var reqOpts = {
110 url: config.h2h_out.partner, 110 url: config.h2h_out.partner,
111 method: "POST", 111 method: "POST",
112 body: payload, 112 body: payload,
113 headers: { 113 headers: {
114 'Content-Type': 'text/xml', 114 'Content-Type': 'text/xml',
115 } 115 }
116 }; 116 };
117 117
118 logger.verbose('Requesting TOPUPSTATUS to partner', {reqOpts: reqOpts, payload: payload}); 118 logger.verbose('Requesting TOPUPSTATUS to partner', {reqOpts: reqOpts, payload: payload});
119 request(reqOpts, function (err, response, body) { 119 request(reqOpts, function (err, response, body) {
120 if (err) { 120 if (err) {
121 var msg = 'Error requesting TOPUPSTATUS to partner: ' + err; 121 var msg = 'Error requesting TOPUPSTATUS to partner: ' + err;
122 logger.warn(msg, {task: task, err: err}); 122 logger.warn(msg, {task: task, err: err});
123 callbackReport(task.requestId, '68', msg); 123 callbackReport(task.requestId, '68', msg);
124 return; 124 return;
125 } 125 }
126 126
127 logger.verbose('Got a direct response from TOPUPSTATUS', {response: body, task: task}); 127 logger.verbose('Got a direct response from TOPUPSTATUS', {response: body, task: task});
128 topupResponseHandler(body, task.requestId, callbackReport); 128 topupResponseHandler(body, task.requestId, callbackReport);
129 }); 129 });
130 } 130 }
131 131
132 function topupResponseHandler(xmlResponse, _requestId, cb) { 132 function topupResponseHandler(xmlResponse, _requestId, cb) {
133 var xmlParser = xml2js.parseString; 133 var xmlParser = xml2js.parseString;
134 xmlParser(xmlResponse, function(err, data) { 134 xmlParser(xmlResponse, function(err, data) {
135 var msg; 135 var msg;
136 var requestId; 136 var requestId;
137 var rc = '68'; 137 var rc = '68';
138 138
139 if (_requestId) { 139 if (_requestId) {
140 requestId = _requestId; 140 requestId = _requestId;
141 } 141 }
142 142
143 if (err) { 143 if (err) {
144 msg = 'Error parsing xml response: ' + err; 144 msg = 'Error parsing xml response: ' + err;
145 145
146 if (logger) { 146 if (logger) {
147 logger.warn(msg, {err: err, response: xmlResponse, task: task}); 147 logger.warn(msg, {err: err, response: xmlResponse, task: task});
148 } else { 148 } else {
149 console.log(msg); 149 console.log(msg);
150 } 150 }
151 } else { 151 } else {
152 152
153 logger.info('Response parsed', {data: data}); 153 logger.info('Response parsed', {data: data});
154 154
155 msg = getMessageFromResponse(data); 155 msg = getMessageFromResponse(data);
156 if (!msg) { 156 if (!msg) {
157 msg = 'Unknown message'; 157 msg = 'Unknown message';
158 } 158 }
159 159
160 var status = getStatusFromResponse(data); 160 var status = getStatusFromResponse(data);
161 if (status == '0') { 161 if (status == '0') {
162 162
163 rc = '00'; 163 rc = '00';
164 msg = modifyMessageWithSn(msg); 164 msg = modifyMessageWithSn(msg);
165 logger.verbose('Modify message on success message', {msg: msg}); 165 logger.verbose('Modify message on success message', {msg: msg});
166 166
167 } else if (status == '1') { 167 } else if (status == '1') {
168 rc = '68'; 168 rc = '68';
169 } else if (status == '2') { 169 } else if (status == '2') {
170 rc = '40'; 170 rc = '40';
171 } else if (status == '3') { 171 } else if (status == '3') {
172 rc = '40'; 172 rc = '40';
173 } else { 173 } else {
174 rc = '68'; 174 rc = '68';
175 msg = msg + '. Status is not valid ' + status; 175 msg = msg + '. Status is not valid ' + status;
176 } 176 }
177 177
178 var requestIdFromData = getRequestIdFromResponse(data); 178 var requestIdFromData = getRequestIdFromResponse(data);
179 if (requestIdFromData) { 179 if (requestIdFromData) {
180 requestId = requestIdFromData; 180 requestId = requestIdFromData;
181 } 181 }
182 } 182 }
183 183
184 cb(requestId, rc, msg, xmlResponse) 184 cb(requestId, rc, msg, xmlResponse)
185 }); 185 });
186 } 186 }
187 187
188 function callbackReport(requestId, responseCode, msg, rawResponse, dontResendDelay) { 188 function callbackReport(requestId, responseCode, msg, rawResponse, dontResendDelay) {
189 if (!requestId) { 189 if (!requestId) {
190 logger.warn('Undefined requestId, not sending callbackReport', {rc: responseCode, msg: msg, rawResponse: rawResponse}); 190 logger.warn('Undefined requestId, not sending callbackReport', {rc: responseCode, msg: msg, rawResponse: rawResponse});
191 return; 191 return;
192 } 192 }
193 193
194 if (responseCode != '68' || dontResendDelay) { 194 if (responseCode != '68' || dontResendDelay) {
195 resendDelay.cancel(requestId); 195 resendDelay.cancel(requestId);
196 } else { 196 } else {
197 getTaskFromHistory(requestId, function(err, archivedTask) { 197 getTaskFromHistory(requestId, function(err, archivedTask) {
198 if (archivedTask) { 198 if (archivedTask) {
199 resendDelay.register(archivedTask); 199 resendDelay.register(archivedTask);
200 } 200 }
201 }); 201 });
202 } 202 }
203 203
204 if (!alreadyPending.get(requestId) || responseCode != '68') { 204 if (!alreadyPending.get(requestId) || responseCode != '68') {
205 var responseObject = { 205 var responseObject = {
206 parsed: { 206 parsed: {
207 MESSAGE: msg 207 MESSAGE: msg
208 }, 208 },
209 raw: rawResponse 209 raw: rawResponse
210 210
211 } 211 }
212 _callbackReport(requestId, responseCode, msg, null, rawResponse); 212 _callbackReport(requestId, responseCode, msg, null, responseObject);
213 } 213 }
214 alreadyPending.set(requestId, '68'); 214 alreadyPending.set(requestId, '68');
215 } 215 }
216 216
217 function getSnFromMessage(msg) { 217 function getSnFromMessage(msg) {
218 try { 218 try {
219 var matches = msg.match(/SN:\s*(\d+)/); 219 var matches = msg.match(/SN:\s*(\d+)/);
220 return matches[1]; 220 return matches[1];
221 } 221 }
222 catch(e) { 222 catch(e) {
223 return; 223 return;
224 } 224 }
225 } 225 }
226 226
227 function getStatusFromResponse(data) { 227 function getStatusFromResponse(data) {
228 try { 228 try {
229 return data.fm.status[0]; 229 return data.fm.status[0];
230 } 230 }
231 catch(e) { 231 catch(e) {
232 logger.warn('Exception on getStatusFromResponse: ' + e); 232 logger.warn('Exception on getStatusFromResponse: ' + e);
233 return; 233 return;
234 } 234 }
235 } 235 }
236 236
237 function getMessageFromResponse(data) { 237 function getMessageFromResponse(data) {
238 try { 238 try {
239 return data.fm.message[0]; 239 return data.fm.message[0];
240 } 240 }
241 catch(e) { 241 catch(e) {
242 logger.warn('Exception on getMessageFromResponse: ' + e); 242 logger.warn('Exception on getMessageFromResponse: ' + e);
243 return; 243 return;
244 } 244 }
245 } 245 }
246 246
247 function getRequestIdFromResponse(data) { 247 function getRequestIdFromResponse(data) {
248 try { 248 try {
249 return data.fm.refTrxid[0]; 249 return data.fm.refTrxid[0];
250 } 250 }
251 catch(e) { 251 catch(e) {
252 return; 252 return;
253 } 253 }
254 } 254 }
255 255
256 function modifyMessageWithSn(msg) { 256 function modifyMessageWithSn(msg) {
257 var sn = getSnFromMessage(msg); 257 var sn = getSnFromMessage(msg);
258 258
259 if (sn) { 259 if (sn) {
260 msg = 'SN=' + sn + '; ' + msg; 260 msg = 'SN=' + sn + '; ' + msg;
261 } 261 }
262 return msg; 262 return msg;
263 } 263 }
264 264
265 function composeTopupMessage(pin, product, destination, requestId) { 265 function composeTopupMessage(pin, product, destination, requestId) {
266 var data = {fm: { 266 var data = {fm: {
267 command: 'TOPUP', 267 command: 'TOPUP',
268 pin: pin, 268 pin: pin,
269 product: product, 269 product: product,
270 msisdn: destination, 270 msisdn: destination,
271 refTrxid: requestId 271 refTrxid: requestId
272 }}; 272 }};
273 273
274 return xmlBuilder.buildObject(data); 274 return xmlBuilder.buildObject(data);
275 } 275 }
276 276
277 function composeTopupStatusMessage(pin, requestId) { 277 function composeTopupStatusMessage(pin, requestId) {
278 var data = {fm: { 278 var data = {fm: {
279 command: 'TOPUPSTATUS', 279 command: 'TOPUPSTATUS',
280 pin: pin, 280 pin: pin,
281 refTrxid: requestId 281 refTrxid: requestId
282 }} 282 }}
283 283
284 return xmlBuilder.buildObject(data); 284 return xmlBuilder.buildObject(data);
285 } 285 }
286 286
287 function createServer() { 287 function createServer() {
288 var httpServer = http.createServer(function(request, response) { 288 var httpServer = http.createServer(function(request, response) {
289 289
290 logger.info('Got request from partner'); 290 logger.info('Got request from partner');
291 291
292 var body = ""; 292 var body = "";
293 req.on('data', function (chunk) { 293 req.on('data', function (chunk) {
294 body += chunk; 294 body += chunk;
295 }); 295 });
296 296
297 req.on('end', function () { 297 req.on('end', function () {
298 res.writeHead(200); 298 res.writeHead(200);
299 res.end('OK'); 299 res.end('OK');
300 300
301 topupResponseHandler(body, null, callbackReport); 301 topupResponseHandler(body, null, callbackReport);
302 302
303 }); 303 });
304 304
305 }); 305 });
306 306
307 httpServer.listen(config.h2h_out.listen_port, function() { 307 httpServer.listen(config.h2h_out.listen_port, function() {
308 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); 308 logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port);
309 }); 309 });
310 } 310 }
311 311
312 function createRedisClient(host, port) { 312 function createRedisClient(host, port) {
313 if (!host && !port) { 313 if (!host && !port) {
314 logger.info('Not creating redis client because unspecified host or port'); 314 logger.info('Not creating redis client because unspecified host or port');
315 return; 315 return;
316 } 316 }
317 317
318 try { 318 try {
319 redisClient = redis.createClient(port, host); 319 redisClient = redis.createClient(port, host);
320 } catch(err) { 320 } catch(err) {
321 logger.warn("Error creating redis client to " + host + ':' + port); 321 logger.warn("Error creating redis client to " + host + ':' + port);
322 } 322 }
323 } 323 }
324 324
325 function getTaskKey(task, chipInfo) { 325 function getTaskKey(task, chipInfo) {
326 var requestId; 326 var requestId;
327 327
328 if (typeof task === 'string') { 328 if (typeof task === 'string') {
329 requestId = task; 329 requestId = task;
330 } else { 330 } else {
331 try { 331 try {
332 requestId = task.requestId; 332 requestId = task.requestId;
333 } 333 }
334 catch(e) { 334 catch(e) {
335 logger.warn('Something wrong', {task: task}); 335 logger.warn('Something wrong', {task: task});
336 console.trace('Cekidot'); 336 console.trace('Cekidot');
337 process.exit(1); 337 process.exit(1);
338 } 338 }
339 339
340 } 340 }
341 341
342 if (!chipInfo && config && config.globals && config.globals.gateway_name) { 342 if (!chipInfo && config && config.globals && config.globals.gateway_name) {
343 chipInfo = config.globals.gateway_name; 343 chipInfo = config.globals.gateway_name;
344 } 344 }
345 345
346 return chipInfo + '.hitachi.rid:' + requestId; 346 return chipInfo + '.hitachi.rid:' + requestId;
347 } 347 }
348 348
349 349
350 function putTaskToHistory(task, cb) { 350 function putTaskToHistory(task, cb) {
351 if (Number(config.globals.no_dupe_check)) { 351 if (Number(config.globals.no_dupe_check)) {
352 if (cb) { cb(); } 352 if (cb) { cb(); }
353 return; 353 return;
354 } 354 }
355 var key = getTaskKey(task, config.globals.gateway_name); 355 var key = getTaskKey(task, config.globals.gateway_name);
356 logger.verbose('Saving task to history LRU', {key: key, task: task}); 356 logger.verbose('Saving task to history LRU', {key: key, task: task});
357 357
358 try { 358 try {
359 taskHistory.set(key, JSON.parse(JSON.stringify(task))); 359 taskHistory.set(key, JSON.parse(JSON.stringify(task)));
360 } catch (e) { } 360 } catch (e) { }
361 361
362 putTaskToRedis(task, cb); 362 putTaskToRedis(task, cb);
363 } 363 }
364 364
365 function putTaskToRedis(task, cb) { 365 function putTaskToRedis(task, cb) {
366 if (!redisClient) { 366 if (!redisClient) {
367 logger.verbose('Not saving to redis because of undefined redisClient') 367 logger.verbose('Not saving to redis because of undefined redisClient')
368 if (cb) { cb(); } 368 if (cb) { cb(); }
369 return; 369 return;
370 } 370 }
371 371
372 var key = getTaskKey(task, config.globals.gateway_name); 372 var key = getTaskKey(task, config.globals.gateway_name);
373 logger.verbose('Saving task to redis', {key: key, task: task}); 373 logger.verbose('Saving task to redis', {key: key, task: task});
374 374
375 redisClient.set(key, JSON.stringify(task), function() { 375 redisClient.set(key, JSON.stringify(task), function() {
376 redisClient.expire(key, 3600*24*30); 376 redisClient.expire(key, 3600*24*30);
377 if (cb) { 377 if (cb) {
378 cb(); 378 cb();
379 } 379 }
380 }); 380 });
381 } 381 }
382 382
383 function getTaskFromHistory(task, cb) { 383 function getTaskFromHistory(task, cb) {
384 logger.verbose('Getting task from history', {task: task}); 384 logger.verbose('Getting task from history', {task: task});
385 var key = getTaskKey(task, config.globals.gateway_name); 385 var key = getTaskKey(task, config.globals.gateway_name);
386 var archive = taskHistory.get(key); 386 var archive = taskHistory.get(key);
387 387
388 if (archive) { 388 if (archive) {
389 if (cb) { cb(null, archive); } 389 if (cb) { cb(null, archive); }
390 } 390 }
391 else { 391 else {
392 getTaskFromRedis(task, cb); 392 getTaskFromRedis(task, cb);
393 } 393 }
394 } 394 }
395 395
396 function getTaskFromRedis(task, cb) { 396 function getTaskFromRedis(task, cb) {
397 if (!redisClient) { 397 if (!redisClient) {
398 if (cb) { cb(null, null); } 398 if (cb) { cb(null, null); }
399 return; 399 return;
400 } 400 }
401 401
402 var key = getTaskKey(task, config.globals.gateway_name); 402 var key = getTaskKey(task, config.globals.gateway_name);
403 redisClient.get(key, function(err, result) { 403 redisClient.get(key, function(err, result) {
404 if (err) { 404 if (err) {
405 logger.warn('Error retrieving task from redis', {err: err}); 405 logger.warn('Error retrieving task from redis', {err: err});
406 cb(err, null); 406 cb(err, null);
407 return; 407 return;
408 } 408 }
409 409
410 var task; 410 var task;
411 try { 411 try {
412 task = JSON.parse(result); 412 task = JSON.parse(result);
413 } 413 }
414 catch(e) { 414 catch(e) {
415 logger.warn('Exception on parsing redis result as a json', {err: e}); 415 logger.warn('Exception on parsing redis result as a json', {err: e});
416 } 416 }
417 417
418 cb(null, task); 418 cb(null, task);
419 }) 419 })
420 } 420 }
421 421
422 422
423 exports.start = start; 423 exports.start = start;
424 exports.topupRequest = topupRequest; 424 exports.topupRequest = topupRequest;
425 exports.composeTopupMessage = composeTopupMessage; 425 exports.composeTopupMessage = composeTopupMessage;
426 exports.getSnFromMessage = getSnFromMessage; 426 exports.getSnFromMessage = getSnFromMessage;
427 exports.modifyMessageWithSn = modifyMessageWithSn; 427 exports.modifyMessageWithSn = modifyMessageWithSn;
428 428