Commit 8ec1a4b4549c978c4b67bf6a7fa6c31f1a1c490a

Authored by Adhidarma Hadiwinoto
1 parent 23f71bcad7
Exists in master

uninstall lru-cache

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