Commit 5443b922a7960d4a2770198890a3b3188bcd4088

Authored by adi surya
1 parent c6ed7016e1
Exists in master

file lib

Showing 29 changed files with 1244 additions and 0 deletions Side-by-side Diff

1 1 node_modules
  2 +config.json
2 3 \ No newline at end of file
... ... @@ -0,0 +1,22 @@
  1 +{
  2 + "name": "gateway-sds-ss",
  3 + "url": "http://localhost",
  4 + "port": 11330,
  5 + "apikey": "fd97cf519b979262d9d9004cba6a165629ca8b69350a6afdcaab6ab2c9a996ae",
  6 + "pull_interval_ms": 5000,
  7 + "core": {
  8 + "url": "http://localhost:26840",
  9 + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnZW5lcmF0b3IiOiJDTEkiLCJjbGllbnQiOnsibmFtZSI6IktPTU9ETzItR1ctU0RTLVNTIn0sImlhdCI6MTY1ODkwODA4N30.2Ego28jwgPs3s9-iKSbYipO72FTH5gFC5gkVccqiN24",
  10 + "request_timeout_ms": 10000
  11 + },
  12 + "products": {
  13 + },
  14 + "postpaid_products": {
  15 + },
  16 + "sds_ss": {
  17 + "url": "http://localhost:8187/request",
  18 + "request_timeout_ms": 10000,
  19 + "username": "user",
  20 + "password": "1234"
  21 + }
  22 +}
... ... @@ -0,0 +1,9 @@
  1 +process.chdir(__dirname);
  2 +
  3 +const fs = require('fs');
  4 +const pull = require('./lib/pull');
  5 +require('./lib/http-server');
  6 +
  7 +pull.run();
  8 +
  9 +fs.writeFileSync('pid.txt', process.pid.toString());
... ... @@ -0,0 +1,71 @@
  1 +const MODULE_NAME = 'ACTIONS.BUY';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +
  9 +const topupToKomodo = require('./topup-to-komodo');
  10 +
  11 +const client = axios.create({
  12 + baseURL: config.core.url,
  13 + timeout: config.core.request_timeout_ms,
  14 + headers: {
  15 + 'x-access-token': config.core.access_token,
  16 + },
  17 +});
  18 +
  19 +/**
  20 + * Buy a product from supplier komodo
  21 + *
  22 + * @param {string} xid
  23 + * @param {object} transaction
  24 + *
  25 + */
  26 +module.exports = async (xid, transaction) => {
  27 + try {
  28 + logger.verbose(`${MODULE_NAME} 4B139379: Buy product to komodo`, {
  29 + xid,
  30 + transaction,
  31 + });
  32 + const iConfig = await configData.all();
  33 +
  34 + let productName = transaction.product_name;
  35 + if (
  36 + iConfig.products[transaction.product_name]
  37 + && iConfig.products[transaction.product_name].remote
  38 + ) {
  39 + productName = iConfig.products[transaction.product_name].remote;
  40 + }
  41 +
  42 + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`;
  43 + const result = await topupToKomodo(
  44 + xid,
  45 + transaction.id,
  46 + transaction.destination,
  47 + productName,
  48 + callbackUrl,
  49 + );
  50 + logger.verbose(`${MODULE_NAME} 5BDFAF41: result from komodo`, {
  51 + xid,
  52 + trxId: transaction.id,
  53 + result,
  54 + });
  55 + const params = {
  56 + id: result.request_id,
  57 + rc: result.rc,
  58 + amount: result.amount || null,
  59 + message: result.message,
  60 + sn: result.sn || null,
  61 + };
  62 +
  63 + await client.post('/transactions/gateway-update', params);
  64 + } catch (e) {
  65 + logger.warn(`${MODULE_NAME} E9887C98: Exception`, {
  66 + xid,
  67 + message: e.message,
  68 + code: e.code,
  69 + });
  70 + }
  71 +};
lib/actions/index.js
... ... @@ -0,0 +1,3 @@
  1 +exports.buy = require('./buy');
  2 +exports.inquiry = require('./inquiry');
  3 +exports.pay = require('./pay');
lib/actions/inquiry-to-komodo.js
... ... @@ -0,0 +1,64 @@
  1 +const MODULE_NAME = 'ACTIONS.INQUIRY-TO-KOMODO';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +
  8 +const client = axios.create({
  9 + baseURL: config.komodo_http_get_x.url,
  10 + timeout: config.komodo_http_get_x.request_timeout_ms,
  11 +});
  12 +
  13 +/**
  14 + * request inquiry transaction to komodo
  15 + *
  16 + * @param {string} xid
  17 + * @param {string} requestId
  18 + * @param {string} destination
  19 + * @param {string} productName
  20 + * @param {string} reverseUrl
  21 + */
  22 +module.exports = async (
  23 + xid,
  24 + requestId,
  25 + destination,
  26 + productName,
  27 + reverseUrl,
  28 +) => {
  29 + logger.verbose(`${MODULE_NAME} 4AD4DF41: request inquiry to komodo`, {
  30 + requestId, destination, productName, reverseUrl, xid,
  31 + });
  32 +
  33 + const params = {
  34 + request_id: requestId,
  35 + terminal_name: config.komodo_http_get_x.terminal_name,
  36 + password: config.komodo_http_get_x.password,
  37 + destination,
  38 + product_name: productName,
  39 + reverse_url: reverseUrl,
  40 + };
  41 +
  42 + try {
  43 + const response = await client.get('/inquiry', {
  44 + params,
  45 + });
  46 + if (!response) {
  47 + throw new Error(`${MODULE_NAME} 6CE3E06E: Empty response from komodo`);
  48 + }
  49 + if (!response.data) {
  50 + throw new Error(`${MODULE_NAME} F236476F: Empty response data from komodo`);
  51 + }
  52 +
  53 + return response.data;
  54 + } catch (err) {
  55 + logger.warn(`${MODULE_NAME} 48BAA6B7: Exception`, {
  56 + xid,
  57 + requestId,
  58 + destination,
  59 + productName,
  60 + message: err.message,
  61 + });
  62 + throw err;
  63 + }
  64 +};
lib/actions/inquiry.js
... ... @@ -0,0 +1,71 @@
  1 +const MODULE_NAME = 'ACTIONS.INQUIRY';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +
  9 +const inquiryToKomodo = require('./inquiry-to-komodo');
  10 +
  11 +const client = axios.create({
  12 + baseURL: config.core.url,
  13 + timeout: config.core.request_timeout_ms,
  14 + headers: {
  15 + 'x-access-token': config.core.access_token,
  16 + },
  17 +});
  18 +
  19 +/**
  20 + * Inquiry a product from supplier komodo
  21 + *
  22 + * @param {string} xid
  23 + * @param {object} transaction
  24 + *
  25 + */
  26 +module.exports = async (xid, transaction) => {
  27 + try {
  28 + logger.verbose(`${MODULE_NAME} ABE82225: Inquiry product to komodo`, {
  29 + xid,
  30 + transaction,
  31 + });
  32 + const iConfig = await configData.all();
  33 +
  34 + let productName = transaction.product_name;
  35 + if (
  36 + iConfig.postpaid_products[transaction.product_name]
  37 + && iConfig.postpaid_products[transaction.product_name].remote
  38 + ) {
  39 + productName = iConfig.postpaid_products[transaction.product_name].remote;
  40 + }
  41 +
  42 + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`;
  43 + const result = await inquiryToKomodo(
  44 + xid,
  45 + transaction.id,
  46 + transaction.destination,
  47 + productName,
  48 + callbackUrl,
  49 + );
  50 + logger.verbose(`${MODULE_NAME} 076C1206: result from komodo`, {
  51 + xid,
  52 + trxId: transaction.id,
  53 + result,
  54 + });
  55 + const params = {
  56 + id: result.request_id,
  57 + rc: result.rc,
  58 + amount: result.amount || null,
  59 + message: result.message,
  60 + sn: result.sn || null,
  61 + };
  62 +
  63 + await client.post('/transactions/gateway-update', params);
  64 + } catch (e) {
  65 + logger.warn(`${MODULE_NAME} D1A1B698: Exception`, {
  66 + xid,
  67 + message: e.message,
  68 + code: e.code,
  69 + });
  70 + }
  71 +};
... ... @@ -0,0 +1,71 @@
  1 +const MODULE_NAME = 'ACTIONS.PAY';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +
  9 +const paymentToKomodo = require('./payment-to-komodo');
  10 +
  11 +const client = axios.create({
  12 + baseURL: config.core.url,
  13 + timeout: config.core.request_timeout_ms,
  14 + headers: {
  15 + 'x-access-token': config.core.access_token,
  16 + },
  17 +});
  18 +
  19 +/**
  20 + * Pay a product from supplier komodo
  21 + *
  22 + * @param {string} xid
  23 + * @param {object} transaction
  24 + *
  25 + */
  26 +module.exports = async (xid, transaction) => {
  27 + try {
  28 + logger.verbose(`${MODULE_NAME} CB9506E9: Pay product to komodo`, {
  29 + xid,
  30 + transaction,
  31 + });
  32 + const iConfig = await configData.all();
  33 +
  34 + let productName = transaction.product_name;
  35 + if (
  36 + iConfig.postpaid_products[transaction.product_name]
  37 + && iConfig.postpaid_products[transaction.product_name].remote
  38 + ) {
  39 + productName = iConfig.postpaid_products[transaction.product_name].remote;
  40 + }
  41 +
  42 + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`;
  43 + const result = await paymentToKomodo(
  44 + xid,
  45 + transaction.id,
  46 + transaction.destination,
  47 + productName,
  48 + callbackUrl,
  49 + );
  50 + logger.verbose(`${MODULE_NAME} 4F45F9E3: result from komodo`, {
  51 + xid,
  52 + trxId: transaction.id,
  53 + result,
  54 + });
  55 + const params = {
  56 + id: result.request_id,
  57 + rc: result.rc,
  58 + amount: result.amount || null,
  59 + message: result.message,
  60 + sn: result.sn || null,
  61 + };
  62 +
  63 + await client.post('/transactions/gateway-update', params);
  64 + } catch (e) {
  65 + logger.warn(`${MODULE_NAME} EF0EE887: Exception`, {
  66 + xid,
  67 + message: e.message,
  68 + code: e.code,
  69 + });
  70 + }
  71 +};
lib/actions/payment-to-komodo.js
... ... @@ -0,0 +1,64 @@
  1 +const MODULE_NAME = 'ACTIONS.PAY-TO-KOMODO';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +
  8 +const client = axios.create({
  9 + baseURL: config.komodo_http_get_x.url,
  10 + timeout: config.komodo_http_get_x.request_timeout_ms,
  11 +});
  12 +
  13 +/**
  14 + * request pay transaction to komodo
  15 + *
  16 + * @param {string} xid
  17 + * @param {string} requestId
  18 + * @param {string} destination
  19 + * @param {string} productName
  20 + * @param {string} reverseUrl
  21 + */
  22 +module.exports = async (
  23 + xid,
  24 + requestId,
  25 + destination,
  26 + productName,
  27 + reverseUrl,
  28 +) => {
  29 + logger.verbose(`${MODULE_NAME} 740EF164: pay to komodo`, {
  30 + requestId, destination, productName, xid,
  31 + });
  32 +
  33 + const params = {
  34 + request_id: requestId,
  35 + terminal_name: config.komodo_http_get_x.terminal_name,
  36 + password: config.komodo_http_get_x.password,
  37 + destination,
  38 + product_name: productName,
  39 + reverse_url: reverseUrl,
  40 + };
  41 +
  42 + try {
  43 + const response = await client.get('/pay', {
  44 + params,
  45 + });
  46 + if (!response) {
  47 + throw new Error(`${MODULE_NAME} 29D8D56F: Empty response from komodo`);
  48 + }
  49 + if (!response.data) {
  50 + throw new Error(`${MODULE_NAME} 288CD049: Empty response data from komodo`);
  51 + }
  52 +
  53 + return response.data;
  54 + } catch (err) {
  55 + logger.warn(`${MODULE_NAME} DCE65215: Exception`, {
  56 + xid,
  57 + requestId,
  58 + destination,
  59 + productName,
  60 + message: err.message,
  61 + });
  62 + throw err;
  63 + }
  64 +};
lib/actions/topup-to-komodo.js
... ... @@ -0,0 +1,64 @@
  1 +const MODULE_NAME = 'ACTIONS.TOPUP-TO-KOMODO';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +
  6 +const config = require('../config');
  7 +
  8 +const client = axios.create({
  9 + baseURL: config.komodo_http_get_x.url,
  10 + timeout: config.komodo_http_get_x.request_timeout_ms,
  11 +});
  12 +
  13 +/**
  14 + * request topup transaction to komodo
  15 + *
  16 + * @param {string} xid
  17 + * @param {string} requestId
  18 + * @param {string} destination
  19 + * @param {string} productName
  20 + * @param {string} reverseUrl
  21 + */
  22 +module.exports = async (
  23 + xid,
  24 + requestId,
  25 + destination,
  26 + productName,
  27 + reverseUrl,
  28 +) => {
  29 + logger.verbose(`${MODULE_NAME} 4AD4DF41: topup to komodo`, {
  30 + requestId, destination, productName, xid,
  31 + });
  32 +
  33 + const params = {
  34 + request_id: requestId,
  35 + terminal_name: config.komodo_http_get_x.terminal_name,
  36 + password: config.komodo_http_get_x.password,
  37 + destination,
  38 + product_name: productName,
  39 + reverse_url: reverseUrl,
  40 + };
  41 +
  42 + try {
  43 + const response = await client.get('/topup', {
  44 + params,
  45 + });
  46 + if (!response) {
  47 + throw new Error(`${MODULE_NAME} 6CE3E06E: Empty response from komodo`);
  48 + }
  49 + if (!response.data) {
  50 + throw new Error(`${MODULE_NAME} F236476F: Empty response data from komodo`);
  51 + }
  52 +
  53 + return response.data;
  54 + } catch (err) {
  55 + logger.warn(`${MODULE_NAME} 48BAA6B7: Exception`, {
  56 + xid,
  57 + requestId,
  58 + destination,
  59 + productName,
  60 + message: err.message,
  61 + });
  62 + throw err;
  63 + }
  64 +};
... ... @@ -0,0 +1,113 @@
  1 +const MODULE_NAME = 'CONFIG.DATA';
  2 +
  3 +const fs = require('fs/promises');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +let config = {};
  7 +
  8 +/**
  9 + * Get all config
  10 + *
  11 + * @param {string} xid
  12 + *
  13 + * @returns <object>
  14 + */
  15 +async function all(xid) {
  16 + try {
  17 + if (Object.keys(config).length === 0) {
  18 + const configString = await fs.readFile('config.json');
  19 + config = JSON.parse(configString);
  20 + }
  21 + } catch (e) {
  22 + logger.warn(`${MODULE_NAME} ED8D390C: Exception`, {
  23 + xid,
  24 + eMessage: e.message,
  25 + eCode: e.code,
  26 + });
  27 + }
  28 + return config;
  29 +}
  30 +
  31 +/**
  32 + * Get active product prepaid config
  33 + *
  34 + * @param {string} xid
  35 + *
  36 + * @returns <Array>
  37 + */
  38 +async function getActiveProductArray(xid) {
  39 + try {
  40 + if (Object.keys(config).length === 0) {
  41 + const configString = await fs.readFile('config.json');
  42 + config = JSON.parse(configString);
  43 + }
  44 + const allProductsArray = Object.values(config.products);
  45 + if (Array.isArray(allProductsArray)) {
  46 + const activeProductArray = allProductsArray.filter((val) => val.active === 1);
  47 + const activeProductNameArray = activeProductArray.map((val) => val.name);
  48 + return activeProductNameArray;
  49 + }
  50 + } catch (e) {
  51 + logger.warn(`${MODULE_NAME} 2D49D035: Exception`, {
  52 + xid,
  53 + eMessage: e.message,
  54 + eCode: e.code,
  55 + });
  56 + }
  57 + return [];
  58 +}
  59 +
  60 +/**
  61 + * Get active product postpaid config
  62 + *
  63 + * @param {string} xid
  64 + *
  65 + * @returns <Array>
  66 + */
  67 +async function getActiveProductPostpaidArray(xid) {
  68 + try {
  69 + if (Object.keys(config).length === 0) {
  70 + const configString = await fs.readFile('config.json');
  71 + config = JSON.parse(configString);
  72 + }
  73 + const allProductsArray = Object.values(config.postpaid_products);
  74 + if (Array.isArray(allProductsArray)) {
  75 + const activeProductArray = allProductsArray.filter((val) => val.active === 1);
  76 + const activeProductNameArray = activeProductArray.map((val) => val.name);
  77 + return activeProductNameArray;
  78 + }
  79 + } catch (e) {
  80 + logger.warn(`${MODULE_NAME} B5414DB0: Exception`, {
  81 + xid,
  82 + eMessage: e.message,
  83 + eCode: e.code,
  84 + });
  85 + }
  86 + return [];
  87 +}
  88 +
  89 +/**
  90 + * Reload config
  91 + *
  92 + * @param {string} xid
  93 + *
  94 + * @returns <object>
  95 + */
  96 +async function reload(xid) {
  97 + try {
  98 + const configString = await fs.readFile('config.json');
  99 + config = JSON.parse(configString);
  100 + } catch (e) {
  101 + logger.warn(`${MODULE_NAME} D005AED3: Exception`, {
  102 + xid,
  103 + eMessage: e.message,
  104 + eCode: e.code,
  105 + });
  106 + }
  107 + return config;
  108 +}
  109 +
  110 +exports.all = all;
  111 +exports.reload = reload;
  112 +exports.getActiveProductArray = getActiveProductArray;
  113 +exports.getActiveProductPostpaidArray = getActiveProductPostpaidArray;
... ... @@ -0,0 +1,3 @@
  1 +const data = require('../../config.json');
  2 +
  3 +module.exports = data;
lib/config/remove-postpaid-product.js
... ... @@ -0,0 +1,33 @@
  1 +const MODULE_NAME = 'CONFIG.REMOVE-POSTPAID-PRODUCT';
  2 +
  3 +const fs = require('fs/promises');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('./data');
  7 +
  8 +/**
  9 + * Menghapus nilai terkini config.products (postpaid)
  10 + *
  11 + * @param {string} name
  12 + *
  13 + */
  14 +module.exports = async (xid, name) => {
  15 + try {
  16 + logger.verbose(`${MODULE_NAME} B4361668: remove postpaid product from config file`, {
  17 + xid,
  18 + key: name,
  19 + });
  20 + const config = await configData.reload();
  21 +
  22 + delete config.postpaid_products[name];
  23 + await fs.writeFile('config.json', JSON.stringify(config, null, 4));
  24 +
  25 + await configData.reload();
  26 + } catch (e) {
  27 + logger.warn(`${MODULE_NAME} 9E5C6976: Exception`, {
  28 + xid,
  29 + eCode: e.code,
  30 + eMessage: e.message,
  31 + });
  32 + }
  33 +};
lib/config/remove-product.js
... ... @@ -0,0 +1,33 @@
  1 +const MODULE_NAME = 'CONFIG.REMOVE-PREPAID-PRODUCT';
  2 +
  3 +const fs = require('fs/promises');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('./data');
  7 +
  8 +/**
  9 + * Menghapus nilai terkini config.products (prepaid)
  10 + *
  11 + * @param {string} name
  12 + *
  13 + */
  14 +module.exports = async (xid, name) => {
  15 + try {
  16 + logger.verbose(`${MODULE_NAME} 80D1628F: remove prepaid product from config file`, {
  17 + xid,
  18 + key: name,
  19 + });
  20 + const config = await configData.reload();
  21 +
  22 + delete config.products[name];
  23 + await fs.writeFile('config.json', JSON.stringify(config, null, 4));
  24 +
  25 + await configData.reload();
  26 + } catch (e) {
  27 + logger.warn(`${MODULE_NAME} 190BD3D7: Exception`, {
  28 + xid,
  29 + eCode: e.code,
  30 + eMessage: e.message,
  31 + });
  32 + }
  33 +};
lib/config/save-postpaid-product.js
... ... @@ -0,0 +1,32 @@
  1 +const MODULE_NAME = 'CONFIG.SAVE-POSTPAID-PRODUCT';
  2 +
  3 +const fs = require('fs/promises');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('./data');
  7 +
  8 +/**
  9 + * Menyimpan nilai terkini config.products (postpaid)
  10 + *
  11 + */
  12 +module.exports = async (xid, key, value) => {
  13 + try {
  14 + logger.verbose(`${MODULE_NAME} 19BB0554: Saving postpaid product to config file`, {
  15 + xid,
  16 + key,
  17 + value,
  18 + });
  19 + const config = await configData.reload();
  20 +
  21 + config.postpaid_products[key] = value;
  22 + await fs.writeFile('config.json', JSON.stringify(config, null, 4));
  23 +
  24 + await configData.reload();
  25 + } catch (e) {
  26 + logger.warn(`${MODULE_NAME} D0F796A6: Exception`, {
  27 + xid,
  28 + eCode: e.code,
  29 + eMessage: e.message,
  30 + });
  31 + }
  32 +};
lib/config/save-product.js
... ... @@ -0,0 +1,32 @@
  1 +const MODULE_NAME = 'CONFIG.SAVE-PREPAID-PRODUCT';
  2 +
  3 +const fs = require('fs/promises');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('./data');
  7 +
  8 +/**
  9 + * Menyimpan nilai terkini config.products (prepaid)
  10 + *
  11 + */
  12 +module.exports = async (xid, key, value) => {
  13 + try {
  14 + logger.verbose(`${MODULE_NAME} C6D936BF: Saving prepaid product to config file`, {
  15 + xid,
  16 + key,
  17 + value,
  18 + });
  19 + const config = await configData.reload();
  20 +
  21 + config.products[key] = value;
  22 + await fs.writeFile('config.json', JSON.stringify(config, null, 4));
  23 +
  24 + await configData.reload();
  25 + } catch (e) {
  26 + logger.warn(`${MODULE_NAME} 1D1937A9: Exception`, {
  27 + xid,
  28 + eCode: e.code,
  29 + eMessage: e.message,
  30 + });
  31 + }
  32 +};
lib/http-server/index.js
... ... @@ -0,0 +1,40 @@
  1 +const MODULE_NAME = 'HTTP-SERVER';
  2 +
  3 +const express = require('express');
  4 +const uniqid = require('uniqid');
  5 +const logger = require('tektrans-logger');
  6 +
  7 +const config = require('../config');
  8 +const matrix = require('../matrix');
  9 +const checkApikey = require('./middlewares/check-apikey');
  10 +
  11 +const routerMatrix = require('./routers/matrix');
  12 +const routerUpdates = require('./routers/updates');
  13 +const routerProducts = require('./routers/products');
  14 +const routerPostpaidProducts = require('./routers/postpaid-products');
  15 +
  16 +const app = express();
  17 +
  18 +app.use((req, res, next) => {
  19 + matrix.httpServer.requestCounter += 1;
  20 + res.locals.xid = uniqid();
  21 +
  22 + next();
  23 +});
  24 +
  25 +app.use('/matrix', routerMatrix);
  26 +app.use('/apikey/:apikey/updates', [checkApikey], routerUpdates);
  27 +app.use('/apikey/:apikey/products', [checkApikey], routerProducts);
  28 +app.use('/apikey/:apikey/postpaid/products', [checkApikey], routerPostpaidProducts);
  29 +
  30 +app.use((req, res) => {
  31 + res.status(404).json({
  32 + error: true,
  33 + message: 'Method/service not found',
  34 + });
  35 +});
  36 +
  37 +const { port } = config;
  38 +app.listen(port, () => {
  39 + logger.info(`${MODULE_NAME} 35069698: Listening`, { port });
  40 +});
lib/http-server/middlewares/check-apikey.js
... ... @@ -0,0 +1,16 @@
  1 +const config = require('../../config');
  2 +
  3 +module.exports = async (req, res, next) => {
  4 + const { apikey } = req.params;
  5 +
  6 + if (!config.apikey) {
  7 + next();
  8 + } else if (config.apikey === apikey) {
  9 + next();
  10 + } else {
  11 + res.status(403).json({
  12 + error: true,
  13 + message: 'Invalid apikey',
  14 + });
  15 + }
  16 +};
lib/http-server/routers/matrix.js
... ... @@ -0,0 +1,12 @@
  1 +const express = require('express');
  2 +
  3 +const matrixDump = require('../../matrix/dump');
  4 +
  5 +const router = express.Router();
  6 +module.exports = router;
  7 +
  8 +const pageMain = (req, res) => {
  9 + res.json(matrixDump());
  10 +};
  11 +
  12 +router.all('/', pageMain);
lib/http-server/routers/postpaid-products/index.js
... ... @@ -0,0 +1,80 @@
  1 +const MODULE_NAME = 'HTTP-SERVER.ROUTER.POSTPAID-PRODUCTS';
  2 +
  3 +const express = require('express');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('../../../config/data');
  7 +const configSaveProduct = require('../../../config/save-postpaid-product');
  8 +const configRemoveProduct = require('../../../config/remove-postpaid-product');
  9 +
  10 +const router = express.Router();
  11 +
  12 +module.exports = router;
  13 +
  14 +const pageIndex = async (req, res) => {
  15 + const { xid } = res.locals;
  16 + try {
  17 + logger.verbose(`${MODULE_NAME} 24D7D9B4: get postpaid product configuration`, { xid });
  18 + const products = (await configData.all()).postpaid_products || {};
  19 + res.json({ error: false, message: 'OK', result: products });
  20 + } catch (e) {
  21 + logger.warn(`${MODULE_NAME} 1DB45AC5: Exception.`, {
  22 + xid, eMessage: e.message, eCode: e.code,
  23 + });
  24 + res.status(500).json({
  25 + error: true,
  26 + error_code: e.code,
  27 + message: e.message,
  28 + });
  29 + }
  30 +};
  31 +
  32 +const pageSave = async (req, res) => {
  33 + const { xid } = res.locals;
  34 + const { name, remote = null, active = 0 } = req.body;
  35 + try {
  36 + logger.verbose(`${MODULE_NAME} A083E9DC: save postpaid product configuration`, { xid, data: req.body });
  37 +
  38 + const params = {
  39 + name,
  40 + remote,
  41 + active,
  42 + };
  43 + await configSaveProduct(xid, name, params);
  44 + res.json({ error: false, message: 'OK' });
  45 + } catch (e) {
  46 + logger.warn(`${MODULE_NAME} 88B9218F: Exception.`, {
  47 + xid, eMessage: e.message, eCode: e.code,
  48 + });
  49 + res.status(500).json({
  50 + error: true,
  51 + error_code: e.code,
  52 + message: e.message,
  53 + });
  54 + }
  55 +};
  56 +
  57 +const pageRemove = async (req, res) => {
  58 + const { xid } = res.locals;
  59 + const { name } = req.body;
  60 + try {
  61 + logger.verbose(`${MODULE_NAME} 7AD392AE: remove postpaid product configuration`, { xid, name });
  62 +
  63 + await configRemoveProduct(xid, name);
  64 + res.json({ error: false, message: 'OK' });
  65 + } catch (e) {
  66 + logger.warn(`${MODULE_NAME} F714088B: Exception.`, {
  67 + xid, eMessage: e.message, eCode: e.code,
  68 + });
  69 + res.status(500).json({
  70 + error: true,
  71 + error_code: e.code,
  72 + message: e.message,
  73 + });
  74 + }
  75 +};
  76 +
  77 +router.get('/', [express.json()], pageIndex);
  78 +
  79 +router.post('/save', [express.json()], pageSave);
  80 +router.post('/remove', [express.json()], pageRemove);
lib/http-server/routers/products/index.js
... ... @@ -0,0 +1,80 @@
  1 +const MODULE_NAME = 'HTTP-SERVER.ROUTER.PRODUCTS';
  2 +
  3 +const express = require('express');
  4 +const logger = require('tektrans-logger');
  5 +
  6 +const configData = require('../../../config/data');
  7 +const configSaveProduct = require('../../../config/save-product');
  8 +const configRemoveProduct = require('../../../config/remove-product');
  9 +
  10 +const router = express.Router();
  11 +
  12 +module.exports = router;
  13 +
  14 +const pageIndex = async (req, res) => {
  15 + const { xid } = res.locals;
  16 + try {
  17 + logger.verbose(`${MODULE_NAME} F1BF0675: get product configuration`, { xid });
  18 + const products = (await configData.all()).products || {};
  19 + res.json({ error: false, message: 'OK', result: products });
  20 + } catch (e) {
  21 + logger.warn(`${MODULE_NAME} 839E55E0: Exception.`, {
  22 + xid, eMessage: e.message, eCode: e.code,
  23 + });
  24 + res.status(500).json({
  25 + error: true,
  26 + error_code: e.code,
  27 + message: e.message,
  28 + });
  29 + }
  30 +};
  31 +
  32 +const pageSave = async (req, res) => {
  33 + const { xid } = res.locals;
  34 + const { name, remote = null, active = 0 } = req.body;
  35 + try {
  36 + logger.verbose(`${MODULE_NAME} 59CB2503: save product configuration`, { xid, data: req.body });
  37 +
  38 + const params = {
  39 + name,
  40 + remote,
  41 + active,
  42 + };
  43 + await configSaveProduct(xid, name, params);
  44 + res.json({ error: false, message: 'OK' });
  45 + } catch (e) {
  46 + logger.warn(`${MODULE_NAME} 47F57E23: Exception.`, {
  47 + xid, eMessage: e.message, eCode: e.code,
  48 + });
  49 + res.status(500).json({
  50 + error: true,
  51 + error_code: e.code,
  52 + message: e.message,
  53 + });
  54 + }
  55 +};
  56 +
  57 +const pageRemove = async (req, res) => {
  58 + const { xid } = res.locals;
  59 + const { name } = req.body;
  60 + try {
  61 + logger.verbose(`${MODULE_NAME} E94A7B38: remove product configuration`, { xid, name });
  62 +
  63 + await configRemoveProduct(xid, name);
  64 + res.json({ error: false, message: 'OK' });
  65 + } catch (e) {
  66 + logger.warn(`${MODULE_NAME} 955FD7E3: Exception.`, {
  67 + xid, eMessage: e.message, eCode: e.code,
  68 + });
  69 + res.status(500).json({
  70 + error: true,
  71 + error_code: e.code,
  72 + message: e.message,
  73 + });
  74 + }
  75 +};
  76 +
  77 +router.get('/', [express.json()], pageIndex);
  78 +
  79 +router.post('/save', [express.json()], pageSave);
  80 +router.post('/remove', [express.json()], pageRemove);
lib/http-server/routers/updates/index.js
... ... @@ -0,0 +1,69 @@
  1 +const MODULE_NAME = 'HTTP-SERVER.ROUTER.UPDATES';
  2 +
  3 +const express = require('express');
  4 +const axios = require('axios').default;
  5 +const logger = require('tektrans-logger');
  6 +
  7 +const config = require('../../../config');
  8 +
  9 +const router = express.Router();
  10 +
  11 +module.exports = router;
  12 +
  13 +const client = axios.create({
  14 + baseURL: config.core.url,
  15 + timeout: config.core.request_timeout_ms,
  16 + headers: {
  17 + 'x-access-token': config.core.access_token,
  18 + },
  19 +});
  20 +
  21 +const pageUpdate = async (req, res) => {
  22 + const { xid } = res.locals;
  23 + let data = req.query;
  24 + if (req.method.toUpperCase() !== 'GET') {
  25 + data = req.body;
  26 + }
  27 +
  28 + try {
  29 + logger.verbose(`${MODULE_NAME} 9E5C70C8: update from komodo`, { xid, data });
  30 + const params = {
  31 + id: data.request_id,
  32 + rc: data.rc,
  33 + amount: data.amount || null,
  34 + message: data.message,
  35 + sn: data.sn || null,
  36 + bill_count: data.bill_count,
  37 + bill_amount: data.bill_amount,
  38 + related_data: null,
  39 + amount_to_charge: data.amount_to_charge,
  40 + };
  41 +
  42 + client.post('/transactions/gateway-update', params).then((result) => {
  43 + logger.verbose(`${MODULE_NAME} A8DA0D04: response from core2`, {
  44 + xid,
  45 + response: result.data,
  46 + });
  47 + }).catch((err) => {
  48 + logger.warn(`${MODULE_NAME} 32EB485C: Exception on request to core2`, {
  49 + xid,
  50 + eMessage: err.message,
  51 + eCode: err.code,
  52 + });
  53 + });
  54 +
  55 + res.json({ error: false, message: 'OK' });
  56 + } catch (e) {
  57 + logger.warn(`${MODULE_NAME} B12B4A2C: Exception.`, {
  58 + xid, eMessage: e.message, eCode: e.code,
  59 + });
  60 + res.status(500).json({
  61 + error: true,
  62 + error_code: e.code,
  63 + message: e.message,
  64 + });
  65 + }
  66 +};
  67 +
  68 +router.get('/', pageUpdate);
  69 +router.post('/', [express.urlencoded({ extended: true }), express.json()], pageUpdate);
... ... @@ -0,0 +1,10 @@
  1 +const matrix = require('./index');
  2 +
  3 +module.exports = () => {
  4 + matrix.processTitle = process.title;
  5 + matrix.uptimeSecs = process.uptime();
  6 + matrix.memoryUsage = process.memoryUsage();
  7 + matrix.resourceUsage = process.resourceUsage();
  8 +
  9 + return matrix;
  10 +};
... ... @@ -0,0 +1,19 @@
  1 +const data = {
  2 + processTitle: process.title,
  3 + pid: process.pid,
  4 + workingDirectory: process.cwd(),
  5 + uptimeSecs: process.uptime(),
  6 +
  7 + memoryUsage: process.memoryUsage(),
  8 + resourceUsage: process.resourceUsage(),
  9 +
  10 + platform: process.platform,
  11 + nodeVersion: process.version,
  12 + nodeRelease: process.release,
  13 +
  14 + httpServer: {
  15 + requestCounter: 0,
  16 + },
  17 +};
  18 +
  19 +module.exports = data;
lib/pull/get-inquiry.js
... ... @@ -0,0 +1,70 @@
  1 +const MODULE_NAME = 'PULL.GET-INQUIRY';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +const uniqid = require('uniqid');
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +const actions = require('../actions');
  9 +
  10 +const client = axios.create({
  11 + baseURL: config.core.url,
  12 + timeout: config.core.request_timeout_ms,
  13 + headers: {
  14 + 'x-access-token': config.core.access_token,
  15 + },
  16 +});
  17 +
  18 +let onPull = false;
  19 +
  20 +/**
  21 + * pull unprocessed inquiry transaction from core
  22 + */
  23 +module.exports = async () => {
  24 + logger.verbose(`${MODULE_NAME} 64E2EFDE: Pull inquiry transaction from core`);
  25 + if (onPull) {
  26 + logger.verbose(`${MODULE_NAME} EECB3ECC: Pull inquiry already running`);
  27 + return false;
  28 + }
  29 + onPull = true;
  30 +
  31 + const xid = uniqid();
  32 +
  33 + try {
  34 + const products = await configData.getActiveProductPostpaidArray(xid);
  35 + const response = await client.post('/transactions/inquiry-pull', {
  36 + gateway: {
  37 + name: `${config.name}-postpaid`,
  38 + url: `${config.url}:${config.port}/apikey/${config.apikey}/postpaid`,
  39 + postpaid: 1,
  40 + },
  41 + products,
  42 + });
  43 + if (response.data.error) {
  44 + logger.info(`${MODULE_NAME} E082E007: Error when pulling inquiry transaction`, {
  45 + xid,
  46 + message: response.data.message,
  47 + error: response.data.error,
  48 + });
  49 + }
  50 +
  51 + if (!response.data.result) {
  52 + logger.info(`${MODULE_NAME} 72C1FAC5: Empty inquiry transaction result`, {
  53 + xid,
  54 + result: response.data.result,
  55 + });
  56 + return null;
  57 + }
  58 +
  59 + await actions.inquiry(xid, response.data.result);
  60 + } catch (e) {
  61 + logger.warn(`${MODULE_NAME} 1E5D9D56: Exception`, {
  62 + xid,
  63 + message: e.message,
  64 + code: e.code,
  65 + });
  66 + } finally {
  67 + onPull = false;
  68 + }
  69 + return true;
  70 +};
lib/pull/get-payment.js
... ... @@ -0,0 +1,70 @@
  1 +const MODULE_NAME = 'PULL.GET-PAYMENT';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +const uniqid = require('uniqid');
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +const actions = require('../actions');
  9 +
  10 +const client = axios.create({
  11 + baseURL: config.core.url,
  12 + timeout: config.core.request_timeout_ms,
  13 + headers: {
  14 + 'x-access-token': config.core.access_token,
  15 + },
  16 +});
  17 +
  18 +let onPull = false;
  19 +
  20 +/**
  21 + * pull unprocessed payment transaction from core
  22 + */
  23 +module.exports = async () => {
  24 + logger.verbose(`${MODULE_NAME} 68CB1245: Pull payment transaction from core`);
  25 + if (onPull) {
  26 + logger.verbose(`${MODULE_NAME} 576C1D1A: Pull payment already running`);
  27 + return false;
  28 + }
  29 + onPull = true;
  30 +
  31 + const xid = uniqid();
  32 +
  33 + try {
  34 + const products = await configData.getActiveProductPostpaidArray(xid);
  35 + const response = await client.post('/transactions/payment-pull', {
  36 + gateway: {
  37 + name: `${config.name}-postpaid`,
  38 + url: `${config.url}:${config.port}/apikey/${config.apikey}/postpaid`,
  39 + postpaid: 1,
  40 + },
  41 + products,
  42 + });
  43 + if (response.data.error) {
  44 + logger.info(`${MODULE_NAME} E3093F6D: Error when pulling payment transaction`, {
  45 + xid,
  46 + message: response.data.message,
  47 + error: response.data.error,
  48 + });
  49 + }
  50 +
  51 + if (!response.data.result) {
  52 + logger.info(`${MODULE_NAME} 230E9E0F: Empty payment transaction result`, {
  53 + xid,
  54 + result: response.data.result,
  55 + });
  56 + return null;
  57 + }
  58 +
  59 + await actions.pay(xid, response.data.result);
  60 + } catch (e) {
  61 + logger.warn(`${MODULE_NAME} 7E6D9444: Exception`, {
  62 + xid,
  63 + message: e.message,
  64 + code: e.code,
  65 + });
  66 + } finally {
  67 + onPull = false;
  68 + }
  69 + return true;
  70 +};
lib/pull/get-prepaid.js
... ... @@ -0,0 +1,69 @@
  1 +const MODULE_NAME = 'PULL.GET-PREPAID';
  2 +
  3 +const logger = require('tektrans-logger');
  4 +const axios = require('axios').default;
  5 +const uniqid = require('uniqid');
  6 +const config = require('../config');
  7 +const configData = require('../config/data');
  8 +const actions = require('../actions');
  9 +
  10 +const client = axios.create({
  11 + baseURL: config.core.url,
  12 + timeout: config.core.request_timeout_ms,
  13 + headers: {
  14 + 'x-access-token': config.core.access_token,
  15 + },
  16 +});
  17 +
  18 +let onPull = false;
  19 +
  20 +/**
  21 + * pull unprocessed prepaid transaction from core
  22 + */
  23 +module.exports = async () => {
  24 + logger.verbose(`${MODULE_NAME} 385A1B0D: Pull prepaid transaction from core`);
  25 + if (onPull) {
  26 + logger.verbose(`${MODULE_NAME} 6563C2C9: Pull prepaid already running`);
  27 + return false;
  28 + }
  29 + onPull = true;
  30 +
  31 + const xid = uniqid();
  32 +
  33 + try {
  34 + const products = await configData.getActiveProductArray(xid);
  35 + const response = await client.post('/transactions/prepaid-pull', {
  36 + gateway: {
  37 + name: config.name,
  38 + url: `${config.url}:${config.port}/apikey/${config.apikey}`,
  39 + },
  40 + products,
  41 + });
  42 + if (response.data.error) {
  43 + logger.info(`${MODULE_NAME} A397BA74: Error when pulling prepaid transaction`, {
  44 + xid,
  45 + message: response.data.message,
  46 + error: response.data.error,
  47 + });
  48 + }
  49 +
  50 + if (!response.data.result) {
  51 + logger.info(`${MODULE_NAME} 712130A5: Empty prepaid transaction result`, {
  52 + xid,
  53 + result: response.data.result,
  54 + });
  55 + return null;
  56 + }
  57 +
  58 + await actions.buy(xid, response.data.result);
  59 + } catch (e) {
  60 + logger.warn(`${MODULE_NAME} 008B2FA5: Exception`, {
  61 + xid,
  62 + message: e.message,
  63 + code: e.code,
  64 + });
  65 + } finally {
  66 + onPull = false;
  67 + }
  68 + return true;
  69 +};
... ... @@ -0,0 +1 @@
  1 +exports.run = require('./run');
... ... @@ -0,0 +1,22 @@
  1 +const MODULE_NAME = 'PULL.RUN';
  2 +const logger = require('tektrans-logger');
  3 +
  4 +const config = require('../config');
  5 +const getInquiry = require('./get-inquiry');
  6 +const getPrepaid = require('./get-prepaid');
  7 +const getPayment = require('./get-payment');
  8 +
  9 +/**
  10 + * Run pulling schedule
  11 + */
  12 +module.exports = async () => {
  13 + logger.verbose(`${MODULE_NAME} 34022A49: Run pulling schedule`, {
  14 + interval: config.pull_interval_ms,
  15 + });
  16 + setInterval(() => {
  17 + logger.verbose(`${MODULE_NAME} 06B8C652: Pull run`);
  18 + getPrepaid();
  19 + getInquiry();
  20 + getPayment();
  21 + }, config.pull_interval_ms);
  22 +};