Commit 1a0a4c0beeb0c27c36993f7be5b2a83ad44705ef

Authored by Adhidarma Hadiwinoto
1 parent 34c1fc6aa5
Exists in master

mongodb

Showing 2 changed files with 80 additions and 2 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 "mongodb": "^2.1.18",
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",
27 "strftime": "^0.9.2",
26 "winston": "^2.2.0", 28 "winston": "^2.2.0",
27 "xml": "^1.0.1", 29 "xml": "^1.0.1",
28 "xml2js": "^0.4.16" 30 "xml2js": "^0.4.16"
29 }, 31 },
30 "devDependencies": { 32 "devDependencies": {
31 "should": "^8.3.1" 33 "should": "^8.3.1"
32 } 34 }
33 } 35 }
34 36
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 mongoClient = require('mongodb').MongoClient;
8 var strftime = require('strftime');
7 9
8 var config; 10 var config;
9 var callbackReport; 11 var callbackReport;
10 var aaa; 12 var aaa;
11 var logger; 13 var logger;
12 var options; 14 var options;
15 var mongodb;
16
17 function initMongoClient() {
18 if (!config.mongodb || !config.mongodb.url) {
19 return;
20 }
21
22 try {
23 var url = config.mongodb.url;
24
25 mongoClient.connect(url, function(err, db) {
26 if (err) {
27 logger.warn('Failed to connect to mongodb', {err: err});
28 return;
29 }
30 mongodb = db;
31 logger.info('MongoDB connected');
32 });
33 }
34 catch(err) {
35 logger.warn('Exception when connecting to mongodb', {err: err, url: url});
36 }
37 }
13 38
14 var maxRetry = 10; 39 var maxRetry = 10;
15 var sleepBeforeRetry = 30; 40 var sleepBeforeRetry = 30;
16 41
17 function start(_config, _callbackReport, options) { 42 function start(_config, _callbackReport, options) {
18 config = _config; 43 config = _config;
19 callbackReport = _callbackReport 44 callbackReport = _callbackReport
20 45
21 if (options && options.aaa) { 46 if (options && options.aaa) {
22 aaa = options.aaa; 47 aaa = options.aaa;
23 } 48 }
24 49
25 if (options && options.logger) { 50 if (options && options.logger) {
26 logger = options.logger; 51 logger = options.logger;
27 } else { 52 } else {
28 logger = new winston.Logger({ 53 logger = new winston.Logger({
29 transports: [ 54 transports: [
30 new (winston.transports.Console)() 55 new (winston.transports.Console)()
31 ] 56 ]
32 }); 57 });
33 } 58 }
59
60 initMongoClient();
34 } 61 }
35 62
36 function calculateSignature(params) { 63 function calculateSignature(params) {
37 var passwordHash = crypto.createHash('sha1').update(params.password).digest().toString('hex'); 64 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; 65 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'); 66 var signature = crypto.createHash('sha256').update(plain).digest().toString('hex');
40 67
41 try { 68 try {
42 logger.verbose('Signature calculated', {plain: plain, signature: signature}); 69 logger.verbose('Signature calculated', {plain: plain, signature: signature});
43 } 70 }
44 catch(err) {} 71 catch(err) {}
45 72
46 return signature; 73 return signature;
47 } 74 }
48 75
49 function createXmlPayload(params) { 76 function createXmlPayload(params) {
50 var payload = "<?xml version=\"1.0\" ?>\n" + xml({ 77 var payload = "<?xml version=\"1.0\" ?>\n" + xml({
51 ciwaru: [ 78 ciwaru: [
52 {trxtype: params.trxtype}, 79 {trxtype: params.trxtype},
53 {prdcode: params.prdcode}, 80 {prdcode: params.prdcode},
54 {value: params.value}, 81 {value: params.value},
55 {msisdn: params.msisdn}, 82 {msisdn: params.msisdn},
56 {trxid: params.trxid}, 83 {trxid: params.trxid},
57 {uid: params.uid}, 84 {uid: params.uid},
58 {hash: calculateSignature(params)} 85 {hash: calculateSignature(params)}
59 ] 86 ]
60 }); 87 });
61 88
62 try { logger.verbose("Payload: " + payload); } 89 try { logger.verbose("Payload: " + payload); }
63 catch(errLog) {} 90 catch(errLog) {}
64 91
65 return payload; 92 return payload;
66 } 93 }
67 94
95 function insertTaskToMongoDb(task) {
96 if (!isMongoReady()) { return; }
97
98 try {
99 mongodb.collection(config.mongodb.collection).insertOne(task);
100 }
101 catch(err) {
102 //logger.warn('Exception when inserting document to mongodb', {err: err, task: task});
103 }
104 }
105
106 function pushResponseToMongoDb(task, response) {
107 if (!isMongoReady()) { return; }
108
109 try {
110 mongodb.collection(config.mongodb.collection).updateOne(
111 {requestId: task.requestId},
112 {$push: {responses: response}},
113 function(err, result) {
114 if (err) {
115 logger.warn('Error when pushing response to mongodb', {err: err, task: task, response: response});
116 return;
117 }
118 }
119 );
120 }
121 catch(err) {
122 logger.warn('Exception when pushing response to mongodb', {err: err, task: task, response: response});
123 }
124 }
125
126 function isMongoReady() {
127 if (!config.mongodb) { return; }
128 if (!config.mongodb.collection) { return; }
129 if (!mongodb) { return; }
130
131 return true;
132 }
133
68 function getSNFromMessage(message) { 134 function getSNFromMessage(message) {
69 try { 135 try {
70 var sn_match = message.match(/SN: (\w+)/); 136 var sn_match = message.match(/SN: (\w+)/);
71 logger.verbose('Got SN: ' + sn_match[1]); 137 logger.verbose('Got SN: ' + sn_match[1]);
72 return sn_match[1].trim(); 138 return sn_match[1].trim();
73 } 139 }
74 catch(err) { 140 catch(err) {
75 logger.verbose('Exception on getting sn from message', {err: err}); 141 logger.verbose('Exception on getting sn from message', {err: err});
76 return ''; 142 return '';
77 } 143 }
78 } 144 }
79 145
80 function hasSuccessKeywords(message) { 146 function hasSuccessKeywords(message) {
81 var keywords = ['SUKSES', 'Finish']; 147 var keywords = ['SUKSES', 'Finish'];
82 148
83 var count = keywords.length; 149 var count = keywords.length;
84 for (var i=0; i < count; i++) { 150 for (var i=0; i < count; i++) {
85 if (message.indexOf(keywords[i]) >= 0) { 151 if (message.indexOf(keywords[i]) >= 0) {
86 return true; 152 return true;
87 } 153 }
88 } 154 }
89 return false; 155 return false;
90 } 156 }
91 157
92 function supplierRcToST24Rc(rc) { 158 function supplierRcToST24Rc(rc) {
93 var rcs = { 159 var rcs = {
94 '0001': '40', 160 '0001': '40',
95 '0019': '13', // produk tidak tersedia 161 '0019': '13', // produk tidak tersedia
96 } 162 }
97 163
98 if (rcs[rc]) { 164 if (rcs[rc]) {
99 return rcs[rc]; 165 return rcs[rc];
100 } else { 166 } else {
101 return; 167 return;
102 } 168 }
103 } 169 }
104 170
105 function getSNFromResponseObject(respObj) { 171 function getSNFromResponseObject(respObj) {
106 try { 172 try {
107 return respObj.ciwaru.sn[0].trim(); 173 return respObj.ciwaru.sn[0].trim();
108 } 174 }
109 catch(err) { 175 catch(err) {
110 return; 176 return;
111 } 177 }
112 } 178 }
113 179
114 function topupResponseHandler(body, task) { 180 function topupResponseHandler(body, task) {
181
115 //logger.info('Got reply from partner', {body: body}); 182 //logger.info('Got reply from partner', {body: body});
183
116 xml2js(body, function(err, result) { 184 xml2js(body, function(err, result) {
185 var ts = strftime('%Y-%m-%d %H:%M:%S', new Date());
186 pushResponseToMongoDb(task, {ts: ts, raw: body});
187
117 if (err) { 188 if (err) {
118 logger.warn('Got invalid XML from partner', {err: err, body: body, task: task}); 189 logger.warn('Got invalid XML from partner', {err: err, body: body, task: task});
190 callbackReport(task.requestId, '68', body);
191 return;
119 } 192 }
120 logger.info('XML message from partner', {result: result}); 193 logger.info('XML message from partner', {result: result});
121 194
122 var rc = '68'; 195 var rc = '68';
123 var message = result.ciwaru.msg[0]; 196 var message = result.ciwaru.msg[0];
124 197
198 /*
125 var trxid = 0; 199 var trxid = 0;
126 try { 200 try {
127 trxid = result.ciwaru.reqnum[0]; 201 trxid = result.ciwaru.reqnum[0];
128 } 202 }
129 catch(err) { 203 catch(err) {
130 trxid = result.ciwaru.trxid[0]; 204 trxid = result.ciwaru.trxid[0];
131 } 205 }
206 */
132 207
133 if (message.toUpperCase().indexOf('PENDING') >= 0) { 208 if (message.toUpperCase().indexOf('PENDING') >= 0) {
134 rc = '68'; 209 rc = '68';
135 } 210 }
136 else if (hasSuccessKeywords(message)) { 211 else if (hasSuccessKeywords(message)) {
137 var sn = getSNFromResponseObject(result); 212 var sn = getSNFromResponseObject(result);
138 if (!sn) { 213 if (!sn) {
139 sn = getSNFromMessage(message); 214 sn = getSNFromMessage(message);
140 } 215 }
141 216
142 message = 'SN=' + sn + '; ' + message; 217 message = 'SN=' + sn + '; ' + message;
143 rc = '00'; 218 rc = '00';
144 219
145 } else { 220 } else {
146 rc = supplierRcToST24Rc(result.ciwaru.rc[0]); 221 rc = supplierRcToST24Rc(result.ciwaru.rc[0]);
147 if (!rc) { 222 if (!rc) {
148 rc = '68'; 223 rc = '68';
149 } 224 }
150 } 225 }
151 226
152 if ((task.retry == maxRetry) || (rc != '68')) { 227 if ((task.retry == maxRetry) || (rc != '68')) {
153 callbackReport(trxid, rc, message); 228 callbackReport(task.requestId, rc, message);
154 } else { 229 } else {
155 logger.info('Not reporting to AAA for duplicate 68', {task: task}); 230 logger.info('Not reporting to AAA for duplicate 68', {task: task});
156 } 231 }
157 232
158 if (rc == '68') { 233 if (rc == '68') {
159 topupRequestRetry(task); 234 topupRequestRetry(task);
160 } 235 }
161 }); 236 });
162 } 237 }
163 238
164 function topupRequestRetry(task) { 239 function topupRequestRetry(task) {
165 task.retry--; 240 task.retry--;
166 241
167 if (task.retry > 0) { 242 if (task.retry > 0) {
168 logger.info('Retrying in ' + sleepBeforeRetry + 's'); 243 logger.info('Retrying in ' + sleepBeforeRetry + 's');
169 setTimeout(topupRequest, sleepBeforeRetry * 1000, task, task.retry); 244 setTimeout(topupRequest, sleepBeforeRetry * 1000, task, task.retry);
170 } 245 }
171 else { 246 else {
172 logger.warn('Maximum retry for pending status exceeded', {task: task}); 247 logger.warn('Maximum retry for pending status exceeded', {task: task});
173 } 248 }
174 } 249 }
175 250
176 function topupRequest(task, retry) { 251 function topupRequest(task, retry) {
177 252
178 if (retry === undefined) { 253 if (retry === undefined) {
254 insertTaskToMongoDb(task);
179 retry = maxRetry; 255 retry = maxRetry;
180 } 256 }
181 257
182 if (!task.retry) { 258 if (!task.retry) {
183 task.retry = retry; 259 task.retry = retry;
184 } 260 }
185 261
186 var remoteProduct = task.remoteProduct.split(','); 262 var remoteProduct = task.remoteProduct.split(',');
187 263
188 var params = { 264 var params = {
189 trxtype: '01', 265 trxtype: '01',
190 prdcode: remoteProduct[0], 266 prdcode: remoteProduct[0],
191 value: remoteProduct[1], 267 value: remoteProduct[1],
192 msisdn: task.destination, 268 msisdn: task.destination,
193 trxid: task.requestId, 269 trxid: task.requestId,
194 uid: config.h2h_out.userid, 270 uid: config.h2h_out.userid,
195 password: config.h2h_out.password, 271 password: config.h2h_out.password,
196 }; 272 };
197 273
198 var postBody = createXmlPayload(params); 274 var postBody = createXmlPayload(params);
199 275
200 var partnerUrl = url.parse(config.h2h_out.partner); 276 var partnerUrl = url.parse(config.h2h_out.partner);
201 var postRequest = { 277 var postRequest = {
202 host: partnerUrl.hostname, 278 host: partnerUrl.hostname,
203 path: partnerUrl.path, 279 path: partnerUrl.path,
204 port: partnerUrl.port, 280 port: partnerUrl.port,
205 method: "POST", 281 method: "POST",
206 headers: { 282 headers: {
207 'Content-Type': 'text/xml', 283 'Content-Type': 'text/xml',
208 'Content-Length': Buffer.byteLength(postBody) 284 'Content-Length': Buffer.byteLength(postBody)
209 } 285 }
210 }; 286 };
211 287
212 logger.info('POST to partner', {postRequest: postRequest}); 288 logger.info('POST to partner', {postRequest: postRequest});
213 var req = http.request(postRequest, function( res ) { 289 var req = http.request(postRequest, function( res ) {
214 290
215 logger.info('Status code: ' + res.statusCode ); 291 logger.info('Status code: ' + res.statusCode );
216 var buffer = ""; 292 var buffer = "";
217 res.on( "data", function( data ) { buffer = buffer + data; } ); 293 res.on( "data", function( data ) { buffer = buffer + data; } );
218 res.on( "end", function( data ) { 294 res.on( "end", function( data ) {
219 topupResponseHandler(buffer, task); 295 topupResponseHandler(buffer, task);
220 }); 296 });
221 }); 297 });
222 298
223 req.on('error', function(e) { 299 req.on('error', function(e) {
224 logger.warn('problem with request: ' + e.message); 300 logger.warn('problem with request: ' + e.message);
225 callbackReport(task['requestId'], '68', e.message); 301 callbackReport(task['requestId'], '68', e.message);
226 302
227 topupRequestRetry(task); 303 topupRequestRetry(task);
228 }); 304 });
229 305
230 req.write(postBody); 306 req.write(postBody);
231 req.end(); 307 req.end();
232 } 308 }
233 309
234 exports.start = start; 310 exports.start = start;
235 exports.topupRequest = topupRequest; 311 exports.topupRequest = topupRequest;
236 exports.calculateSignature = calculateSignature; 312 exports.calculateSignature = calculateSignature;
237 exports.createXmlPayload = createXmlPayload; 313 exports.createXmlPayload = createXmlPayload;
238 exports.getSNFromMessage = getSNFromMessage; 314 exports.getSNFromMessage = getSNFromMessage;
239 315