Commit 60fa6ddb465ae83e3d3c1895b449f0dcb392ac66
1 parent
2fbb21dc08
Exists in
master
coba ditest
Showing 5 changed files with 273 additions and 0 deletions Inline Diff
.gitignore
File was created | 1 | node_modules/ | |
2 | config.ini | ||
3 | config.ini.backup* | ||
4 | run.sh | ||
5 | admin-cli.js | ||
6 | logs/ | ||
7 |
index.js
File was created | 1 | var fs = require('fs'); | |
2 | var ini = require('ini'); | ||
3 | var expresso = require('sate24-expresso'); | ||
4 | var config = ini.parse(fs.readFileSync(__dirname + '/config.ini', 'utf-8')); | ||
5 | |||
6 | process.chdir(__dirname); | ||
7 | |||
8 | var logDirectory = __dirname + '/logs'; | ||
9 | fs.existsSync(logDirectory) || fs.mkdirSync(logDirectory); | ||
10 | |||
11 | var logger = require('sate24/logger.js').start(); | ||
12 | var HttpServer = require('sate24/httpserver.js'); | ||
13 | var aaa = require('sate24/aaa.js'); | ||
14 | var partner = require('./partner-fm.js'); | ||
15 | |||
16 | var matrix = aaa.prepareMatrix(); | ||
17 | |||
18 | var options = { | ||
19 | 'aaa': aaa, | ||
20 | 'logger': logger, | ||
21 | 'config': config, | ||
22 | 'matrix': matrix, | ||
23 | } | ||
24 | |||
25 | var httpServer = HttpServer.start(config, options); | ||
26 | |||
27 | partner.start(config, aaa.callbackReport, options); | ||
28 | aaa.start(config, partner, options); | ||
29 | expresso.start(options); | ||
30 |
package.json
File was created | 1 | { | |
2 | "name": "sate24-to-fm-bp", | ||
3 | "version": "1.0.0", | ||
4 | "description": "ST24 H2H-OUT to FM based on belanjapulsa.com", | ||
5 | "main": "index.js", | ||
6 | "scripts": { | ||
7 | "test": "mocha" | ||
8 | }, | ||
9 | "repository": { | ||
10 | "type": "git", | ||
11 | "url": "git@gitlab.kodesumber.com:reload97/sate24-to-fm-bp.git" | ||
12 | }, | ||
13 | "keywords": [ | ||
14 | "st24", | ||
15 | "reload97", | ||
16 | "r97", | ||
17 | "ppob", | ||
18 | "fm", | ||
19 | "flashmachine" | ||
20 | ], | ||
21 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", | ||
22 | "license": "ISC", | ||
23 | "dependencies": { | ||
24 | "request": "^2.74.0", | ||
25 | "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git", | ||
26 | "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git", | ||
27 | "xml2js": "^0.4.17" | ||
28 | }, | ||
29 | "devDependencies": { | ||
30 | "should": "^11.1.0" | ||
31 | } | ||
32 | } | ||
33 |
partner-fm.js
File was created | 1 | var xml2js = require('xml2js'); | |
2 | |||
3 | var aaa; | ||
4 | var _callbackReport; | ||
5 | var config; | ||
6 | var logger; | ||
7 | |||
8 | var xmlBuilder = new xml2js.Builder(); | ||
9 | |||
10 | function start(options) { | ||
11 | if (!options) { | ||
12 | console.log('Undefined options, terminating....'); | ||
13 | process.exit(1); | ||
14 | } | ||
15 | |||
16 | if (options.config) { | ||
17 | config = options.config; | ||
18 | } else { | ||
19 | console.log('Undefined options.config, terminating....') | ||
20 | process.exit(1); | ||
21 | } | ||
22 | |||
23 | if (options.aaa) { | ||
24 | aaa = options.aaa; | ||
25 | _callbackReport = options.aaa.callbackReportWithPushToMongoDb; | ||
26 | } else { | ||
27 | console.log('Undefined options.aaa, terminating....') | ||
28 | process.exit(1); | ||
29 | } | ||
30 | |||
31 | if (options && options.logger) { | ||
32 | logger = options.logger; | ||
33 | } else { | ||
34 | console.log('Undefined options.logger, terminating....') | ||
35 | process.exit(1); | ||
36 | } | ||
37 | |||
38 | createServer(); | ||
39 | |||
40 | /* | ||
41 | resendDelay.init({ | ||
42 | config: config, | ||
43 | topupRequest: topupRequest, | ||
44 | logger: logger | ||
45 | }); | ||
46 | */ | ||
47 | } | ||
48 | |||
49 | function topupRequest(task) { | ||
50 | aaa.insertTaskToMongoDb(task); | ||
51 | |||
52 | var payload = composeTopupStatusMessage( | ||
53 | config.h2h_out.pin, | ||
54 | task.remoteProduct, | ||
55 | task.destination, | ||
56 | task.requestId | ||
57 | ); | ||
58 | |||
59 | var reqOpts = { | ||
60 | url: config.h2h_out.partner_url, | ||
61 | method: "POST", | ||
62 | headers: { | ||
63 | 'Content-Type': 'text/xml', | ||
64 | 'Content-Length': Buffer.byteLength(payload) | ||
65 | } | ||
66 | } | ||
67 | |||
68 | logger.verbose('Requesting to partner', {reqOpts: reqOpts, payload: payload}); | ||
69 | var buffer = ""; | ||
70 | var req = http.request(reqOpts, function( res ) { | ||
71 | |||
72 | logger.info('Status code: ' + res.statusCode ); | ||
73 | var buffer = ""; | ||
74 | res.on( "data", function( data ) { buffer = buffer + data; } ); | ||
75 | res.on( "end", function( data ) { | ||
76 | logger.verbose('Got a direct response from partner', {response: buffer, task: task}); | ||
77 | topupResponseHandler(buffer, task.requestId); | ||
78 | }); | ||
79 | }); | ||
80 | } | ||
81 | |||
82 | function topupResponseHandler(xmlResponse, _requestId, cb) { | ||
83 | var xmlParser = xml2js.parseString; | ||
84 | xmlParser(xmlResponse, function(err, data) { | ||
85 | var msg; | ||
86 | var requestId; | ||
87 | var rc = '68'; | ||
88 | |||
89 | if (_requestId) { | ||
90 | requestId = _requestId; | ||
91 | } | ||
92 | |||
93 | if (err) { | ||
94 | msg = 'Error parsing xml response: ' + err; | ||
95 | |||
96 | if (logger) { | ||
97 | logger.warn(msg, {err: err, response: xmlResponse, task: task}); | ||
98 | } else { | ||
99 | console.log(msg); | ||
100 | } | ||
101 | } else { | ||
102 | |||
103 | try { | ||
104 | msg = data.fm.message | ||
105 | } | ||
106 | catch(e) { | ||
107 | msg = 'Unknown message' | ||
108 | } | ||
109 | |||
110 | if (data.fm.status == '0') { | ||
111 | |||
112 | rc = '00'; | ||
113 | msg = modifyMessageWithSn(msg); | ||
114 | |||
115 | } else if (data.fm.status == '1') { | ||
116 | rc = '68'; | ||
117 | } else if (data.fm.status == '2') { | ||
118 | rc = '40'; | ||
119 | } else if (data.fm.status == '3') { | ||
120 | rc = '40'; | ||
121 | } else { | ||
122 | rc = '68'; | ||
123 | } | ||
124 | |||
125 | if (data.fm.refTrxid) { | ||
126 | requestId = data.fm.refTrxid; | ||
127 | } | ||
128 | |||
129 | } | ||
130 | |||
131 | cb(requestId, rc, msg, xmlResponse) | ||
132 | }); | ||
133 | } | ||
134 | |||
135 | function callbackReport(requestId, responseCode, msg, rawResponse) { | ||
136 | if (requestId) { | ||
137 | _callbackReport(requestId, responseCode, msg, null, rawResponse); | ||
138 | } else { | ||
139 | logger.warn('Undefined requestId, not sending callbackReport', {rc: responseCode, msg: msg, rawResponse: rawResponse}); | ||
140 | } | ||
141 | |||
142 | } | ||
143 | |||
144 | function getSnFromMessage(msg) { | ||
145 | try { | ||
146 | var matches = msg.match(/SN:(\w+)/); | ||
147 | return matches[1]; | ||
148 | } | ||
149 | catch(e) { | ||
150 | return; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | function modifyMessageWithSn(msg) { | ||
155 | var sn = getSnFromMessage(msg); | ||
156 | if (sn) { | ||
157 | msg = 'SN=' + sn + '; ' + msg; | ||
158 | } | ||
159 | return msg; | ||
160 | } | ||
161 | |||
162 | function composeTopupStatusMessage(pin, product, destination, requestId) { | ||
163 | var data = {fm: { | ||
164 | command: 'TOPUP', | ||
165 | pin: pin, | ||
166 | product: product, | ||
167 | msisdn: destination, | ||
168 | refTrxid: requestId | ||
169 | }} | ||
170 | |||
171 | return xmlBuilder.buildObject(data); | ||
172 | } | ||
173 | |||
174 | exports.start = start; | ||
175 | exports.topupRequest = topupRequest; | ||
176 | exports.composeTopupStatusMessage = composeTopupStatusMessage; | ||
177 | exports.getSnFromMessage = getSnFromMessage; | ||
178 | exports.modifyMessageWithSn = modifyMessageWithSn; | ||
179 |
test.js
File was created | 1 | var should = require('should'); | |
2 | var crypto = require('crypto'); | ||
3 | |||
4 | describe('#partner', function () { | ||
5 | var partner = require('./partner-fm') | ||
6 | |||
7 | describe('#composeTopupStatusMessage', function() { | ||
8 | it('should return correct xml message', function() { | ||
9 | var msg = partner.composeTopupStatusMessage('1234', 'S10', '08120812', '2345'); | ||
10 | crypto.createHash('sha256').update(msg, 'utf8').digest().toString('hex').should.equal('1b926cb9101d9b172ae12206d0c10d4800b553f3d9f2e320fe526c7effb11985'); | ||
11 | }) | ||
12 | }); | ||
13 | |||
14 | describe('#getSnFromMessage', function() { | ||
15 | it('should return correct sn', function() { | ||
16 | partner.getSnFromMessage('S10.081300000000 berhasil, SN:123456789').should.equal('123456789'); | ||
17 | }); | ||
18 | }) | ||
19 | |||
20 | describe('#modifyMessageWithSn', function() { | ||
21 | it('should return correct sn', function() { | ||
22 | partner.modifyMessageWithSn('S10.081300000000 berhasil.').should.equal('S10.081300000000 berhasil.'); | ||
23 | partner.modifyMessageWithSn('S10.081300000000 berhasil, SN:').should.equal('S10.081300000000 berhasil, SN:'); | ||
24 | partner.modifyMessageWithSn('S10.081300000000 berhasil, SN:123456789').should.equal('SN=123456789; S10.081300000000 berhasil, SN:123456789'); | ||
25 | partner.modifyMessageWithSn('S10.081300000000 berhasil, SN:123456789. Berita tambahan').should.equal('SN=123456789; S10.081300000000 berhasil, SN:123456789. Berita tambahan'); | ||
26 | }); | ||
27 | }); | ||
28 | }) | ||
29 |