Commit 365bfd35578ba82f288316dae87e2e5142e2fde4

Authored by Adhidarma Hadiwinoto
1 parent c01126a249
Exists in master

penanaganan error connect

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

partner-bayarkilat.js
1 var request = require('request'); 1 var request = require('request');
2 var url = require('url'); 2 var url = require('url');
3 var winston = require('winston'); 3 var winston = require('winston');
4 var xml2jsParser = require('xml2js').parseString; 4 var xml2jsParser = require('xml2js').parseString;
5 var redis = require('redis'); 5 var redis = require('redis');
6 6
7 7
8 var config; 8 var config;
9 var aaa; 9 var aaa;
10 var callbackReport; 10 var callbackReport;
11 var logger; 11 var logger;
12 var redisClient; 12 var redisClient;
13 13
14 var maxCheckRetry = 20; 14 var maxCheckRetry = 20;
15 var delayBeforeCheckRetry = 30 * 1000; 15 var delayBeforeCheckRetry = 30 * 1000;
16 16
17 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; 17 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
18 18
19 function createRedisClient(host, port) { 19 function createRedisClient(host, port) {
20 try { 20 try {
21 redisClient = redis.createClient(port, host); 21 redisClient = redis.createClient(port, host);
22 } catch(err) { 22 } catch(err) {
23 logger.warn("Error creating redis client to " + host + ':' + port); 23 logger.warn("Error creating redis client to " + host + ':' + port);
24 } 24 }
25 } 25 }
26 26
27 function start(_config, _callbackReport, options) { 27 function start(_config, _callbackReport, options) {
28 config = _config; 28 config = _config;
29 callbackReport = _callbackReport; 29 callbackReport = _callbackReport;
30 30
31 if (options && options.aaa) { 31 if (options && options.aaa) {
32 aaa = options.aaa; 32 aaa = options.aaa;
33 } 33 }
34 34
35 if (options && options.logger) { 35 if (options && options.logger) {
36 logger = options.logger; 36 logger = options.logger;
37 } else { 37 } else {
38 logger = new winston.Logger({ 38 logger = new winston.Logger({
39 transports: [ 39 transports: [
40 new (winston.transports.Console)() 40 new (winston.transports.Console)()
41 ] 41 ]
42 }); 42 });
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 } 46 }
47 47
48 function createRequestOptions(methodName, task) { 48 function createRequestOptions(methodName, task) {
49 var partnerUrl = url.parse(config.h2h_out.partner); 49 var partnerUrl = url.parse(config.h2h_out.partner);
50 var product = prepareRemoteProductCode(task.remoteProduct); 50 var product = prepareRemoteProductCode(task.remoteProduct);
51 51
52 var destination = task.destination; 52 var destination = task.destination;
53 if (methodName == 'CHECKING') { 53 if (methodName == 'CHECKING') {
54 destination = paddingDestination(destination); 54 destination = paddingDestination(destination);
55 } 55 }
56 56
57 var options = { 57 var options = {
58 url: config.h2h_out.partner, 58 url: config.h2h_out.partner,
59 qs: { 59 qs: {
60 request: methodName + '*' 60 request: methodName + '*'
61 + task.requestId + '*' 61 + task.requestId + '*'
62 + product.product + '*' 62 + product.product + '*'
63 + product.productDetail + '*' 63 + product.productDetail + '*'
64 + destination + '*' 64 + destination + '*'
65 + product.nominal + '*' 65 + product.nominal + '*'
66 + '0*' 66 + '0*'
67 + config.h2h_out.noid + '*' 67 + config.h2h_out.noid + '*'
68 + config.h2h_out.userid + '*' 68 + config.h2h_out.userid + '*'
69 + config.h2h_out.password 69 + config.h2h_out.password
70 } 70 }
71 }; 71 };
72 72
73 return options; 73 return options;
74 } 74 }
75 75
76 function topupCheck(task, retry) { 76 function topupCheck(task, retry) {
77 if (retry === null || retry === undefined) { 77 if (retry === null || retry === undefined) {
78 retry = maxCheckRetry + 1; 78 retry = maxCheckRetry + 1;
79 } 79 }
80 80
81 retry = retry - 1; 81 retry = retry - 1;
82 82
83 if (retry < 0) { 83 if (retry < 0) {
84 var message = 'Max retry check transaction retry exceeded'; 84 var message = 'Max retry check transaction retry exceeded';
85 var response = { 85 var response = {
86 raw: message, 86 raw: message,
87 parsed: { 87 parsed: {
88 MESSAGE: message 88 MESSAGE: message
89 } 89 }
90 } 90 }
91 aaa.pushResponseToMongoDb(task, response, '68'); 91 aaa.pushResponseToMongoDb(task, response, '68');
92 callbackReport(task.requestId, '68', message); 92 callbackReport(task.requestId, '68', message);
93 return; 93 return;
94 } 94 }
95 95
96 requestToPartner('CHECKING', task, retry); 96 requestToPartner('CHECKING', task, retry);
97 } 97 }
98 98
99 function topupRequest(task) { 99 function topupRequest(task) {
100 if (!aaa.isTodayTrx(task)) { 100 if (!aaa.isTodayTrx(task)) {
101 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan'); 101 logger.warn('Maaf, transaksi beda hari tidak dapat dilakukan');
102 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan'); 102 callbackReport(task.requestId, '68', 'Maaf, transaksi beda hari tidak dapat dilakukan');
103 return; 103 return;
104 } 104 }
105 105
106 getTaskForDupeCheck(task, function(err, dupeTask) { 106 getTaskForDupeCheck(task, function(err, dupeTask) {
107 if (dupeTask) { 107 if (dupeTask) {
108 logger.info('Duplicate task detected, requesting topupCheck', {task: task}); 108 logger.info('Duplicate task detected, requesting topupCheck', {task: task});
109 topupCheck(task); 109 topupCheck(task);
110 } else { 110 } else {
111 saveTaskForDupeCheck(task); 111 saveTaskForDupeCheck(task);
112 requestToPartner('PURCHASE', task); 112 requestToPartner('PURCHASE', task);
113 } 113 }
114 }); 114 });
115 115
116 } 116 }
117 117
118 function requestToPartner(methodName, task, retry) { 118 function requestToPartner(methodName, task, retry) {
119 aaa.insertTaskToMongoDb(task); 119 aaa.insertTaskToMongoDb(task);
120 120
121 var options = createRequestOptions(methodName, task); 121 var options = createRequestOptions(methodName, task);
122 122
123 logger.info('Requesting to partner', {requestOption: options}); 123 logger.info('Requesting to partner', {requestOption: options});
124 request(options, function(error, response, body) { 124 request(options, function(error, response, body) {
125 if (error) { 125 if (error) {
126 logger.warn('Error requesting to partner', {error: error}); 126 var msg = 'Error requesting to partner. ' + error;
127 callbackReport(task.requestId, '68', 'Error requesting to partner. ' + error); 127 var rc = '68';
128
129 try {
130 if (methodName == 'PURCHASE') {
131 if (error.connect === true && (error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED')) {
132 rc = '40';
133 }
134 }
135 }
136 catch(e) {
137 logger.warn('Parsing error exception on requestToPartner()');
138 }
139
140 logger.warn(msg, {error: error});
141 callbackReport(task.requestId, rc, msg);
128 142
129 var _response = { 143 var _response = {
130 raw: 'Error requesting to partner. ' + error, 144 raw: JSON.stringify(msg: msg, error: error),
131 parsed: { 145 parsed: {
132 MESSAGE: 'Error requesting to partner. ' + error, 146 MESSAGE: msg
133 error: error 147 error: error
134 } 148 }
135 } 149 }
136 aaa.pushResponseToMongoDb(task, _response, '68'); 150 aaa.pushResponseToMongoDb(task, _response, rc);
137 151
138 setTimeout( 152 if (rc == '68') {
139 topupCheck, 153 setTimeout(
140 delayBeforeCheckRetry, 154 topupCheck,
141 task, 155 delayBeforeCheckRetry,
142 retry 156 task,
143 ); 157 retry
158 );
159 }
144 160
145 return; 161 return;
146 } 162 }
147 163
148 if (response.statusCode != 200) { 164 if (response.statusCode != 200) {
149 var message = 'Partner response with http status code other that 200 (' + response.statusCode + ')'; 165 var message = 'Partner response with http status code other that 200 (' + response.statusCode + ')';
150 166
151 logger.warn(message); 167 logger.warn(message);
152 callbackReport(task.requestId, '68', message); 168 callbackReport(task.requestId, '68', message);
153 169
154 var _response = { 170 var _response = {
155 raw: 'Partner response with http status code other that 200 (' + response.statusCode + ')', 171 raw: 'Partner response with http status code other that 200 (' + response.statusCode + ')',
156 parsed: { 172 parsed: {
157 MESSAGE: 'Partner response with http status code other that 200 (' + response.statusCode + ')', 173 MESSAGE: 'Partner response with http status code other that 200 (' + response.statusCode + ')',
158 responseHttpStatus: response.statusCode, 174 responseHttpStatus: response.statusCode,
159 responseBody: body, 175 responseBody: body,
160 } 176 }
161 } 177 }
162 aaa.pushResponseToMongoDb(task, _response, '68'); 178 aaa.pushResponseToMongoDb(task, _response, '68');
163 179
164 setTimeout( 180 setTimeout(
165 topupCheck, 181 topupCheck,
166 delayBeforeCheckRetry, 182 delayBeforeCheckRetry,
167 task, 183 task,
168 retry 184 retry
169 ); 185 );
170 186
171 return; 187 return;
172 } 188 }
173 189
174 logger.verbose('Got respose', {rawBody: body}); 190 logger.verbose('Got respose', {rawBody: body});
175 parseResponse(body, task); 191 parseResponse(body, task);
176 }); 192 });
177 } 193 }
178 194
179 function getSn(response) { 195 function getSn(response) {
180 try { 196 try {
181 var sn = response.xml.ket1[0]; 197 var sn = response.xml.ket1[0];
182 return sn; 198 return sn;
183 } 199 }
184 catch (err) { 200 catch (err) {
185 return; 201 return;
186 } 202 }
187 } 203 }
188 204
189 function getHarga(response) { 205 function getHarga(response) {
190 try { 206 try {
191 var harga = response.xml.amount[0]; 207 var harga = response.xml.amount[0];
192 return harga; 208 return harga;
193 } 209 }
194 catch (err) { 210 catch (err) {
195 return; 211 return;
196 } 212 }
197 } 213 }
198 214
199 function getSaldo(response) { 215 function getSaldo(response) {
200 try { 216 try {
201 var saldo = response.xml.saldo[0]; 217 var saldo = response.xml.saldo[0];
202 return saldo; 218 return saldo;
203 } 219 }
204 catch (err) { 220 catch (err) {
205 return; 221 return;
206 } 222 }
207 } 223 }
208 224
209 function parseResponse(body, task) { 225 function parseResponse(body, task) {
210 xml2jsParser(body, function(err, response) { 226 xml2jsParser(body, function(err, response) {
211 if (err) { 227 if (err) {
212 logger.warn('Error parsing XML', {error: err, task: task, responseBody: body}); 228 logger.warn('Error parsing XML', {error: err, task: task, responseBody: body});
213 229
214 var message = 'Error parsing XML. ' + err + '. ' + body; 230 var message = 'Error parsing XML. ' + err + '. ' + body;
215 231
216 var _response = { 232 var _response = {
217 raw: body, 233 raw: body,
218 parsed: { 234 parsed: {
219 MESSAGE: message 235 MESSAGE: message
220 } 236 }
221 } 237 }
222 aaa.pushResponseToMongoDb(task, _response, '68'); 238 aaa.pushResponseToMongoDb(task, _response, '68');
223 239
224 callbackReport(task.requestId, '68', message); 240 callbackReport(task.requestId, '68', message);
225 return; 241 return;
226 } 242 }
227 243
228 logger.info('Got response', {response: response}); 244 logger.info('Got response', {response: response});
229 245
230 var responseCode; 246 var responseCode;
231 var message; 247 var message;
232 248
233 try { 249 try {
234 responseCode = response.xml.response_code[0]; 250 responseCode = response.xml.response_code[0];
235 message = response.xml.response_message[0]; 251 message = response.xml.response_message[0];
236 } 252 }
237 catch(errGetParam) { 253 catch(errGetParam) {
238 logger.warn('Exception saat parsing hasil', {error: errGetParam, task: task, responseBody: body}); 254 logger.warn('Exception saat parsing hasil', {error: errGetParam, task: task, responseBody: body});
239 255
240 var _response = { 256 var _response = {
241 raw: body, 257 raw: body,
242 parsed: { 258 parsed: {
243 MESSAGE: 'Exception saat parsing hasil. ' + errGetParam, 259 MESSAGE: 'Exception saat parsing hasil. ' + errGetParam,
244 xml: response.xml 260 xml: response.xml
245 } 261 }
246 } 262 }
247 aaa.pushResponseToMongoDb(task, _response, '68'); 263 aaa.pushResponseToMongoDb(task, _response, '68');
248 264
249 callbackReport(task.requestId, '68', 'Exception saat parsing hasil. ' + errGetParam); 265 callbackReport(task.requestId, '68', 'Exception saat parsing hasil. ' + errGetParam);
250 return; 266 return;
251 } 267 }
252 268
253 var st24rc; 269 var st24rc;
254 if (parseInt(responseCode) == 0) { 270 if (parseInt(responseCode) == 0) {
255 st24rc = '00'; 271 st24rc = '00';
256 } 272 }
257 else if (parseInt(responseCode) == '99') { 273 else if (parseInt(responseCode) == '99') {
258 st24rc = '68' 274 st24rc = '68'
259 } 275 }
260 else { 276 else {
261 st24rc = '40'; 277 st24rc = '40';
262 } 278 }
263 279
264 var st24message = message; 280 var st24message = message;
265 if (responseCode) { 281 if (responseCode) {
266 st24message = responseCode + ' ' + st24message; 282 st24message = responseCode + ' ' + st24message;
267 } 283 }
268 284
269 if (st24rc == '00') { 285 if (st24rc == '00') {
270 var sn = getSn(response); 286 var sn = getSn(response);
271 287
272 if (sn) { 288 if (sn) {
273 st24message = 'SN=' + sn + ';' + st24message + '. SN=' + sn; 289 st24message = 'SN=' + sn + ';' + st24message + '. SN=' + sn;
274 } 290 }
275 } 291 }
276 292
277 var harga = getHarga(response); 293 var harga = getHarga(response);
278 if (harga) { 294 if (harga) {
279 st24message = st24message + '. Harga ' + harga; 295 st24message = st24message + '. Harga ' + harga;
280 } 296 }
281 297
282 var saldo = getSaldo(response); 298 var saldo = getSaldo(response);
283 if (saldo) { 299 if (saldo) {
284 st24message = st24message + '. Saldo ' + saldo; 300 st24message = st24message + '. Saldo ' + saldo;
285 aaa.updateBalance(saldo); 301 aaa.updateBalance(saldo);
286 } 302 }
287 303
288 var _response = { 304 var _response = {
289 raw: body, 305 raw: body,
290 parsed: { 306 parsed: {
291 MESSAGE: st24message, 307 MESSAGE: st24message,
292 xml: response.xml 308 xml: response.xml
293 } 309 }
294 } 310 }
295 311
296 aaa.pushResponseToMongoDb(task, _response, st24rc); 312 aaa.pushResponseToMongoDb(task, _response, st24rc);
297 313
298 callbackReport(task.requestId, st24rc, st24message); 314 callbackReport(task.requestId, st24rc, st24message);
299 }); 315 });
300 } 316 }
301 317
302 function prepareRemoteProductCode(remoteProduct) { 318 function prepareRemoteProductCode(remoteProduct) {
303 var product = remoteProduct.split(','); 319 var product = remoteProduct.split(',');
304 320
305 if (product.length != 3) { 321 if (product.length != 3) {
306 return; 322 return;
307 } 323 }
308 324
309 return { 325 return {
310 product: product[0], 326 product: product[0],
311 productDetail: product[1], 327 productDetail: product[1],
312 nominal: product[2] 328 nominal: product[2]
313 } 329 }
314 } 330 }
315 331
316 function paddingDestination(destination, width) { 332 function paddingDestination(destination, width) {
317 if (!width) { 333 if (!width) {
318 width = 13; 334 width = 13;
319 } 335 }
320 336
321 if (destination.length > width) { 337 if (destination.length > width) {
322 return destination; 338 return destination;
323 } 339 }
324 340
325 var padder = "000000000000000000000000000"; 341 var padder = "000000000000000000000000000";
326 342
327 return (padder + destination).slice(-1 * width); 343 return (padder + destination).slice(-1 * width);
328 } 344 }
329 345
330 function getTaskKeyForDupeCheck(task) { 346 function getTaskKeyForDupeCheck(task) {
331 return config.globals.gateway_name + '.dupecheck.reqId:' + task.requestId; 347 return config.globals.gateway_name + '.dupecheck.reqId:' + task.requestId;
332 } 348 }
333 349
334 function saveTaskForDupeCheck(task, cb) { 350 function saveTaskForDupeCheck(task, cb) {
335 var key = getTaskKeyForDupeCheck(task); 351 var key = getTaskKeyForDupeCheck(task);
336 352
337 logger.verbose('Saving ' + key + ' to redis for dupecheck protection'); 353 logger.verbose('Saving ' + key + ' to redis for dupecheck protection');
338 354
339 redisClient.set(key, JSON.stringify(task), function() { 355 redisClient.set(key, JSON.stringify(task), function() {
340 redisClient.expire(key, 3600*24*7); 356 redisClient.expire(key, 3600*24*7);
341 if (cb) { 357 if (cb) {
342 cb(null, task); 358 cb(null, task);
343 } 359 }
344 }); 360 });
345 } 361 }
346 362
347 function getTaskForDupeCheck(task, cb) { 363 function getTaskForDupeCheck(task, cb) {
348 var key = getTaskKeyForDupeCheck(task); 364 var key = getTaskKeyForDupeCheck(task);
349 365
350 redisClient.get(key, function(err, result) { 366 redisClient.get(key, function(err, result) {
351 if (err) { 367 if (err) {
352 cb(err, null); 368 cb(err, null);
353 return; 369 return;
354 } 370 }
355 371
356 var taskOnRedis = null; 372 var taskOnRedis = null;
357 try { 373 try {
358 taskOnRedis = JSON.parse(result); 374 taskOnRedis = JSON.parse(result);
359 } 375 }
360 catch(err1) { 376 catch(err1) {
361 cb(err1, null); 377 cb(err1, null);
362 return; 378 return;
363 } 379 }
364 380
365 cb(null, taskOnRedis); 381 cb(null, taskOnRedis);
366 }); 382 });
367 } 383 }
368 384
369 exports.start = start; 385 exports.start = start;
370 exports.topupRequest = topupRequest; 386 exports.topupRequest = topupRequest;
371 exports.prepareRemoteProductCode = prepareRemoteProductCode; 387 exports.prepareRemoteProductCode = prepareRemoteProductCode;
372 exports.paddingDestination = paddingDestination; 388 exports.paddingDestination = paddingDestination;
373 389