Commit b84090305166723fcdf2e8e642e46889299caebe

Authored by Adhidarma Hadiwinoto
1 parent 3e96a0f029
Exists in master

max retry

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

1 var winston = require('winston'); 1 var winston = require('winston');
2 var crypto = require('crypto'); 2 var crypto = require('crypto');
3 var xml = require('xml'); 3 var xml = require('xml');
4 var url = require('url'); 4 var url = require('url');
5 var http = require('http'); 5 var http = require('http');
6 var xml2js = require('xml2js').parseString; 6 var xml2js = require('xml2js').parseString;
7 var LRU = require("lru-cache"); 7 var LRU = require("lru-cache");
8 8
9 var config; 9 var config;
10 var callbackReport; 10 var callbackReport;
11 var aaa; 11 var aaa;
12 var logger; 12 var logger;
13 var options; 13 var options;
14 var taskCache = LRU({max: 2000}); 14 var taskCache = LRU({max: 2000});
15 15
16 var maxRetry = 10; 16 var maxRetry = 10;
17 var sleepBeforeRetry = 30; 17 var sleepBeforeRetry = 30;
18 18
19 function start(_config, _callbackReport, options) { 19 function start(_config, _callbackReport, options) {
20 config = _config; 20 config = _config;
21 callbackReport = _callbackReport 21 callbackReport = _callbackReport
22 22
23 if (options && options.aaa) { 23 if (options && options.aaa) {
24 aaa = options.aaa; 24 aaa = options.aaa;
25 } 25 }
26 26
27 if (options && options.logger) { 27 if (options && options.logger) {
28 logger = options.logger; 28 logger = options.logger;
29 } else { 29 } else {
30 logger = new winston.Logger({ 30 logger = new winston.Logger({
31 transports: [ 31 transports: [
32 new (winston.transports.Console)() 32 new (winston.transports.Console)()
33 ] 33 ]
34 }); 34 });
35 } 35 }
36 } 36 }
37 37
38 function calculateSignature(params) { 38 function calculateSignature(params) {
39 var passwordHash = crypto.createHash('sha1').update(params.password).digest().toString('hex'); 39 var passwordHash = crypto.createHash('sha1').update(params.password).digest().toString('hex');
40 var plain = params.trxtype + params.prdcode + params.value + params.msisdn + params.trxid + params.uid + passwordHash; 40 var plain = params.trxtype + params.prdcode + params.value + params.msisdn + params.trxid + params.uid + passwordHash;
41 var signature = crypto.createHash('sha256').update(plain).digest().toString('hex'); 41 var signature = crypto.createHash('sha256').update(plain).digest().toString('hex');
42 42
43 try { 43 try {
44 logger.verbose('Signature calculated', {plain: plain, signature: signature}); 44 logger.verbose('Signature calculated', {plain: plain, signature: signature});
45 } 45 }
46 catch(err) {} 46 catch(err) {}
47 47
48 return signature; 48 return signature;
49 } 49 }
50 50
51 function createXmlPayload(params) { 51 function createXmlPayload(params) {
52 var payload = "<?xml version=\"1.0\" ?>\n" + xml({ 52 var payload = "<?xml version=\"1.0\" ?>\n" + xml({
53 ciwaru: [ 53 ciwaru: [
54 {trxtype: params.trxtype}, 54 {trxtype: params.trxtype},
55 {prdcode: params.prdcode}, 55 {prdcode: params.prdcode},
56 {value: params.value}, 56 {value: params.value},
57 {msisdn: params.msisdn}, 57 {msisdn: params.msisdn},
58 {trxid: params.trxid}, 58 {trxid: params.trxid},
59 {uid: params.uid}, 59 {uid: params.uid},
60 {hash: calculateSignature(params)} 60 {hash: calculateSignature(params)}
61 ] 61 ]
62 }); 62 });
63 63
64 logger.verbose("Payload: " + payload); 64 logger.verbose("Payload: " + payload);
65 return payload; 65 return payload;
66 } 66 }
67 67
68 function getSNFromMessage(message) { 68 function getSNFromMessage(message) {
69 try { 69 try {
70 var sn_match = message.match(/SN: (\w+)/); 70 var sn_match = message.match(/SN: (\w+)/);
71 return sn_match[1]; 71 return sn_match[1];
72 } 72 }
73 catch(err) { 73 catch(err) {
74 return ''; 74 return '';
75 } 75 }
76 } 76 }
77 77
78 function hasSuccessKeywords(message) { 78 function hasSuccessKeywords(message) {
79 var keywords = ['SUKSES', 'Finish']; 79 var keywords = ['SUKSES', 'Finish'];
80 80
81 var count = keywords.length; 81 var count = keywords.length;
82 for (var i=0; i < count; i++) { 82 for (var i=0; i < count; i++) {
83 if (message.indexOf(keywords[i]) >= 0) { 83 if (message.indexOf(keywords[i]) >= 0) {
84 return true; 84 return true;
85 } 85 }
86 } 86 }
87 return false; 87 return false;
88 } 88 }
89 89
90 function supplierRcToST24Rc(rc) { 90 function supplierRcToST24Rc(rc) {
91 var rcs = { 91 var rcs = {
92 '0001': '40', 92 '0001': '40',
93 '0019': '13', // produk tidak tersedia 93 '0019': '13', // produk tidak tersedia
94 } 94 }
95 95
96 if (rcs[rc]) { 96 if (rcs[rc]) {
97 return rcs[rc]; 97 return rcs[rc];
98 } else { 98 } else {
99 return; 99 return;
100 } 100 }
101 } 101 }
102 102
103 function topupResponseHandler(body) { 103 function topupResponseHandler(body) {
104 //logger.info('Got reply from partner', {body: body}); 104 //logger.info('Got reply from partner', {body: body});
105 xml2js(body, function(err, result) { 105 xml2js(body, function(err, result) {
106 if (err) { 106 if (err) {
107 logger.warn('Got invalid XML from partner', {err: err, body: body}); 107 logger.warn('Got invalid XML from partner', {err: err, body: body});
108 } 108 }
109 logger.info('XML message from partner', {result: result}); 109 logger.info('XML message from partner', {result: result});
110 110
111 var rc = '68'; 111 var rc = '68';
112 var message = result.ciwaru.msg[0]; 112 var message = result.ciwaru.msg[0];
113 113
114 var trxid = 0; 114 var trxid = 0;
115 try { 115 try {
116 trxid = result.ciwaru.reqnum[0]; 116 trxid = result.ciwaru.reqnum[0];
117 } 117 }
118 catch(err) { 118 catch(err) {
119 trxid = result.ciwaru.trxid[0]; 119 trxid = result.ciwaru.trxid[0];
120 } 120 }
121 121
122 var task = taskCache.get(trxid);
123 if (!task) {
124 logger.warn('Got reply for undefined task');
125 return;
126 }
127
122 if (message.indexOf('PENDING') >= 0) { 128 if (message.indexOf('PENDING') >= 0) {
123 rc = '68'; 129 rc = '68';
124 } 130 }
125 else if (hasSuccessKeywords(message)) { 131 else if (hasSuccessKeywords(message)) {
126 var sn = getSNFromMessage(result.ciwaru.msg); 132 var sn = getSNFromMessage(result.ciwaru.msg);
127 message = 'SN=' + sn + '; ' + message; 133 message = 'SN=' + sn + '; ' + message;
128 rc = '00'; 134 rc = '00';
129 } else { 135 } else {
130 rc = supplierRcToST24Rc(result.ciwaru.rc[0]); 136 rc = supplierRcToST24Rc(result.ciwaru.rc[0]);
131 if (!rc) { 137 if (!rc) {
132 rc = '68'; 138 rc = '68';
133 } 139 }
134 } 140 }
135 141
136 callbackReport(trxid, rc, message); 142 if ((task.retry == maxRetry) || (rc != '68')) {
143 callbackReport(trxid, rc, message);
144 }
137 145
138 if (rc == '68') { 146 if (rc == '68') {
139 task = taskCache.get(trxid); 147 task.retry--;
140 if (!task) { 148 taskCache.set(trxid, task);
141 return; 149
150 if (task.retry) {
151 logger.info('Got pending status, retrying in ' + sleepBeforeRetry + 's');
152 setTimeout(topupRequest, sleepBeforeRetry * 1000, task);
153 }
154 else {
155 logger.warn('Maximum retry for pending status exceeded', {task: task});
142 } 156 }
143
144 logger.info('Got pending status, retrying in ' + sleepBeforeRetry + 's');
145 setTimeout(topupRequest, sleepBeforeRetry * 1000, task);
146 } else { 157 } else {
147 taskCache.del(trxid); 158 taskCache.del(trxid);
148 } 159 }
149 }); 160 });
150 } 161 }
151 162
152 function topupRequest(task, retry) { 163 function topupRequest(task, retry) {
153 164
154 logger.info('Executing task', {retry: retry}); 165 if (retry === undefined) {
166 task.retry = maxRetry;
167 }
155 168
156 taskCache.set(task.requestId, task); 169 taskCache.set(task.requestId, task);
157 170
158 var remoteProduct = task.remoteProduct.split(','); 171 var remoteProduct = task.remoteProduct.split(',');
159 172
160 var params = { 173 var params = {
161 trxtype: '01', 174 trxtype: '01',
162 prdcode: remoteProduct[0], 175 prdcode: remoteProduct[0],
163 value: remoteProduct[1], 176 value: remoteProduct[1],
164 msisdn: task.destination, 177 msisdn: task.destination,
165 trxid: task.requestId, 178 trxid: task.requestId,
166 uid: config.h2h_out.userid, 179 uid: config.h2h_out.userid,
167 password: config.h2h_out.password, 180 password: config.h2h_out.password,
168 }; 181 };
169 182
170 var postBody = createXmlPayload(params); 183 var postBody = createXmlPayload(params);
171 184
172 var partnerUrl = url.parse(config.h2h_out.partner); 185 var partnerUrl = url.parse(config.h2h_out.partner);
173 var postRequest = { 186 var postRequest = {
174 host: partnerUrl.hostname, 187 host: partnerUrl.hostname,
175 path: partnerUrl.path, 188 path: partnerUrl.path,
176 port: partnerUrl.port, 189 port: partnerUrl.port,
177 method: "POST", 190 method: "POST",
178 headers: { 191 headers: {
179 'Content-Type': 'text/xml', 192 'Content-Type': 'text/xml',
180 'Content-Length': Buffer.byteLength(postBody) 193 'Content-Length': Buffer.byteLength(postBody)
181 } 194 }
182 }; 195 };
183 196
184 logger.info('POST to partner', {postRequest: postRequest}); 197 logger.info('POST to partner', {postRequest: postRequest});
185 var req = http.request(postRequest, function( res ) { 198 var req = http.request(postRequest, function( res ) {
186 199
187 logger.info('Status code: ' + res.statusCode ); 200 logger.info('Status code: ' + res.statusCode );
188 var buffer = ""; 201 var buffer = "";
189 res.on( "data", function( data ) { buffer = buffer + data; } ); 202 res.on( "data", function( data ) { buffer = buffer + data; } );
190 res.on( "end", function( data ) { 203 res.on( "end", function( data ) {
191 topupResponseHandler(buffer); 204 topupResponseHandler(buffer);
192 }); 205 });
193 }); 206 });
194 207
195 req.on('error', function(e) { 208 req.on('error', function(e) {
196 logger.warn('problem with request: ' + e.message); 209 logger.warn('problem with request: ' + e.message);
197 callbackReport(task['requestId'], '40', e.message); 210 callbackReport(task['requestId'], '40', e.message);
198 }); 211 });
199 212
200 req.write(postBody); 213 req.write(postBody);
201 req.end(); 214 req.end();
202 } 215 }
203 216
204 exports.start = start; 217 exports.start = start;
205 exports.topupRequest = topupRequest; 218 exports.topupRequest = topupRequest;
206 exports.calculateSignature = calculateSignature; 219 exports.calculateSignature = calculateSignature;