Commit 3e96a0f029ddeddd0fbf201225f5ed6c3e14972f

Authored by Adhidarma Hadiwinoto
1 parent 20b54782eb
Exists in master

debug

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