Commit 3080232bfb492d79a9c1ccce315d014681b35c20
0 parents
Exists in
master
initial comit
Showing 9 changed files with 472 additions and 0 deletions Inline Diff
.gitignore
File was created | 1 | node_modules/ | |
2 | config.ini | ||
3 | log.txt | ||
4 | logs/log* | ||
5 |
aaa.js
File was created | 1 | var request = require('request'); | |
2 | var strftime = require('strftime'); | ||
3 | |||
4 | var max_retry = 10; | ||
5 | var sleep_before_retry = 3000; | ||
6 | |||
7 | var config; | ||
8 | var partner; | ||
9 | |||
10 | var available_products = []; | ||
11 | |||
12 | function unaliasResponseCode(response_code, config_responsecode_alias) { | ||
13 | if (config_responsecode_alias == undefined && config && config.h2h_out && config.h2h_out.responsecode_alias) { | ||
14 | config_responsecode_alias = config.h2h_out.responsecode_alias; | ||
15 | } | ||
16 | |||
17 | if (!config_responsecode_alias) { | ||
18 | return response_code; | ||
19 | } | ||
20 | |||
21 | items = config_responsecode_alias.split(','); | ||
22 | items_count = items.length; | ||
23 | |||
24 | for (var i=0; i < items_count; i++) { | ||
25 | codes = items[i].split(':'); | ||
26 | |||
27 | if (codes.length <= 0) { continue; } | ||
28 | |||
29 | if (response_code == codes[0]) { | ||
30 | console.log('Change response code from ' + codes[0] + ' to ' + codes[1]); | ||
31 | return codes[1]; | ||
32 | } | ||
33 | } | ||
34 | |||
35 | return response_code; | ||
36 | } | ||
37 | |||
38 | function pullCity() { | ||
39 | var url = config.globals.aaa_host + '/pull_city'; | ||
40 | console.log('Pull cities from AAA - ' + url); | ||
41 | request(url, function (error, response, body) { | ||
42 | if (!error && response.statusCode == 200) { | ||
43 | //console.log('city=' + body); | ||
44 | } else { | ||
45 | console.log('Error in pull city'); | ||
46 | } | ||
47 | }); | ||
48 | } | ||
49 | |||
50 | function pullProduct() { | ||
51 | var url = config.globals.aaa_host + '/pull_product?opr_name=' + config.globals.operators; | ||
52 | console.log('Pull products from AAA - ' + url); | ||
53 | |||
54 | request(url, function (error, response, body) { | ||
55 | if (error || response.statusCode != 200) { | ||
56 | console.log('Error in pull products'); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | var productsAndOperators = body.split(';'); | ||
61 | var productsCount = productsAndOperators.length; | ||
62 | |||
63 | for (var i=0; i < productsCount; i++) { | ||
64 | var product = productsAndOperators[i].split(',', 1)[0]; | ||
65 | available_products.push(product); | ||
66 | } | ||
67 | //console.log(available_products); | ||
68 | }); | ||
69 | } | ||
70 | |||
71 | function pull() { | ||
72 | var url = config.globals.aaa_host | ||
73 | + '/pull?city=ALL&nom=' + config.globals.products | ||
74 | + '&chip_info=' + config.globals.gateway_name; | ||
75 | |||
76 | //console.log('AAA PULL - ' + url); | ||
77 | request(url, function (error, response, body) { | ||
78 | if (!error && response.statusCode == 200) { | ||
79 | if (body == 'NONE') { | ||
80 | return; | ||
81 | } | ||
82 | console.log(body); | ||
83 | |||
84 | var result = body.split(';'); | ||
85 | if (result[0] != 'OK') { | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | var task = []; | ||
90 | task['requestId'] = result[1]; | ||
91 | task['timestamp'] = result[3]; | ||
92 | task['destination'] = result[4]; | ||
93 | task['product'] = result[7]; | ||
94 | |||
95 | if (config.products[task['product']] !== undefined) { | ||
96 | task['remoteProduct'] = config.products[task['product']]; | ||
97 | } else { | ||
98 | task['remoteProduct'] = task['product']; | ||
99 | } | ||
100 | |||
101 | partner.topupRequest(task); | ||
102 | |||
103 | } else { | ||
104 | console.log('Error in pull task'); | ||
105 | return; | ||
106 | } | ||
107 | }); | ||
108 | } | ||
109 | |||
110 | function pullLoop() { | ||
111 | if (!config.globals.pause) { | ||
112 | pull(); | ||
113 | } | ||
114 | |||
115 | setTimeout(pullLoop, config.globals.interval); | ||
116 | } | ||
117 | |||
118 | function callbackReport(requestId, responseCode, message, retry) { | ||
119 | if (retry === undefined) { | ||
120 | retry = max_retry; | ||
121 | } | ||
122 | |||
123 | responseCode = unaliasResponseCode(responseCode); | ||
124 | |||
125 | timestamp = strftime('%Y%m%d%H%M%S'); | ||
126 | var url = config.globals.aaa_host | ||
127 | + '/topup?trans_id=' + requestId | ||
128 | + '&trans_date' + timestamp | ||
129 | + '&trans_date=' + timestamp | ||
130 | + '&resp_code=' + responseCode | ||
131 | + '&ussd_msg=' + config.globals.gateway_name | ||
132 | + '$' + encodeURIComponent(message); | ||
133 | |||
134 | console.log('Report to AAA - ' + url); | ||
135 | request(url, function (error, response, body) { | ||
136 | if (error || response.statusCode != 200) { | ||
137 | console.log('Error report to AAA'); | ||
138 | |||
139 | if (retry) { | ||
140 | console.log('Retrying to report to AAA (' + retry + ')'); | ||
141 | callbackReport(requestId, responseCode, message, retry - 1); | ||
142 | } | ||
143 | } | ||
144 | }); | ||
145 | } | ||
146 | |||
147 | function start(_config, _partner) { | ||
148 | config = _config; | ||
149 | partner = _partner; | ||
150 | |||
151 | pullCity(); | ||
152 | pullProduct(); | ||
153 | |||
154 | setTimeout(pullLoop, 10 * 1000); | ||
155 | } | ||
156 | |||
157 | exports.start = start; | ||
158 | exports.callbackReport = callbackReport; | ||
159 | exports.unaliasResponseCode = unaliasResponseCode; | ||
160 |
config.sample.ini
File was created | 1 | [globals] | |
2 | operators=TEST,XL_ALTERNATIF | ||
3 | products=TST1 | ||
4 | gateway_name=NODEJS-DEV | ||
5 | aaa_host=http://172.23.0.12:4250 | ||
6 | interval=1000 | ||
7 | admin_port=17456 | ||
8 | |||
9 | [h2h_out] | ||
10 | partner=https://172.23.0.12:6789 | ||
11 | userid=R97DEV | ||
12 | password=czcb | ||
13 | listen_port=13522 | ||
14 | check_interval=2000 | ||
15 | |||
16 | [products] | ||
17 | TST1=TR1 | ||
18 | |||
19 |
httpserver.js
File was created | 1 | var http = require('http'); | |
2 | var nsr = require('node-simple-router'); | ||
3 | var router = nsr(); | ||
4 | |||
5 | var config; | ||
6 | var httpServer; | ||
7 | |||
8 | function start(_config) { | ||
9 | if (_config != undefined) { | ||
10 | config = _config; | ||
11 | } | ||
12 | listenPort = config.globals.admin_port; | ||
13 | |||
14 | router.get("/info", function(request, response) { | ||
15 | response.setHeader("Content-Type", "text/plain"); | ||
16 | response.write('CHIPINFO / GATEWAY NAME: ' + config.globals.gateway_name + "\n"); | ||
17 | response.write('PRODUCTS: ' + config.globals.products + "\n"); | ||
18 | response.write('AAA HOST: ' + config.globals.aaa_host + "\n"); | ||
19 | response.write('PARTNER: ' + config.h2h_out.partner + "\n"); | ||
20 | response.write('PAUSED: ' + config.globals.pause + "\n"); | ||
21 | response.write('UPTIME: ' + process.uptime() + "\n"); | ||
22 | response.write('REQUESTS COUNT: ' + config.globals.requests_count + "\n"); | ||
23 | response.write('ACTIVE REQUESTS COUNT: ' + config.globals.active_requests_count + "\n"); | ||
24 | response.write('MAX ACTIVE REQUESTS COUNT: ' + config.globals.max_active_requests_count + "\n"); | ||
25 | |||
26 | response.end(); | ||
27 | }); | ||
28 | |||
29 | router.get("/pause/:apikey", function(request, response) { | ||
30 | if (!config.globals.apikey) { | ||
31 | response.end('Undefined APIKEY on config'); | ||
32 | return; | ||
33 | } | ||
34 | |||
35 | if (request.params.apikey != config.globals.apikey) { | ||
36 | response.end('Invalid APIKEY'); | ||
37 | return; | ||
38 | } | ||
39 | |||
40 | config.globals.pause = 1; | ||
41 | response.end('Paused'); | ||
42 | }); | ||
43 | |||
44 | router.get("/resume/:apikey", function(request, response) { | ||
45 | if (!config.globals.apikey) { | ||
46 | response.end('Undefined APIKEY on config'); | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | if (request.params.apikey != config.globals.apikey) { | ||
51 | response.end('Invalid APIKEY'); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | delete config.globals.pause; | ||
56 | response.end('Resume'); | ||
57 | }); | ||
58 | |||
59 | router.get("/reset-stats/:apikey", function(request, response) { | ||
60 | if (!config.globals.apikey) { | ||
61 | response.end('Undefined APIKEY on config'); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | if (request.params.apikey != config.globals.apikey) { | ||
66 | response.end('Invalid APIKEY'); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | config.globals.max_active_requests_count = 0; | ||
71 | |||
72 | response.writeHead(307, { | ||
73 | 'Location': '/info' | ||
74 | }); | ||
75 | |||
76 | response.end(); | ||
77 | }); | ||
78 | |||
79 | httpServer = http.createServer(router).listen(listenPort); | ||
80 | console.log('HTTP server listens on port ' + listenPort); | ||
81 | |||
82 | return httpServer; | ||
83 | } | ||
84 | |||
85 | function setConfig(_config) { | ||
86 | config = _config; | ||
87 | } | ||
88 | |||
89 | exports.start = start; | ||
90 | exports.setConfig = setConfig; | ||
91 |
index.js
File was created | 1 | var iniparser = require('iniparser'); | |
2 | var config = iniparser.parseSync('./config.ini'); | ||
3 | |||
4 | var aaaHost = config.globals.aaa_host; | ||
5 | |||
6 | HttpServer = require('./httpserver.js'); | ||
7 | var httpServer = HttpServer.start(config); | ||
8 | |||
9 | var aaa = require('./aaa.js'); | ||
10 | var partner = require('./partner-scrappingkisel.js'); | ||
11 | |||
12 | partner.start(config, aaa.callbackReport); | ||
13 | aaa.start(config, partner); | ||
14 |
logs/empty
package.json
File was created | 1 | { | |
2 | "name": "sate24-to-sc", | ||
3 | "version": "0.0.1", | ||
4 | "description": "ST24 to SimpleConnect H2H OUT", | ||
5 | "main": "index.js", | ||
6 | "scripts": { | ||
7 | "test": "mocha" | ||
8 | }, | ||
9 | "repository": { | ||
10 | "type": "git", | ||
11 | "url": "git@gitlab.kodesumber.com:reload97/sate24-to-sc.git" | ||
12 | }, | ||
13 | "keywords": [ | ||
14 | "st24", | ||
15 | "reload97", | ||
16 | "ppob", | ||
17 | "h2h", | ||
18 | "m2m", | ||
19 | "xmlrpc" | ||
20 | ], | ||
21 | "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>", | ||
22 | "license": "BSD", | ||
23 | "dependencies": { | ||
24 | "mocha": "~2.2.5", | ||
25 | "request": "~2.57.0", | ||
26 | "strftime": "~0.9.2", | ||
27 | "iniparser": "~1.0.5", | ||
28 | "mathjs": "~1.7.0", | ||
29 | "xmlrpc": "~1.3.1", | ||
30 | "xml2js": "~0.4.9", | ||
31 | "redis": "~0.12.1", | ||
32 | "hiredis": "~0.4.0", | ||
33 | "node-simple-router": "~0.9.4-2" | ||
34 | } | ||
35 | } | ||
36 |
partner-scrappingkisel.js
File was created | 1 | var fs = require('fs'); | |
2 | var https = require('https'); | ||
3 | var http = require('http'); | ||
4 | var url = require('url'); | ||
5 | var request = require('request'); | ||
6 | var xml2js = require('xml2js').parseString; | ||
7 | var strftime = require('strftime'); | ||
8 | var math = require('mathjs'); | ||
9 | |||
10 | var config; | ||
11 | var httpServer; | ||
12 | |||
13 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; | ||
14 | |||
15 | var logTag = __filename.split('/').reverse()[0]; | ||
16 | |||
17 | function topupRequest(task) { | ||
18 | if (config.globals.requests_count == undefined) { | ||
19 | config.globals.requests_count = 1; | ||
20 | } else { | ||
21 | config.globals.requests_count++; | ||
22 | } | ||
23 | |||
24 | if (config.globals.active_requests_count == undefined) { | ||
25 | config.globals.active_requests_count = 1; | ||
26 | } else { | ||
27 | config.globals.active_requests_count++; | ||
28 | } | ||
29 | |||
30 | if (config.globals.max_active_requests_count == undefined) { | ||
31 | config.globals.max_active_requests_count = config.globals.active_requests_count; | ||
32 | } else { | ||
33 | config.globals.max_active_requests_count = math.max(config.globals.max_active_requests_count, config.globals.active_requests_count); | ||
34 | } | ||
35 | |||
36 | var options = { | ||
37 | url: config.h2h_out.partner, | ||
38 | qs: { | ||
39 | reqid: task['requestId'], | ||
40 | msisdn: task['destination'], | ||
41 | product: task['product'] | ||
42 | } | ||
43 | }; | ||
44 | console.log(options); | ||
45 | |||
46 | request(options, function (error, response, body) { | ||
47 | if (config.globals.active_requests_count == undefined) { | ||
48 | config.globals.active_requests_count = 0; | ||
49 | } else { | ||
50 | config.globals.active_requests_count--; | ||
51 | } | ||
52 | |||
53 | if (error || response.statusCode != 200) { | ||
54 | console.log(logTag + ': Gateway Error'); | ||
55 | callbackReport(task['requestId'], '40', 'Gateway Error'); | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | console.log(logTag + ': Supplier response:'); | ||
60 | console.log(body); | ||
61 | |||
62 | xml2js(body, function (err, result) { | ||
63 | if (err) { | ||
64 | callbackReport(task['requestId'], '40', body); | ||
65 | return; | ||
66 | } | ||
67 | |||
68 | console.log(result); | ||
69 | |||
70 | var response_code = '68'; | ||
71 | var message = result.trx_response.info[0].trim(); | ||
72 | |||
73 | if (message == 'Error Parsing') { | ||
74 | |||
75 | response_code = '40'; | ||
76 | |||
77 | } else if (message == "Phone number's not found") { | ||
78 | |||
79 | response_code = '14'; | ||
80 | |||
81 | } else if (message == "TRANSAKSI SUKSES !!!") { | ||
82 | var destination = result.trx_response.msisdn.join(' ').trim(); | ||
83 | var product = result.trx_response.product.join(' ').trim(); | ||
84 | var ref_num = result.trx_response.ref_num.join(' ').trim(); | ||
85 | var harga = result.trx_response.harga.join(' ').trim(); | ||
86 | var kode_voucher = result.trx_response.kode_voucher.join(' ').trim(); | ||
87 | |||
88 | response_code = '00'; | ||
89 | |||
90 | message = 'SN=' + ref_num + '; ' + product + ' ' + msisdn + ' ' + harga + ' ref_num: ' + ref_num + ' kode_voucher: ' + kode_voucher; | ||
91 | } | ||
92 | |||
93 | callbackReport(task['requestId'], response_code, message); | ||
94 | }); | ||
95 | }); | ||
96 | } | ||
97 | |||
98 | function start(_config, _callbackReport) { | ||
99 | config = _config; | ||
100 | callbackReport = _callbackReport | ||
101 | } | ||
102 | |||
103 | exports.start = start; | ||
104 | exports.topupRequest = topupRequest; | ||
105 |
test.js
File was created | 1 | var assert = require("assert"); | |
2 | |||
3 | |||
4 | describe('aaa', function() { | ||
5 | var aaa = require('./aaa'); | ||
6 | |||
7 | describe("#unaliasResponseCode()", function() { | ||
8 | it('should return 68', function() { | ||
9 | assert.equal('68', aaa.unaliasResponseCode('01', '01:68')); | ||
10 | }); | ||
11 | |||
12 | it('should return 68', function() { | ||
13 | assert.equal('68', aaa.unaliasResponseCode('68', '01:68')); | ||
14 | }); | ||
15 | |||
16 | it('should return 00', function() { | ||
17 | assert.equal('00', aaa.unaliasResponseCode('00', '01:68')); | ||
18 | }); | ||
19 | |||
20 | it('should return 40', function() { | ||
21 | assert.equal('40', aaa.unaliasResponseCode('40', '')); | ||
22 | }); | ||
23 | |||
24 | it('should return 40', function() { | ||
25 | assert.equal('40', aaa.unaliasResponseCode('40', '')); | ||
26 | }); | ||
27 | |||
28 | it('should return 40', function() { | ||
29 | assert.equal('40', aaa.unaliasResponseCode('40')); | ||
30 | }); | ||
31 | |||
32 | }); | ||
33 | }); | ||
34 | |||
35 | describe('aaa', function() { | ||
36 | var partner = require('./httppulsakita'); | ||
37 | |||
38 | describe("#parseResult()", function() { | ||
39 | message = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><respon><tanggal>2015/6/16 15:43:35</tanggal><idagen>P0039</idagen><refid>AEE15B32987941D89FFF4BC7EF676C13</refid><produk>PLN20</produk><tujuan>14204279369</tujuan><rc>0000</rc><data> </data><token> </token><pesan>#14836 PLN20 ke:14204279369 SUKSES. SN:3520-2887-6627-6699-4826/TestDummyPanjang6955555/P1/7000VA/32,4. \ | ||
40 | Sisa saldo Rp. 5,000,000 - Rp. 18,700 = Rp. 4,981,300</pesan></respon>'; | ||
41 | |||
42 | data = partner.parseResult(message); | ||
43 | console.log(data); | ||
44 | |||
45 | it('should return 2015/6/16 15:43:35', function() { | ||
46 | assert.equal('2015/6/16 15:43:35', data.respon.tanggal); | ||
47 | }); | ||
48 | }); | ||
49 | }); | ||
50 |