From fb2ba8c5da083cb5d9558773bf7ffb2a0a81fcaf Mon Sep 17 00:00:00 2001
From: Adhidarma Hadiwinoto <gua@adhisimon.org>
Date: Wed, 21 Mar 2018 16:26:27 +0700
Subject: [PATCH] ready to run

---
 .gitignore            |  4 +++
 README                |  1 +
 config.sample.json    | 21 ++++++++++++
 index.js              |  8 +++++
 lib/partner-rc.json   |  8 +++++
 lib/partner.js        | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/reverse-report.js | 50 ++++++++++++++++++++++++++++
 lib/st24.js           | 35 ++++++++++++++++++++
 package.json          | 28 ++++++++++++++++
 9 files changed, 247 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 config.sample.json
 create mode 100644 index.js
 create mode 100644 lib/partner-rc.json
 create mode 100644 lib/partner.js
 create mode 100644 lib/reverse-report.js
 create mode 100644 lib/st24.js
 create mode 100644 package.json

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8e2eaef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+/node_modules/
+/config.json
+/tmp/
+/logs/
diff --git a/README b/README
index e69de29..2b2d50a 100644
--- a/README
+++ b/README
@@ -0,0 +1 @@
+Komodo gateway to ST24 XML-RPC
diff --git a/config.sample.json b/config.sample.json
new file mode 100644
index 0000000..a83de93
--- /dev/null
+++ b/config.sample.json
@@ -0,0 +1,21 @@
+{
+    "handler_name": "ST24",
+    "products": [
+        "PLEASE_CHANGE_ME"
+    ],
+    "core_url": "http://127.0.0.1:32972/apikey/PLEASE_CHANGE_ME",
+    "pull_interval_ms": 1000,
+    "partner": {
+        "url": "https://PLEASE_CHANGE_ME:6789/",
+        "msidn": "PLEASE_CHANGE_ME",
+        "pin": "PLEASE_CHANGE_ME"
+    },
+    "remote_products": {
+        "PLEASE_CHANGE_ME": "PLEASE_CHANGE_ME"
+    },
+    "reverse_report_port": 27440,
+    "control_panel": {
+        "listen_port": 27441
+    },
+    "do_not_verbose_log_report": true
+}
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..0d9322b
--- /dev/null
+++ b/index.js
@@ -0,0 +1,8 @@
+"use strict";
+process.chdir(__dirname);
+
+const pullgw = require('komodo-sdk/gateway/pull');
+const partner = require('./lib/partner');
+const reverseReport = require('./lib/reverse-report');
+
+pullgw.setPartner(partner);
diff --git a/lib/partner-rc.json b/lib/partner-rc.json
new file mode 100644
index 0000000..0a109e8
--- /dev/null
+++ b/lib/partner-rc.json
@@ -0,0 +1,8 @@
+{
+    "00": "00",
+    "13": "90",
+    "14": "14",
+    "68": "68",
+    "91": "90",
+    "94": "68"
+}
diff --git a/lib/partner.js b/lib/partner.js
new file mode 100644
index 0000000..57ef0b0
--- /dev/null
+++ b/lib/partner.js
@@ -0,0 +1,92 @@
+"use strict";
+
+process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
+
+const url = require('url');
+const xmlrpc = require('xmlrpc');
+
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+const matrix = require('komodo-sdk/matrix');
+const pull = require('komodo-sdk/gateway/pull');
+
+const st24 = require('./st24');
+const partnerRc = require('./partner-rc.json');
+
+function buy(task) {
+    const partnerUrl = url.parse(config.partner.url);
+    const clientOptions = {
+        host: partnerUrl.hostname,
+        port: partnerUrl.port,
+        path: partnerUrl.pathname
+    };
+
+    let client;
+    if (partnerUrl.protocol == 'https:') {
+        client = xmlrpc.createSecureClient(clientOptions);
+    } else {
+        client = xmlrpc.createClient(clientOptions);
+    }
+
+    const params = {
+        MSISDN: config.partner.msisdn || config.partner.userid,
+        REQUESTID: task.trx_id,
+        PIN: config.partner.pin || config.partner.password,
+        NOHP: task.destination,
+        NOM: task.remote_product
+    };
+
+    const xmlrpcMethod = 'topUpRequest';
+    logger.info('Preparing XMLRPC request', {method: xmlrpcMethod, params: params, partnerUrl: partnerUrl.href});
+
+    client.methodCall(xmlrpcMethod, [ params ], function (err, value) {
+
+        if (err) {
+            let rc = '68';
+            let msg = 'XMLRPC Client Error: ' + err;
+
+            if (error.code == 'ECONNREFUSED' || error.code == 'EHOSTUNREACH' || (error.code == 'ETIMEDOUT' && error.syscall == "connect")) {
+                rc = '91';
+            }
+
+            logger.warn(msg, {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, err: err});
+            report({
+                trx_id: task.trx_id,
+                rc: rc,
+                message: 'INTERNAL: ' + msg,
+                misc: {
+                    task: task
+                }
+            });
+
+            return;
+        }
+
+        logger.info('Got XMLRPC response from partner for', {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, response: value});
+        matrix.last_topupRequest_ack = value;
+
+        report({
+            trx_id: task.trx_id,
+            rc: partnerRc[value.RESPONSECODE] || '40',
+            message: value.MESSAGE,
+            sn: value.SN || st24.extractSnFromMessage(value.MESSAGE),
+            amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE),
+            raw: value,
+            misc: {
+                task: task
+            }
+        });
+    });
+}
+
+function advice(task) {
+}
+
+function report(data) {
+    matrix.last_report_to_core = data;
+    pull.report(data);
+}
+
+exports.buy = buy;
+exports.advice = advice;
+exports.report = report;
diff --git a/lib/reverse-report.js b/lib/reverse-report.js
new file mode 100644
index 0000000..3101899
--- /dev/null
+++ b/lib/reverse-report.js
@@ -0,0 +1,50 @@
+"use strict";
+
+const xmlrpc = require('xmlrpc');
+
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+const matrix = require('komodo-sdk/matrix');
+const pull = require('komodo-sdk/gateway/pull');
+
+const st24 = require('./st24');
+const partner = require('./partner');
+const partnerRc = require('./partner-rc.json');
+
+function create() {
+    const server = xmlrpc.createServer({
+        port: config.reverse_report_port
+    });
+
+    logger.info('Reverse report server listen on port ' + config.reverse_report_port);
+
+    server.on('NotFound', function (method, params) {
+        logger.warn('REVERSEREPORT: Unknown method recevied on XMLRPC server', {method: method, params: params});
+    });
+
+    server.on('topUpReport', function (err, params, callback) {
+
+        logger.info('REVERSEREPORT: Got XMLRPC topUpReport request from partner', {method: 'topUpReport', params: params});
+        matrix.last_topupReport_params = params;
+
+        const paramsCount = params.length;
+        for (let i = 0; i < paramsCount; i++) {
+            let value = params[i];
+
+            partner.report({
+                trx_id: value.REQUESTID,
+                rc: partnerRc[value.RESPONSECODE] || '40',
+                message: value.MESSAGE,
+                sn: value.SN || st24.extractSnFromMessage(value.MESSAGE),
+                amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE),
+                raw: value,
+                misc: {
+                }
+            });
+        }
+
+        callback(null, 'ACK REPORT OK');
+    })
+}
+
+create();
diff --git a/lib/st24.js b/lib/st24.js
new file mode 100644
index 0000000..bd5b311
--- /dev/null
+++ b/lib/st24.js
@@ -0,0 +1,35 @@
+"use strict";
+
+function extractSnFromMessage(msg) {
+    if (!msg || typeof msg !== 'string') {
+        return;
+    }
+
+    let match = msg.match(/^SN=(.*?);/);
+    if (!match || match.length < 2) {
+        return;
+    }
+
+    return match[1];
+}
+
+function extractPriceFromMsg(msg) {
+    if (!msg || typeof msg !== 'string') {
+        return;
+    }
+
+    let match = msg.match(/\d,HRG=(.*?),ID=/);
+    if (!match || match.length < 2) {
+        return;
+    }
+
+    if (!match[1]) {
+        return;
+    }
+
+    return parseInt(match[1].replace(/\./g, ''));
+}
+
+
+exports.extractSnFromMessage = extractSnFromMessage;
+exports.extractPriceFromMsg = extractPriceFromMsg;
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..7fa8604
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "komodo-gw-st24",
+  "version": "0.1.0",
+  "description": "Komodo Gateway to ST24 XML-RPC",
+  "main": "index.js",
+  "scripts": {
+    "test": "mocha",
+    "postversion": "git push && git push --tags"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git@gitlab.kodesumber.com:komodo/komodo-gw-st24.git"
+  },
+  "keywords": [
+    "komodo",
+    "tektrans",
+    "ppob",
+    "st24",
+    "xmlrpc",
+    "xml-rpc"
+  ],
+  "author": "Adhidarma Hadiwinoto <me@adhisimon.org>",
+  "license": "ISC",
+  "dependencies": {
+    "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git",
+    "xmlrpc": "^1.3.2"
+  }
+}
-- 
1.9.0