From cd4feda874d40350602bf6821c4d9bef6e0d8bed Mon Sep 17 00:00:00 2001
From: Adhidarma Hadiwinoto <adhisimon@gmail.com>
Date: Mon, 31 May 2021 16:11:53 +0700
Subject: [PATCH] APISERVER and MATRIX

---
 config.sample.json                    |  4 +++
 index.js                              |  2 ++
 lib/apiserver/index.js                | 47 +++++++++++++++++++++++++++++++++++
 lib/apiserver/routers/matrix.js       | 18 ++++++++++++++
 lib/apiserver/valid-apikey.js         |  6 +++++
 lib/core-callback/index.js            |  3 +++
 lib/core-callback/sender.js           | 12 +++++++++
 lib/matrix.js                         | 20 +++++++++++++++
 lib/middlewares/common.js             | 13 +++++++---
 lib/partner-listener/index.js         |  7 ++++++
 lib/partner-listener/routers/topup.js |  3 +++
 11 files changed, 132 insertions(+), 3 deletions(-)
 create mode 100644 lib/apiserver/index.js
 create mode 100644 lib/apiserver/routers/matrix.js
 create mode 100644 lib/apiserver/valid-apikey.js
 create mode 100644 lib/matrix.js

diff --git a/config.sample.json b/config.sample.json
index 37f00c3..69a9585 100644
--- a/config.sample.json
+++ b/config.sample.json
@@ -11,6 +11,10 @@
         },
         "core": {
             "port": 25615
+        },
+        "apiserver": {
+            "port": 25617,
+            "apikey": "PLEASE_CHANGE_ME"
         }
     },
 
diff --git a/index.js b/index.js
index 0813bfb..1720bbc 100644
--- a/index.js
+++ b/index.js
@@ -30,6 +30,8 @@ if (config.cluster && cluster.isMaster) {
     }
 
     // eslint-disable-next-line global-require
+    require('./lib/apiserver');
+    // eslint-disable-next-line global-require
     require('./lib/core-callback');
     // eslint-disable-next-line global-require
     require('./lib/partner-listener');
diff --git a/lib/apiserver/index.js b/lib/apiserver/index.js
new file mode 100644
index 0000000..081cf32
--- /dev/null
+++ b/lib/apiserver/index.js
@@ -0,0 +1,47 @@
+const MODULE_NAME = 'APISERVER';
+
+const express = require('express');
+const config = require('komodo-sdk/config');
+const logger = require('komodo-sdk/logger');
+
+const validApikey = require('./valid-apikey');
+
+const middlewareCommon = require('../middlewares/common');
+const routerMatrix = require('./routers/matrix');
+
+const app = express();
+
+app.use((req, res, next) => {
+    res.locals.httpgetx_subsystem = MODULE_NAME;
+    next();
+});
+
+const apikeyChecker = (req, res, next) => {
+    if (validApikey(req.params.apikey)) {
+        next();
+    } else {
+        res.status(403).end('Invalid APIKEY');
+    }
+};
+
+app.use(middlewareCommon);
+
+app.use('/apikey/:apikey', apikeyChecker);
+app.use('/apikey/:apikey/matrix', routerMatrix);
+
+app.use((req, res) => {
+    const { xid } = res.locals;
+    res.status(404).end(`KOMODO-HTTP-GET-X CENTER (APISERVER).\n404: Method not found.\n\nXID: ${xid}.\n`);
+});
+
+const listenPort = config.listener && config.listener.apiserver && config.listener.apiserver.port;
+if (
+    listenPort
+    && config.listener && config.listener.apiserver && config.listener.apiserver.apikey
+) {
+    app.listen(listenPort, () => {
+        logger.info(`${MODULE_NAME} FAEE1E47: Listening`, { port: listenPort });
+    });
+} else {
+    logger.info(`${MODULE_NAME}: Disabled because of missing configuration`);
+}
diff --git a/lib/apiserver/routers/matrix.js b/lib/apiserver/routers/matrix.js
new file mode 100644
index 0000000..2f34fd9
--- /dev/null
+++ b/lib/apiserver/routers/matrix.js
@@ -0,0 +1,18 @@
+const express = require('express');
+
+const os = require('os');
+const matrix = require('../../matrix');
+
+const router = express.Router();
+module.exports = router;
+
+const pageIndex = (req, res) => {
+    matrix.uptime = process.uptime();
+    matrix.loadavg = os.loadavg();
+    matrix.workdir = process.cwd;
+    matrix.memory_usage = process.memoryUsage();
+
+    res.json(matrix);
+};
+
+router.all('/', pageIndex);
diff --git a/lib/apiserver/valid-apikey.js b/lib/apiserver/valid-apikey.js
new file mode 100644
index 0000000..9f706c1
--- /dev/null
+++ b/lib/apiserver/valid-apikey.js
@@ -0,0 +1,6 @@
+const config = require('komodo-sdk/config');
+
+module.exports = (apikey) => apikey
+    && apikey === (
+        config.listener && config.listener.apiserver && config.listener.apiserver.apikey
+    );
diff --git a/lib/core-callback/index.js b/lib/core-callback/index.js
index 41604e0..c4561de 100644
--- a/lib/core-callback/index.js
+++ b/lib/core-callback/index.js
@@ -7,6 +7,8 @@ const config = require('komodo-sdk/config');
 const logger = require('komodo-sdk/logger');
 const middlewareCommon = require('../middlewares/common');
 const sender = require('./sender');
+const matrix = require('../matrix');
+
 
 const app = express();
 
@@ -21,6 +23,7 @@ app.use((req, res, next) => {
 app.use(middlewareCommon);
 
 app.use((req, res) => {
+    matrix.messages_from_core += 1;
     res.end('OK');
     sender(req.query, res.locals.xid);
 });
diff --git a/lib/core-callback/sender.js b/lib/core-callback/sender.js
index ff3fa0a..47c72a4 100644
--- a/lib/core-callback/sender.js
+++ b/lib/core-callback/sender.js
@@ -4,6 +4,8 @@ const axios = require('axios').default;
 const config = require('komodo-sdk/config');
 const logger = require('komodo-sdk/logger');
 
+const matrix = require('../matrix');
+
 const HTTP_TIMEOUT = Number(
     config.callback_sender && config.callback_sender.http_timeout_ms,
 ) || 30 * 1000;
@@ -98,6 +100,14 @@ const sender = async (data, xid, retry) => {
                 headers: axiosHeaders,
             });
 
+        matrix.callback_sender.message_sent += 1;
+
+        if (isPostpaid) {
+            matrix.callback_sender.message_sent_using_post_method += 1;
+        } else {
+            matrix.callback_sender.message_sent_using_get_method += 1;
+        }
+
         logger.info(`${MODULE_NAME} 3641FBD7: Has been sent to PARTNER successfully`, {
             xid,
             retry,
@@ -105,6 +115,8 @@ const sender = async (data, xid, retry) => {
             responseBody: response && response.data,
         });
     } catch (e) {
+        matrix.callback_sender.message_sent_failed += 1;
+
         logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending to PARTNER`, {
             xid,
             retry,
diff --git a/lib/matrix.js b/lib/matrix.js
new file mode 100644
index 0000000..3721775
--- /dev/null
+++ b/lib/matrix.js
@@ -0,0 +1,20 @@
+const os = require('os');
+// const config = require('komodo-sdk/config');
+
+module.exports = {
+    pid: process.pid,
+    start_time: new Date(),
+    uptime: process.uptime(),
+    hostname: os.hostname(),
+    loadavg: os.loadavg(),
+    workdir: process.cwd(),
+    memory_usage: process.memoryUsage(),
+    messages_from_core: 0,
+    messages_to_core: 0,
+    callback_sender: {
+        message_sent: 0,
+        message_sent_failed: 0,
+        message_sent_using_get_method: 0,
+        message_sent_using_post_method: 0,
+    },
+};
diff --git a/lib/middlewares/common.js b/lib/middlewares/common.js
index debe156..ae159c2 100644
--- a/lib/middlewares/common.js
+++ b/lib/middlewares/common.js
@@ -1,5 +1,9 @@
-// const uuidv1 = require('uuid/v1');
+const MODULE_NAME = 'MIDDLEWARES';
+
+const uuidv1 = require('uuid/v1');
 const uniqid = require('uniqid');
+
+const config = require('komodo-sdk/config');
 const logger = require('komodo-sdk/logger');
 
 module.exports = function common(req, res, next) {
@@ -8,12 +12,15 @@ module.exports = function common(req, res, next) {
         return;
     }
 
-    res.locals.xid = uniqid();
+    res.locals.xid = config.xid_from_uuid ? uuidv1()
+        : uniqid();
+
     res.locals.x_http_request_ts = new Date();
 
-    logger.info(`Got request from ${res.locals.httpgetx_subsystem === 'CORE-CALLBACK' ? 'CORE' : 'PARTNER'}`, {
+    logger.info(`${MODULE_NAME}.COMMON B6257542: Got a request`, {
         xid: res.locals.xid,
         pid: process.pid,
+        subsystem: res.locals.httpgetx_subsystem,
         requester_ip: req.ip,
         method: req.method,
         path: req.path,
diff --git a/lib/partner-listener/index.js b/lib/partner-listener/index.js
index 8cc88a8..1ac4b44 100644
--- a/lib/partner-listener/index.js
+++ b/lib/partner-listener/index.js
@@ -1,3 +1,5 @@
+const MODULE_NAME = 'PARTNER-LISTENER';
+
 const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614;
 
 const express = require('express');
@@ -18,6 +20,11 @@ if (config.partner && config.partner.trust_proxy) {
     app.set('trust proxy', config.partner.trust_proxy);
 }
 
+app.use((req, res, next) => {
+    res.locals.httpgetx_subsystem = MODULE_NAME;
+    next();
+});
+
 app.use(express.json({ extended: true }));
 app.use(express.urlencoded({ extended: true }));
 app.use(middlewareCommon);
diff --git a/lib/partner-listener/routers/topup.js b/lib/partner-listener/routers/topup.js
index 40d44a0..7bdea2e 100644
--- a/lib/partner-listener/routers/topup.js
+++ b/lib/partner-listener/routers/topup.js
@@ -6,6 +6,7 @@ const config = require('komodo-sdk/config');
 const logger = require('komodo-sdk/logger');
 const coreapi = require('komodo-sdk/coreapi');
 // const coreapi = require('../../coreapi');
+const matrix = require('../../matrix');
 
 const router = express.Router();
 module.exports = router;
@@ -58,6 +59,8 @@ async function pageIndex(req, res) {
 
     const terminalName = `${req.body.terminal_name || req.query.terminal_name}@${req.ip.replace(/^::ffff:/, '')}`;
 
+    matrix.messages_to_core += 1;
+
     const [err, coreResponse] = await coreapi({
         xid,
         path: '/prepaid/buy',
-- 
1.9.0