Commit 34c1fc6aa5882d46d4dfccacf97ecd7d65ad9199

Authored by Adhidarma Hadiwinoto
1 parent 2d64cb6a0b
Exists in master

topupRequestRetry

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