Commit 05158bd37278cc8f8405d3f03158f091ce635e1d

Authored by Adhidarma Hadiwinoto
0 parents
Exists in master

initial commit

Showing 9 changed files with 570 additions and 0 deletions Side-by-side Diff

... ... @@ -0,0 +1,4 @@
  1 +node_modules/
  2 +config.ini
  3 +log.txt
  4 +logs/log*
... ... @@ -0,0 +1,159 @@
  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;
... ... @@ -0,0 +1,18 @@
  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 +
... ... @@ -0,0 +1,90 @@
  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;
... ... @@ -0,0 +1,13 @@
  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 xmlout = require('./xmlout.js');
  11 +
  12 +xmlout.start(config, aaa.callbackReport);
  13 +aaa.start(config, xmlout);
... ... @@ -0,0 +1,31 @@
  1 +{
  2 + "name": "sate24-to-sate24",
  3 + "version": "0.0.1",
  4 + "description": "ST24 to ST24 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-sate24.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 + }
  31 +}
... ... @@ -0,0 +1,33 @@
  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 +});
... ... @@ -0,0 +1,222 @@
  1 +var xmlrpc = require('xmlrpc');
  2 +var url = require('url');
  3 +var math = require('mathjs');
  4 +
  5 +var config;
  6 +var callbackReport;
  7 +
  8 +var max_retry = 2;
  9 +var sleep_before_retry = 2000;
  10 +
  11 +process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
  12 +
  13 +function topupRequest(task, retry) {
  14 + if (config.globals.requests_count == undefined) {
  15 + config.globals.requests_count = 1;
  16 + } else {
  17 + config.globals.requests_count++;
  18 + }
  19 +
  20 + if (config.globals.active_requests_count == undefined) {
  21 + config.globals.active_requests_count = 1;
  22 + } else {
  23 + config.globals.active_requests_count++;
  24 + }
  25 +
  26 + if (config.globals.max_active_requests_count == undefined) {
  27 + config.globals.max_active_requests_count = config.globals.active_requests_count;
  28 + } else {
  29 + config.globals.max_active_requests_count = math.max(config.globals.max_active_requests_count, config.globals.active_requests_count);
  30 + }
  31 +
  32 +
  33 + if (retry === undefined) {
  34 + retry = max_retry;
  35 + }
  36 +
  37 + var partnerUrl = url.parse(config.h2h_out.partner);
  38 + var clientOptions = {
  39 + host: partnerUrl.hostname
  40 + , port: partnerUrl.port
  41 + , path: partnerUrl.pathname
  42 + };
  43 + console.log('XMLRPC client options:');
  44 + console.log(clientOptions);
  45 +
  46 + var client;
  47 + if (partnerUrl.protocol == 'https:') {
  48 + console.log('Use SSL');
  49 + client = xmlrpc.createSecureClient(clientOptions);
  50 + } else {
  51 + console.log('Not using SSL');
  52 + client = xmlrpc.createClient(clientOptions);
  53 + }
  54 +
  55 + var methodName = 'topUpRequest';
  56 + console.log('methodName: ' + methodName);
  57 +
  58 + var params = {
  59 + MSISDN: config.h2h_out.userid,
  60 + REQUESTID: task['requestId'],
  61 + PIN: config.h2h_out.password,
  62 + NOHP: task['destination'],
  63 + NOM: task['remoteProduct']
  64 + };
  65 + console.log('PARAMS:');
  66 + console.log(params);
  67 +
  68 +
  69 + client.methodCall(methodName, [ params ], function (error, value) {
  70 +
  71 + if (config.globals.active_requests_count == undefined) {
  72 + config.globals.active_requests_count = 0;
  73 + } else {
  74 + config.globals.active_requests_count--;
  75 + }
  76 +
  77 + // Results of the method response
  78 + if (error) {
  79 + console.log('XMLRPC Client Error (' + task['requestId'] + '): ');
  80 + console.log(error);
  81 +
  82 + if (retry) {
  83 +
  84 + console.log('Retrying topUpRequest (' + retry + ')');
  85 + setTimeout(function() {
  86 + topupRequest(task, retry - 1);
  87 + }, sleep_before_retry);
  88 +
  89 + } else {
  90 + callbackReport(task['requestId'], '40', 'Gangguan koneksi ke suplier');
  91 + }
  92 + return;
  93 + }
  94 +
  95 + console.log('Method response for \'' + methodName + '\': ')
  96 + console.log(value);
  97 +
  98 + if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') {
  99 + value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE'];
  100 + //console.log('Message with SN: ' + value['MESSAGE']);
  101 + }
  102 +
  103 + callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']);
  104 + });
  105 +}
  106 +
  107 +function createServer() {
  108 +
  109 + console.log('Creating XML-RPC server on port ' + config.h2h_out.listen_port);
  110 + var serverOptions = {
  111 + port: config.h2h_out.listen_port
  112 + };
  113 +
  114 + var server = xmlrpc.createServer(serverOptions);
  115 +
  116 + server.on('NotFound', function (method, params) {
  117 + console.log(method + ' is not found on our XML-RPC server');
  118 + console.log('params:');
  119 + console.log(params);
  120 + });
  121 +
  122 + server.on('topUpReport', function (err, params, callback) {
  123 + console.log('RECEIVE topUpReport, params:');
  124 + console.log(params);
  125 +
  126 + var paramscount = params.length;
  127 + for (var i = 0; i < paramscount; i++) {
  128 + var value = params[i];
  129 +
  130 + if (value['RESPONSECODE'] == '00' && config.h2h_out.parse_sn == 'YES') {
  131 + value['MESSAGE'] = 'SN=' + parseSN(value['MESSAGE']) + '; ' + value['MESSAGE'];
  132 + //console.log('Message with SN: ' + value['MESSAGE']);
  133 + }
  134 +
  135 + callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']);
  136 + }
  137 +
  138 + callback(null, 'ACK REPORT OK');
  139 + })
  140 +
  141 +}
  142 +
  143 +function checkStatus(task) {
  144 + var partnerUrl = url.parse(config.h2h_out.partner);
  145 + var clientOptions = {
  146 + host: partnerUrl.hostname
  147 + , port: partnerUrl.port
  148 + , path: partnerUrl.pathname
  149 + };
  150 + console.log('XMLRPC client options:');
  151 + console.log(clientOptions);
  152 +
  153 + var client;
  154 + if (partnerUrl.protocol == 'https:') {
  155 + console.log('Use SSL');
  156 + client = xmlrpc.createSecureClient(clientOptions);
  157 + } else {
  158 + console.log('Not using SSL');
  159 + client = xmlrpc.createClient(clientOptions);
  160 + }
  161 +
  162 + var methodName = 'topUpInquiry';
  163 + console.log('methodName: ' + methodName);
  164 +
  165 + var params = {
  166 + MSISDN: config.h2h_out.userid,
  167 + REQUESTID: task['requestId'],
  168 + PIN: config.h2h_out.password,
  169 + NOHP: task['destination']
  170 + };
  171 + console.log('PARAMS:');
  172 + console.log(params);
  173 +
  174 + client.methodCall(methodName, [ params ], function (error, value) {
  175 + // Results of the method response
  176 + if (error) {
  177 + console.log('Error: ');
  178 + console.log(error);
  179 + return;
  180 + }
  181 + console.log('Method response for \'' + methodName + '\': ')
  182 + console.log(value);
  183 +
  184 + callbackReport(value['REQUESTID'], value['RESPONSECODE'], value['MESSAGE']);
  185 + });
  186 +}
  187 +
  188 +function start(_config, _callbackReport) {
  189 + config = _config;
  190 + callbackReport = _callbackReport
  191 +
  192 + createServer();
  193 +}
  194 +
  195 +function parseSN(message) {
  196 + var sn_regex = new RegExp(config.h2h_out.sn_pattern);
  197 + var sn_match = message.match(sn_regex);
  198 +
  199 + //console.log('SN MATCH:');
  200 + //console.log(sn_match);
  201 +
  202 + if (sn_match <= 0) {
  203 + console.log('SN Not found: ' + message);
  204 + return '';
  205 + }
  206 +
  207 + var sn = sn_match[0];
  208 + var sn_remove_patterns = config.h2h_out.sn_remove_patterns.split(config.h2h_out.sn_remove_patterns_separator);
  209 + //console.log('SN REMOVE PATTERNS:');
  210 + //console.log (sn_remove_patterns);
  211 +
  212 + var count = sn_remove_patterns.length;
  213 +
  214 + for(var i = 0; i < count; i++) {
  215 + sn = sn.replace(sn_remove_patterns[i], '');
  216 + }
  217 +
  218 + return sn.trim();
  219 +}
  220 +
  221 +exports.start = start;
  222 +exports.topupRequest = topupRequest;