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