Commit 0d4216a3e97741e69db09586cad1057c89339b10

Authored by Adhidarma Hadiwinoto
1 parent c72e0d349a
Exists in master

verbose

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