Commit 20b54782ebba581bdebfa45825798fec563e6671

Authored by Adhidarma Hadiwinoto
1 parent 64f2f233f9
Exists in master

retry if pending

Showing 2 changed files with 20 additions and 0 deletions Inline Diff

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