From 5443b922a7960d4a2770198890a3b3188bcd4088 Mon Sep 17 00:00:00 2001 From: adi surya <adisurya1@gmail.com> Date: Wed, 27 Jul 2022 14:50:24 +0700 Subject: [PATCH] file lib --- .gitignore | 1 + config.sample.json | 22 ++++ index.js | 9 ++ lib/actions/buy.js | 71 +++++++++++++ lib/actions/index.js | 3 + lib/actions/inquiry-to-komodo.js | 64 ++++++++++++ lib/actions/inquiry.js | 71 +++++++++++++ lib/actions/pay.js | 71 +++++++++++++ lib/actions/payment-to-komodo.js | 64 ++++++++++++ lib/actions/topup-to-komodo.js | 64 ++++++++++++ lib/config/data.js | 113 +++++++++++++++++++++ lib/config/index.js | 3 + lib/config/remove-postpaid-product.js | 33 ++++++ lib/config/remove-product.js | 33 ++++++ lib/config/save-postpaid-product.js | 32 ++++++ lib/config/save-product.js | 32 ++++++ lib/http-server/index.js | 40 ++++++++ lib/http-server/middlewares/check-apikey.js | 16 +++ lib/http-server/routers/matrix.js | 12 +++ lib/http-server/routers/postpaid-products/index.js | 80 +++++++++++++++ lib/http-server/routers/products/index.js | 80 +++++++++++++++ lib/http-server/routers/updates/index.js | 69 +++++++++++++ lib/matrix/dump.js | 10 ++ lib/matrix/index.js | 19 ++++ lib/pull/get-inquiry.js | 70 +++++++++++++ lib/pull/get-payment.js | 70 +++++++++++++ lib/pull/get-prepaid.js | 69 +++++++++++++ lib/pull/index.js | 1 + lib/pull/run.js | 22 ++++ 29 files changed, 1244 insertions(+) create mode 100644 config.sample.json create mode 100644 index.js create mode 100644 lib/actions/buy.js create mode 100644 lib/actions/index.js create mode 100644 lib/actions/inquiry-to-komodo.js create mode 100644 lib/actions/inquiry.js create mode 100644 lib/actions/pay.js create mode 100644 lib/actions/payment-to-komodo.js create mode 100644 lib/actions/topup-to-komodo.js create mode 100644 lib/config/data.js create mode 100644 lib/config/index.js create mode 100644 lib/config/remove-postpaid-product.js create mode 100644 lib/config/remove-product.js create mode 100644 lib/config/save-postpaid-product.js create mode 100644 lib/config/save-product.js create mode 100644 lib/http-server/index.js create mode 100644 lib/http-server/middlewares/check-apikey.js create mode 100644 lib/http-server/routers/matrix.js create mode 100644 lib/http-server/routers/postpaid-products/index.js create mode 100644 lib/http-server/routers/products/index.js create mode 100644 lib/http-server/routers/updates/index.js create mode 100644 lib/matrix/dump.js create mode 100644 lib/matrix/index.js create mode 100644 lib/pull/get-inquiry.js create mode 100644 lib/pull/get-payment.js create mode 100644 lib/pull/get-prepaid.js create mode 100644 lib/pull/index.js create mode 100644 lib/pull/run.js diff --git a/.gitignore b/.gitignore index 3c3629e..36420af 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +config.json \ No newline at end of file diff --git a/config.sample.json b/config.sample.json new file mode 100644 index 0000000..1048184 --- /dev/null +++ b/config.sample.json @@ -0,0 +1,22 @@ +{ + "name": "gateway-sds-ss", + "url": "http://localhost", + "port": 11330, + "apikey": "fd97cf519b979262d9d9004cba6a165629ca8b69350a6afdcaab6ab2c9a996ae", + "pull_interval_ms": 5000, + "core": { + "url": "http://localhost:26840", + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJnZW5lcmF0b3IiOiJDTEkiLCJjbGllbnQiOnsibmFtZSI6IktPTU9ETzItR1ctU0RTLVNTIn0sImlhdCI6MTY1ODkwODA4N30.2Ego28jwgPs3s9-iKSbYipO72FTH5gFC5gkVccqiN24", + "request_timeout_ms": 10000 + }, + "products": { + }, + "postpaid_products": { + }, + "sds_ss": { + "url": "http://localhost:8187/request", + "request_timeout_ms": 10000, + "username": "user", + "password": "1234" + } +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..3a2fd9b --- /dev/null +++ b/index.js @@ -0,0 +1,9 @@ +process.chdir(__dirname); + +const fs = require('fs'); +const pull = require('./lib/pull'); +require('./lib/http-server'); + +pull.run(); + +fs.writeFileSync('pid.txt', process.pid.toString()); diff --git a/lib/actions/buy.js b/lib/actions/buy.js new file mode 100644 index 0000000..3c6b34d --- /dev/null +++ b/lib/actions/buy.js @@ -0,0 +1,71 @@ +const MODULE_NAME = 'ACTIONS.BUY'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); +const configData = require('../config/data'); + +const topupToKomodo = require('./topup-to-komodo'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +/** + * Buy a product from supplier komodo + * + * @param {string} xid + * @param {object} transaction + * + */ +module.exports = async (xid, transaction) => { + try { + logger.verbose(`${MODULE_NAME} 4B139379: Buy product to komodo`, { + xid, + transaction, + }); + const iConfig = await configData.all(); + + let productName = transaction.product_name; + if ( + iConfig.products[transaction.product_name] + && iConfig.products[transaction.product_name].remote + ) { + productName = iConfig.products[transaction.product_name].remote; + } + + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`; + const result = await topupToKomodo( + xid, + transaction.id, + transaction.destination, + productName, + callbackUrl, + ); + logger.verbose(`${MODULE_NAME} 5BDFAF41: result from komodo`, { + xid, + trxId: transaction.id, + result, + }); + const params = { + id: result.request_id, + rc: result.rc, + amount: result.amount || null, + message: result.message, + sn: result.sn || null, + }; + + await client.post('/transactions/gateway-update', params); + } catch (e) { + logger.warn(`${MODULE_NAME} E9887C98: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } +}; diff --git a/lib/actions/index.js b/lib/actions/index.js new file mode 100644 index 0000000..580d9ad --- /dev/null +++ b/lib/actions/index.js @@ -0,0 +1,3 @@ +exports.buy = require('./buy'); +exports.inquiry = require('./inquiry'); +exports.pay = require('./pay'); diff --git a/lib/actions/inquiry-to-komodo.js b/lib/actions/inquiry-to-komodo.js new file mode 100644 index 0000000..19a60c0 --- /dev/null +++ b/lib/actions/inquiry-to-komodo.js @@ -0,0 +1,64 @@ +const MODULE_NAME = 'ACTIONS.INQUIRY-TO-KOMODO'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); + +const client = axios.create({ + baseURL: config.komodo_http_get_x.url, + timeout: config.komodo_http_get_x.request_timeout_ms, +}); + +/** + * request inquiry transaction to komodo + * + * @param {string} xid + * @param {string} requestId + * @param {string} destination + * @param {string} productName + * @param {string} reverseUrl + */ +module.exports = async ( + xid, + requestId, + destination, + productName, + reverseUrl, +) => { + logger.verbose(`${MODULE_NAME} 4AD4DF41: request inquiry to komodo`, { + requestId, destination, productName, reverseUrl, xid, + }); + + const params = { + request_id: requestId, + terminal_name: config.komodo_http_get_x.terminal_name, + password: config.komodo_http_get_x.password, + destination, + product_name: productName, + reverse_url: reverseUrl, + }; + + try { + const response = await client.get('/inquiry', { + params, + }); + if (!response) { + throw new Error(`${MODULE_NAME} 6CE3E06E: Empty response from komodo`); + } + if (!response.data) { + throw new Error(`${MODULE_NAME} F236476F: Empty response data from komodo`); + } + + return response.data; + } catch (err) { + logger.warn(`${MODULE_NAME} 48BAA6B7: Exception`, { + xid, + requestId, + destination, + productName, + message: err.message, + }); + throw err; + } +}; diff --git a/lib/actions/inquiry.js b/lib/actions/inquiry.js new file mode 100644 index 0000000..555e31c --- /dev/null +++ b/lib/actions/inquiry.js @@ -0,0 +1,71 @@ +const MODULE_NAME = 'ACTIONS.INQUIRY'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); +const configData = require('../config/data'); + +const inquiryToKomodo = require('./inquiry-to-komodo'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +/** + * Inquiry a product from supplier komodo + * + * @param {string} xid + * @param {object} transaction + * + */ +module.exports = async (xid, transaction) => { + try { + logger.verbose(`${MODULE_NAME} ABE82225: Inquiry product to komodo`, { + xid, + transaction, + }); + const iConfig = await configData.all(); + + let productName = transaction.product_name; + if ( + iConfig.postpaid_products[transaction.product_name] + && iConfig.postpaid_products[transaction.product_name].remote + ) { + productName = iConfig.postpaid_products[transaction.product_name].remote; + } + + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`; + const result = await inquiryToKomodo( + xid, + transaction.id, + transaction.destination, + productName, + callbackUrl, + ); + logger.verbose(`${MODULE_NAME} 076C1206: result from komodo`, { + xid, + trxId: transaction.id, + result, + }); + const params = { + id: result.request_id, + rc: result.rc, + amount: result.amount || null, + message: result.message, + sn: result.sn || null, + }; + + await client.post('/transactions/gateway-update', params); + } catch (e) { + logger.warn(`${MODULE_NAME} D1A1B698: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } +}; diff --git a/lib/actions/pay.js b/lib/actions/pay.js new file mode 100644 index 0000000..ac7ed6f --- /dev/null +++ b/lib/actions/pay.js @@ -0,0 +1,71 @@ +const MODULE_NAME = 'ACTIONS.PAY'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); +const configData = require('../config/data'); + +const paymentToKomodo = require('./payment-to-komodo'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +/** + * Pay a product from supplier komodo + * + * @param {string} xid + * @param {object} transaction + * + */ +module.exports = async (xid, transaction) => { + try { + logger.verbose(`${MODULE_NAME} CB9506E9: Pay product to komodo`, { + xid, + transaction, + }); + const iConfig = await configData.all(); + + let productName = transaction.product_name; + if ( + iConfig.postpaid_products[transaction.product_name] + && iConfig.postpaid_products[transaction.product_name].remote + ) { + productName = iConfig.postpaid_products[transaction.product_name].remote; + } + + const callbackUrl = `${iConfig.url}:${iConfig.port}/apikey/${iConfig.apikey}/updates`; + const result = await paymentToKomodo( + xid, + transaction.id, + transaction.destination, + productName, + callbackUrl, + ); + logger.verbose(`${MODULE_NAME} 4F45F9E3: result from komodo`, { + xid, + trxId: transaction.id, + result, + }); + const params = { + id: result.request_id, + rc: result.rc, + amount: result.amount || null, + message: result.message, + sn: result.sn || null, + }; + + await client.post('/transactions/gateway-update', params); + } catch (e) { + logger.warn(`${MODULE_NAME} EF0EE887: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } +}; diff --git a/lib/actions/payment-to-komodo.js b/lib/actions/payment-to-komodo.js new file mode 100644 index 0000000..3132ef0 --- /dev/null +++ b/lib/actions/payment-to-komodo.js @@ -0,0 +1,64 @@ +const MODULE_NAME = 'ACTIONS.PAY-TO-KOMODO'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); + +const client = axios.create({ + baseURL: config.komodo_http_get_x.url, + timeout: config.komodo_http_get_x.request_timeout_ms, +}); + +/** + * request pay transaction to komodo + * + * @param {string} xid + * @param {string} requestId + * @param {string} destination + * @param {string} productName + * @param {string} reverseUrl + */ +module.exports = async ( + xid, + requestId, + destination, + productName, + reverseUrl, +) => { + logger.verbose(`${MODULE_NAME} 740EF164: pay to komodo`, { + requestId, destination, productName, xid, + }); + + const params = { + request_id: requestId, + terminal_name: config.komodo_http_get_x.terminal_name, + password: config.komodo_http_get_x.password, + destination, + product_name: productName, + reverse_url: reverseUrl, + }; + + try { + const response = await client.get('/pay', { + params, + }); + if (!response) { + throw new Error(`${MODULE_NAME} 29D8D56F: Empty response from komodo`); + } + if (!response.data) { + throw new Error(`${MODULE_NAME} 288CD049: Empty response data from komodo`); + } + + return response.data; + } catch (err) { + logger.warn(`${MODULE_NAME} DCE65215: Exception`, { + xid, + requestId, + destination, + productName, + message: err.message, + }); + throw err; + } +}; diff --git a/lib/actions/topup-to-komodo.js b/lib/actions/topup-to-komodo.js new file mode 100644 index 0000000..c712eac --- /dev/null +++ b/lib/actions/topup-to-komodo.js @@ -0,0 +1,64 @@ +const MODULE_NAME = 'ACTIONS.TOPUP-TO-KOMODO'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; + +const config = require('../config'); + +const client = axios.create({ + baseURL: config.komodo_http_get_x.url, + timeout: config.komodo_http_get_x.request_timeout_ms, +}); + +/** + * request topup transaction to komodo + * + * @param {string} xid + * @param {string} requestId + * @param {string} destination + * @param {string} productName + * @param {string} reverseUrl + */ +module.exports = async ( + xid, + requestId, + destination, + productName, + reverseUrl, +) => { + logger.verbose(`${MODULE_NAME} 4AD4DF41: topup to komodo`, { + requestId, destination, productName, xid, + }); + + const params = { + request_id: requestId, + terminal_name: config.komodo_http_get_x.terminal_name, + password: config.komodo_http_get_x.password, + destination, + product_name: productName, + reverse_url: reverseUrl, + }; + + try { + const response = await client.get('/topup', { + params, + }); + if (!response) { + throw new Error(`${MODULE_NAME} 6CE3E06E: Empty response from komodo`); + } + if (!response.data) { + throw new Error(`${MODULE_NAME} F236476F: Empty response data from komodo`); + } + + return response.data; + } catch (err) { + logger.warn(`${MODULE_NAME} 48BAA6B7: Exception`, { + xid, + requestId, + destination, + productName, + message: err.message, + }); + throw err; + } +}; diff --git a/lib/config/data.js b/lib/config/data.js new file mode 100644 index 0000000..f25a9e3 --- /dev/null +++ b/lib/config/data.js @@ -0,0 +1,113 @@ +const MODULE_NAME = 'CONFIG.DATA'; + +const fs = require('fs/promises'); +const logger = require('tektrans-logger'); + +let config = {}; + +/** + * Get all config + * + * @param {string} xid + * + * @returns <object> + */ +async function all(xid) { + try { + if (Object.keys(config).length === 0) { + const configString = await fs.readFile('config.json'); + config = JSON.parse(configString); + } + } catch (e) { + logger.warn(`${MODULE_NAME} ED8D390C: Exception`, { + xid, + eMessage: e.message, + eCode: e.code, + }); + } + return config; +} + +/** + * Get active product prepaid config + * + * @param {string} xid + * + * @returns <Array> + */ +async function getActiveProductArray(xid) { + try { + if (Object.keys(config).length === 0) { + const configString = await fs.readFile('config.json'); + config = JSON.parse(configString); + } + const allProductsArray = Object.values(config.products); + if (Array.isArray(allProductsArray)) { + const activeProductArray = allProductsArray.filter((val) => val.active === 1); + const activeProductNameArray = activeProductArray.map((val) => val.name); + return activeProductNameArray; + } + } catch (e) { + logger.warn(`${MODULE_NAME} 2D49D035: Exception`, { + xid, + eMessage: e.message, + eCode: e.code, + }); + } + return []; +} + +/** + * Get active product postpaid config + * + * @param {string} xid + * + * @returns <Array> + */ +async function getActiveProductPostpaidArray(xid) { + try { + if (Object.keys(config).length === 0) { + const configString = await fs.readFile('config.json'); + config = JSON.parse(configString); + } + const allProductsArray = Object.values(config.postpaid_products); + if (Array.isArray(allProductsArray)) { + const activeProductArray = allProductsArray.filter((val) => val.active === 1); + const activeProductNameArray = activeProductArray.map((val) => val.name); + return activeProductNameArray; + } + } catch (e) { + logger.warn(`${MODULE_NAME} B5414DB0: Exception`, { + xid, + eMessage: e.message, + eCode: e.code, + }); + } + return []; +} + +/** + * Reload config + * + * @param {string} xid + * + * @returns <object> + */ +async function reload(xid) { + try { + const configString = await fs.readFile('config.json'); + config = JSON.parse(configString); + } catch (e) { + logger.warn(`${MODULE_NAME} D005AED3: Exception`, { + xid, + eMessage: e.message, + eCode: e.code, + }); + } + return config; +} + +exports.all = all; +exports.reload = reload; +exports.getActiveProductArray = getActiveProductArray; +exports.getActiveProductPostpaidArray = getActiveProductPostpaidArray; diff --git a/lib/config/index.js b/lib/config/index.js new file mode 100644 index 0000000..e04cb9d --- /dev/null +++ b/lib/config/index.js @@ -0,0 +1,3 @@ +const data = require('../../config.json'); + +module.exports = data; diff --git a/lib/config/remove-postpaid-product.js b/lib/config/remove-postpaid-product.js new file mode 100644 index 0000000..e7ee7f9 --- /dev/null +++ b/lib/config/remove-postpaid-product.js @@ -0,0 +1,33 @@ +const MODULE_NAME = 'CONFIG.REMOVE-POSTPAID-PRODUCT'; + +const fs = require('fs/promises'); +const logger = require('tektrans-logger'); + +const configData = require('./data'); + +/** + * Menghapus nilai terkini config.products (postpaid) + * + * @param {string} name + * + */ +module.exports = async (xid, name) => { + try { + logger.verbose(`${MODULE_NAME} B4361668: remove postpaid product from config file`, { + xid, + key: name, + }); + const config = await configData.reload(); + + delete config.postpaid_products[name]; + await fs.writeFile('config.json', JSON.stringify(config, null, 4)); + + await configData.reload(); + } catch (e) { + logger.warn(`${MODULE_NAME} 9E5C6976: Exception`, { + xid, + eCode: e.code, + eMessage: e.message, + }); + } +}; diff --git a/lib/config/remove-product.js b/lib/config/remove-product.js new file mode 100644 index 0000000..5e88d07 --- /dev/null +++ b/lib/config/remove-product.js @@ -0,0 +1,33 @@ +const MODULE_NAME = 'CONFIG.REMOVE-PREPAID-PRODUCT'; + +const fs = require('fs/promises'); +const logger = require('tektrans-logger'); + +const configData = require('./data'); + +/** + * Menghapus nilai terkini config.products (prepaid) + * + * @param {string} name + * + */ +module.exports = async (xid, name) => { + try { + logger.verbose(`${MODULE_NAME} 80D1628F: remove prepaid product from config file`, { + xid, + key: name, + }); + const config = await configData.reload(); + + delete config.products[name]; + await fs.writeFile('config.json', JSON.stringify(config, null, 4)); + + await configData.reload(); + } catch (e) { + logger.warn(`${MODULE_NAME} 190BD3D7: Exception`, { + xid, + eCode: e.code, + eMessage: e.message, + }); + } +}; diff --git a/lib/config/save-postpaid-product.js b/lib/config/save-postpaid-product.js new file mode 100644 index 0000000..8ee1f1f --- /dev/null +++ b/lib/config/save-postpaid-product.js @@ -0,0 +1,32 @@ +const MODULE_NAME = 'CONFIG.SAVE-POSTPAID-PRODUCT'; + +const fs = require('fs/promises'); +const logger = require('tektrans-logger'); + +const configData = require('./data'); + +/** + * Menyimpan nilai terkini config.products (postpaid) + * + */ +module.exports = async (xid, key, value) => { + try { + logger.verbose(`${MODULE_NAME} 19BB0554: Saving postpaid product to config file`, { + xid, + key, + value, + }); + const config = await configData.reload(); + + config.postpaid_products[key] = value; + await fs.writeFile('config.json', JSON.stringify(config, null, 4)); + + await configData.reload(); + } catch (e) { + logger.warn(`${MODULE_NAME} D0F796A6: Exception`, { + xid, + eCode: e.code, + eMessage: e.message, + }); + } +}; diff --git a/lib/config/save-product.js b/lib/config/save-product.js new file mode 100644 index 0000000..d9fac58 --- /dev/null +++ b/lib/config/save-product.js @@ -0,0 +1,32 @@ +const MODULE_NAME = 'CONFIG.SAVE-PREPAID-PRODUCT'; + +const fs = require('fs/promises'); +const logger = require('tektrans-logger'); + +const configData = require('./data'); + +/** + * Menyimpan nilai terkini config.products (prepaid) + * + */ +module.exports = async (xid, key, value) => { + try { + logger.verbose(`${MODULE_NAME} C6D936BF: Saving prepaid product to config file`, { + xid, + key, + value, + }); + const config = await configData.reload(); + + config.products[key] = value; + await fs.writeFile('config.json', JSON.stringify(config, null, 4)); + + await configData.reload(); + } catch (e) { + logger.warn(`${MODULE_NAME} 1D1937A9: Exception`, { + xid, + eCode: e.code, + eMessage: e.message, + }); + } +}; diff --git a/lib/http-server/index.js b/lib/http-server/index.js new file mode 100644 index 0000000..5b44a6b --- /dev/null +++ b/lib/http-server/index.js @@ -0,0 +1,40 @@ +const MODULE_NAME = 'HTTP-SERVER'; + +const express = require('express'); +const uniqid = require('uniqid'); +const logger = require('tektrans-logger'); + +const config = require('../config'); +const matrix = require('../matrix'); +const checkApikey = require('./middlewares/check-apikey'); + +const routerMatrix = require('./routers/matrix'); +const routerUpdates = require('./routers/updates'); +const routerProducts = require('./routers/products'); +const routerPostpaidProducts = require('./routers/postpaid-products'); + +const app = express(); + +app.use((req, res, next) => { + matrix.httpServer.requestCounter += 1; + res.locals.xid = uniqid(); + + next(); +}); + +app.use('/matrix', routerMatrix); +app.use('/apikey/:apikey/updates', [checkApikey], routerUpdates); +app.use('/apikey/:apikey/products', [checkApikey], routerProducts); +app.use('/apikey/:apikey/postpaid/products', [checkApikey], routerPostpaidProducts); + +app.use((req, res) => { + res.status(404).json({ + error: true, + message: 'Method/service not found', + }); +}); + +const { port } = config; +app.listen(port, () => { + logger.info(`${MODULE_NAME} 35069698: Listening`, { port }); +}); diff --git a/lib/http-server/middlewares/check-apikey.js b/lib/http-server/middlewares/check-apikey.js new file mode 100644 index 0000000..89cec38 --- /dev/null +++ b/lib/http-server/middlewares/check-apikey.js @@ -0,0 +1,16 @@ +const config = require('../../config'); + +module.exports = async (req, res, next) => { + const { apikey } = req.params; + + if (!config.apikey) { + next(); + } else if (config.apikey === apikey) { + next(); + } else { + res.status(403).json({ + error: true, + message: 'Invalid apikey', + }); + } +}; diff --git a/lib/http-server/routers/matrix.js b/lib/http-server/routers/matrix.js new file mode 100644 index 0000000..ee26c3d --- /dev/null +++ b/lib/http-server/routers/matrix.js @@ -0,0 +1,12 @@ +const express = require('express'); + +const matrixDump = require('../../matrix/dump'); + +const router = express.Router(); +module.exports = router; + +const pageMain = (req, res) => { + res.json(matrixDump()); +}; + +router.all('/', pageMain); diff --git a/lib/http-server/routers/postpaid-products/index.js b/lib/http-server/routers/postpaid-products/index.js new file mode 100644 index 0000000..3901983 --- /dev/null +++ b/lib/http-server/routers/postpaid-products/index.js @@ -0,0 +1,80 @@ +const MODULE_NAME = 'HTTP-SERVER.ROUTER.POSTPAID-PRODUCTS'; + +const express = require('express'); +const logger = require('tektrans-logger'); + +const configData = require('../../../config/data'); +const configSaveProduct = require('../../../config/save-postpaid-product'); +const configRemoveProduct = require('../../../config/remove-postpaid-product'); + +const router = express.Router(); + +module.exports = router; + +const pageIndex = async (req, res) => { + const { xid } = res.locals; + try { + logger.verbose(`${MODULE_NAME} 24D7D9B4: get postpaid product configuration`, { xid }); + const products = (await configData.all()).postpaid_products || {}; + res.json({ error: false, message: 'OK', result: products }); + } catch (e) { + logger.warn(`${MODULE_NAME} 1DB45AC5: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +const pageSave = async (req, res) => { + const { xid } = res.locals; + const { name, remote = null, active = 0 } = req.body; + try { + logger.verbose(`${MODULE_NAME} A083E9DC: save postpaid product configuration`, { xid, data: req.body }); + + const params = { + name, + remote, + active, + }; + await configSaveProduct(xid, name, params); + res.json({ error: false, message: 'OK' }); + } catch (e) { + logger.warn(`${MODULE_NAME} 88B9218F: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +const pageRemove = async (req, res) => { + const { xid } = res.locals; + const { name } = req.body; + try { + logger.verbose(`${MODULE_NAME} 7AD392AE: remove postpaid product configuration`, { xid, name }); + + await configRemoveProduct(xid, name); + res.json({ error: false, message: 'OK' }); + } catch (e) { + logger.warn(`${MODULE_NAME} F714088B: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +router.get('/', [express.json()], pageIndex); + +router.post('/save', [express.json()], pageSave); +router.post('/remove', [express.json()], pageRemove); diff --git a/lib/http-server/routers/products/index.js b/lib/http-server/routers/products/index.js new file mode 100644 index 0000000..c9eee25 --- /dev/null +++ b/lib/http-server/routers/products/index.js @@ -0,0 +1,80 @@ +const MODULE_NAME = 'HTTP-SERVER.ROUTER.PRODUCTS'; + +const express = require('express'); +const logger = require('tektrans-logger'); + +const configData = require('../../../config/data'); +const configSaveProduct = require('../../../config/save-product'); +const configRemoveProduct = require('../../../config/remove-product'); + +const router = express.Router(); + +module.exports = router; + +const pageIndex = async (req, res) => { + const { xid } = res.locals; + try { + logger.verbose(`${MODULE_NAME} F1BF0675: get product configuration`, { xid }); + const products = (await configData.all()).products || {}; + res.json({ error: false, message: 'OK', result: products }); + } catch (e) { + logger.warn(`${MODULE_NAME} 839E55E0: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +const pageSave = async (req, res) => { + const { xid } = res.locals; + const { name, remote = null, active = 0 } = req.body; + try { + logger.verbose(`${MODULE_NAME} 59CB2503: save product configuration`, { xid, data: req.body }); + + const params = { + name, + remote, + active, + }; + await configSaveProduct(xid, name, params); + res.json({ error: false, message: 'OK' }); + } catch (e) { + logger.warn(`${MODULE_NAME} 47F57E23: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +const pageRemove = async (req, res) => { + const { xid } = res.locals; + const { name } = req.body; + try { + logger.verbose(`${MODULE_NAME} E94A7B38: remove product configuration`, { xid, name }); + + await configRemoveProduct(xid, name); + res.json({ error: false, message: 'OK' }); + } catch (e) { + logger.warn(`${MODULE_NAME} 955FD7E3: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +router.get('/', [express.json()], pageIndex); + +router.post('/save', [express.json()], pageSave); +router.post('/remove', [express.json()], pageRemove); diff --git a/lib/http-server/routers/updates/index.js b/lib/http-server/routers/updates/index.js new file mode 100644 index 0000000..1bbf3ac --- /dev/null +++ b/lib/http-server/routers/updates/index.js @@ -0,0 +1,69 @@ +const MODULE_NAME = 'HTTP-SERVER.ROUTER.UPDATES'; + +const express = require('express'); +const axios = require('axios').default; +const logger = require('tektrans-logger'); + +const config = require('../../../config'); + +const router = express.Router(); + +module.exports = router; + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +const pageUpdate = async (req, res) => { + const { xid } = res.locals; + let data = req.query; + if (req.method.toUpperCase() !== 'GET') { + data = req.body; + } + + try { + logger.verbose(`${MODULE_NAME} 9E5C70C8: update from komodo`, { xid, data }); + const params = { + id: data.request_id, + rc: data.rc, + amount: data.amount || null, + message: data.message, + sn: data.sn || null, + bill_count: data.bill_count, + bill_amount: data.bill_amount, + related_data: null, + amount_to_charge: data.amount_to_charge, + }; + + client.post('/transactions/gateway-update', params).then((result) => { + logger.verbose(`${MODULE_NAME} A8DA0D04: response from core2`, { + xid, + response: result.data, + }); + }).catch((err) => { + logger.warn(`${MODULE_NAME} 32EB485C: Exception on request to core2`, { + xid, + eMessage: err.message, + eCode: err.code, + }); + }); + + res.json({ error: false, message: 'OK' }); + } catch (e) { + logger.warn(`${MODULE_NAME} B12B4A2C: Exception.`, { + xid, eMessage: e.message, eCode: e.code, + }); + res.status(500).json({ + error: true, + error_code: e.code, + message: e.message, + }); + } +}; + +router.get('/', pageUpdate); +router.post('/', [express.urlencoded({ extended: true }), express.json()], pageUpdate); diff --git a/lib/matrix/dump.js b/lib/matrix/dump.js new file mode 100644 index 0000000..0ac7f24 --- /dev/null +++ b/lib/matrix/dump.js @@ -0,0 +1,10 @@ +const matrix = require('./index'); + +module.exports = () => { + matrix.processTitle = process.title; + matrix.uptimeSecs = process.uptime(); + matrix.memoryUsage = process.memoryUsage(); + matrix.resourceUsage = process.resourceUsage(); + + return matrix; +}; diff --git a/lib/matrix/index.js b/lib/matrix/index.js new file mode 100644 index 0000000..ca3b317 --- /dev/null +++ b/lib/matrix/index.js @@ -0,0 +1,19 @@ +const data = { + processTitle: process.title, + pid: process.pid, + workingDirectory: process.cwd(), + uptimeSecs: process.uptime(), + + memoryUsage: process.memoryUsage(), + resourceUsage: process.resourceUsage(), + + platform: process.platform, + nodeVersion: process.version, + nodeRelease: process.release, + + httpServer: { + requestCounter: 0, + }, +}; + +module.exports = data; diff --git a/lib/pull/get-inquiry.js b/lib/pull/get-inquiry.js new file mode 100644 index 0000000..00aac65 --- /dev/null +++ b/lib/pull/get-inquiry.js @@ -0,0 +1,70 @@ +const MODULE_NAME = 'PULL.GET-INQUIRY'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; +const uniqid = require('uniqid'); +const config = require('../config'); +const configData = require('../config/data'); +const actions = require('../actions'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +let onPull = false; + +/** + * pull unprocessed inquiry transaction from core + */ +module.exports = async () => { + logger.verbose(`${MODULE_NAME} 64E2EFDE: Pull inquiry transaction from core`); + if (onPull) { + logger.verbose(`${MODULE_NAME} EECB3ECC: Pull inquiry already running`); + return false; + } + onPull = true; + + const xid = uniqid(); + + try { + const products = await configData.getActiveProductPostpaidArray(xid); + const response = await client.post('/transactions/inquiry-pull', { + gateway: { + name: `${config.name}-postpaid`, + url: `${config.url}:${config.port}/apikey/${config.apikey}/postpaid`, + postpaid: 1, + }, + products, + }); + if (response.data.error) { + logger.info(`${MODULE_NAME} E082E007: Error when pulling inquiry transaction`, { + xid, + message: response.data.message, + error: response.data.error, + }); + } + + if (!response.data.result) { + logger.info(`${MODULE_NAME} 72C1FAC5: Empty inquiry transaction result`, { + xid, + result: response.data.result, + }); + return null; + } + + await actions.inquiry(xid, response.data.result); + } catch (e) { + logger.warn(`${MODULE_NAME} 1E5D9D56: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } finally { + onPull = false; + } + return true; +}; diff --git a/lib/pull/get-payment.js b/lib/pull/get-payment.js new file mode 100644 index 0000000..a7587be --- /dev/null +++ b/lib/pull/get-payment.js @@ -0,0 +1,70 @@ +const MODULE_NAME = 'PULL.GET-PAYMENT'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; +const uniqid = require('uniqid'); +const config = require('../config'); +const configData = require('../config/data'); +const actions = require('../actions'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +let onPull = false; + +/** + * pull unprocessed payment transaction from core + */ +module.exports = async () => { + logger.verbose(`${MODULE_NAME} 68CB1245: Pull payment transaction from core`); + if (onPull) { + logger.verbose(`${MODULE_NAME} 576C1D1A: Pull payment already running`); + return false; + } + onPull = true; + + const xid = uniqid(); + + try { + const products = await configData.getActiveProductPostpaidArray(xid); + const response = await client.post('/transactions/payment-pull', { + gateway: { + name: `${config.name}-postpaid`, + url: `${config.url}:${config.port}/apikey/${config.apikey}/postpaid`, + postpaid: 1, + }, + products, + }); + if (response.data.error) { + logger.info(`${MODULE_NAME} E3093F6D: Error when pulling payment transaction`, { + xid, + message: response.data.message, + error: response.data.error, + }); + } + + if (!response.data.result) { + logger.info(`${MODULE_NAME} 230E9E0F: Empty payment transaction result`, { + xid, + result: response.data.result, + }); + return null; + } + + await actions.pay(xid, response.data.result); + } catch (e) { + logger.warn(`${MODULE_NAME} 7E6D9444: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } finally { + onPull = false; + } + return true; +}; diff --git a/lib/pull/get-prepaid.js b/lib/pull/get-prepaid.js new file mode 100644 index 0000000..cce1534 --- /dev/null +++ b/lib/pull/get-prepaid.js @@ -0,0 +1,69 @@ +const MODULE_NAME = 'PULL.GET-PREPAID'; + +const logger = require('tektrans-logger'); +const axios = require('axios').default; +const uniqid = require('uniqid'); +const config = require('../config'); +const configData = require('../config/data'); +const actions = require('../actions'); + +const client = axios.create({ + baseURL: config.core.url, + timeout: config.core.request_timeout_ms, + headers: { + 'x-access-token': config.core.access_token, + }, +}); + +let onPull = false; + +/** + * pull unprocessed prepaid transaction from core + */ +module.exports = async () => { + logger.verbose(`${MODULE_NAME} 385A1B0D: Pull prepaid transaction from core`); + if (onPull) { + logger.verbose(`${MODULE_NAME} 6563C2C9: Pull prepaid already running`); + return false; + } + onPull = true; + + const xid = uniqid(); + + try { + const products = await configData.getActiveProductArray(xid); + const response = await client.post('/transactions/prepaid-pull', { + gateway: { + name: config.name, + url: `${config.url}:${config.port}/apikey/${config.apikey}`, + }, + products, + }); + if (response.data.error) { + logger.info(`${MODULE_NAME} A397BA74: Error when pulling prepaid transaction`, { + xid, + message: response.data.message, + error: response.data.error, + }); + } + + if (!response.data.result) { + logger.info(`${MODULE_NAME} 712130A5: Empty prepaid transaction result`, { + xid, + result: response.data.result, + }); + return null; + } + + await actions.buy(xid, response.data.result); + } catch (e) { + logger.warn(`${MODULE_NAME} 008B2FA5: Exception`, { + xid, + message: e.message, + code: e.code, + }); + } finally { + onPull = false; + } + return true; +}; diff --git a/lib/pull/index.js b/lib/pull/index.js new file mode 100644 index 0000000..503ece1 --- /dev/null +++ b/lib/pull/index.js @@ -0,0 +1 @@ +exports.run = require('./run'); diff --git a/lib/pull/run.js b/lib/pull/run.js new file mode 100644 index 0000000..9d818b6 --- /dev/null +++ b/lib/pull/run.js @@ -0,0 +1,22 @@ +const MODULE_NAME = 'PULL.RUN'; +const logger = require('tektrans-logger'); + +const config = require('../config'); +const getInquiry = require('./get-inquiry'); +const getPrepaid = require('./get-prepaid'); +const getPayment = require('./get-payment'); + +/** + * Run pulling schedule + */ +module.exports = async () => { + logger.verbose(`${MODULE_NAME} 34022A49: Run pulling schedule`, { + interval: config.pull_interval_ms, + }); + setInterval(() => { + logger.verbose(`${MODULE_NAME} 06B8C652: Pull run`); + getPrepaid(); + getInquiry(); + getPayment(); + }, config.pull_interval_ms); +}; -- 1.9.0