Commit cd4feda874d40350602bf6821c4d9bef6e0d8bed

Authored by Adhidarma Hadiwinoto
1 parent 05d016dd09
Exists in master and in 1 other branch dev

APISERVER and MATRIX

Showing 11 changed files with 132 additions and 3 deletions Inline Diff

1 { 1 {
2 "name": "HTTPGETX", 2 "name": "HTTPGETX",
3 3
4 "# core_url": "Silahkan diisi dengan core url, bisa dikosongkan jika ingin membaca dari main config komodo", 4 "# core_url": "Silahkan diisi dengan core url, bisa dikosongkan jika ingin membaca dari main config komodo",
5 "core_url": "", 5 "core_url": "",
6 6
7 "listener": { 7 "listener": {
8 "partner": { 8 "partner": {
9 "trust_proxy": ["loopback", "linklocal"], 9 "trust_proxy": ["loopback", "linklocal"],
10 "port": 25614 10 "port": 25614
11 }, 11 },
12 "core": { 12 "core": {
13 "port": 25615 13 "port": 25615
14 },
15 "apiserver": {
16 "port": 25617,
17 "apikey": "PLEASE_CHANGE_ME"
14 } 18 }
15 }, 19 },
16 20
17 "callback_sender": { 21 "callback_sender": {
18 "http_timeout_ms": 30000, 22 "http_timeout_ms": 30000,
19 "sleep_before_retry_ms": 10000, 23 "sleep_before_retry_ms": 10000,
20 "max_retry": 10 24 "max_retry": 10
21 }, 25 },
22 26
23 "# cluster": "Isi dengan boolean atau angka jumlah anak yang akan dibuat. Jika diisi boolean true, jumlah anak akan dihitung otomatis", 27 "# cluster": "Isi dengan boolean atau angka jumlah anak yang akan dibuat. Jika diisi boolean true, jumlah anak akan dihitung otomatis",
24 "cluster": false 28 "cluster": false
25 } 29 }
1 process.chdir(__dirname); 1 process.chdir(__dirname);
2 2
3 const fs = require('fs'); 3 const fs = require('fs');
4 const numCPUs = require('os').cpus().length; 4 const numCPUs = require('os').cpus().length;
5 5
6 fs.writeFileSync('pid.txt', process.pid.toString()); 6 fs.writeFileSync('pid.txt', process.pid.toString());
7 7
8 const config = require('komodo-sdk/config'); 8 const config = require('komodo-sdk/config');
9 9
10 global.KOMODO_LOG_LABEL = `KOMODO-CENTER@${config.name || 'HTTPGETX'}`; 10 global.KOMODO_LOG_LABEL = `KOMODO-CENTER@${config.name || 'HTTPGETX'}`;
11 process.title = global.KOMODO_LOG_LABEL; 11 process.title = global.KOMODO_LOG_LABEL;
12 12
13 const cluster = require('cluster'); 13 const cluster = require('cluster');
14 const logger = require('komodo-sdk/logger'); 14 const logger = require('komodo-sdk/logger');
15 15
16 if (config.cluster && cluster.isMaster) { 16 if (config.cluster && cluster.isMaster) {
17 const numberOfChildren = config.cluster === true ? numCPUs + 1 : config.cluster; 17 const numberOfChildren = config.cluster === true ? numCPUs + 1 : config.cluster;
18 18
19 logger.info('Running on cluster mode', { 19 logger.info('Running on cluster mode', {
20 masterPid: process.pid, 20 masterPid: process.pid,
21 numberOfChildren, 21 numberOfChildren,
22 }); 22 });
23 23
24 for (let i = 0; i < numberOfChildren; i += 1) { 24 for (let i = 0; i < numberOfChildren; i += 1) {
25 cluster.fork(); 25 cluster.fork();
26 } 26 }
27 } else { 27 } else {
28 if (config.cluster) { 28 if (config.cluster) {
29 logger.info(`Worker ${process.pid} started`); 29 logger.info(`Worker ${process.pid} started`);
30 } 30 }
31 31
32 // eslint-disable-next-line global-require 32 // eslint-disable-next-line global-require
33 require('./lib/apiserver');
34 // eslint-disable-next-line global-require
33 require('./lib/core-callback'); 35 require('./lib/core-callback');
34 // eslint-disable-next-line global-require 36 // eslint-disable-next-line global-require
35 require('./lib/partner-listener'); 37 require('./lib/partner-listener');
36 } 38 }
37 39
lib/apiserver/index.js
File was created 1 const MODULE_NAME = 'APISERVER';
2
3 const express = require('express');
4 const config = require('komodo-sdk/config');
5 const logger = require('komodo-sdk/logger');
6
7 const validApikey = require('./valid-apikey');
8
9 const middlewareCommon = require('../middlewares/common');
10 const routerMatrix = require('./routers/matrix');
11
12 const app = express();
13
14 app.use((req, res, next) => {
15 res.locals.httpgetx_subsystem = MODULE_NAME;
16 next();
17 });
18
19 const apikeyChecker = (req, res, next) => {
20 if (validApikey(req.params.apikey)) {
21 next();
22 } else {
23 res.status(403).end('Invalid APIKEY');
24 }
25 };
26
27 app.use(middlewareCommon);
28
29 app.use('/apikey/:apikey', apikeyChecker);
30 app.use('/apikey/:apikey/matrix', routerMatrix);
31
32 app.use((req, res) => {
33 const { xid } = res.locals;
34 res.status(404).end(`KOMODO-HTTP-GET-X CENTER (APISERVER).\n404: Method not found.\n\nXID: ${xid}.\n`);
35 });
36
37 const listenPort = config.listener && config.listener.apiserver && config.listener.apiserver.port;
38 if (
39 listenPort
40 && config.listener && config.listener.apiserver && config.listener.apiserver.apikey
41 ) {
42 app.listen(listenPort, () => {
43 logger.info(`${MODULE_NAME} FAEE1E47: Listening`, { port: listenPort });
44 });
45 } else {
46 logger.info(`${MODULE_NAME}: Disabled because of missing configuration`);
47 }
48
lib/apiserver/routers/matrix.js
File was created 1 const express = require('express');
2
3 const os = require('os');
4 const matrix = require('../../matrix');
5
6 const router = express.Router();
7 module.exports = router;
8
9 const pageIndex = (req, res) => {
10 matrix.uptime = process.uptime();
11 matrix.loadavg = os.loadavg();
12 matrix.workdir = process.cwd;
13 matrix.memory_usage = process.memoryUsage();
14
15 res.json(matrix);
16 };
17
18 router.all('/', pageIndex);
19
lib/apiserver/valid-apikey.js
File was created 1 const config = require('komodo-sdk/config');
2
3 module.exports = (apikey) => apikey
4 && apikey === (
5 config.listener && config.listener.apiserver && config.listener.apiserver.apikey
6 );
7
lib/core-callback/index.js
1 const MODULE_NAME = 'CORE-CALLBACK'; 1 const MODULE_NAME = 'CORE-CALLBACK';
2 2
3 const DEFAULT_LISTENER_FROM_CORE = 25613; 3 const DEFAULT_LISTENER_FROM_CORE = 25613;
4 4
5 const express = require('express'); 5 const express = require('express');
6 const config = require('komodo-sdk/config'); 6 const config = require('komodo-sdk/config');
7 const logger = require('komodo-sdk/logger'); 7 const logger = require('komodo-sdk/logger');
8 const middlewareCommon = require('../middlewares/common'); 8 const middlewareCommon = require('../middlewares/common');
9 const sender = require('./sender'); 9 const sender = require('./sender');
10 const matrix = require('../matrix');
11
10 12
11 const app = express(); 13 const app = express();
12 14
13 app.use(express.json({ extended: true })); 15 app.use(express.json({ extended: true }));
14 app.use(express.urlencoded({ extended: true })); 16 app.use(express.urlencoded({ extended: true }));
15 17
16 app.use((req, res, next) => { 18 app.use((req, res, next) => {
17 res.locals.httpgetx_subsystem = MODULE_NAME; 19 res.locals.httpgetx_subsystem = MODULE_NAME;
18 next(); 20 next();
19 }); 21 });
20 22
21 app.use(middlewareCommon); 23 app.use(middlewareCommon);
22 24
23 app.use((req, res) => { 25 app.use((req, res) => {
26 matrix.messages_from_core += 1;
24 res.end('OK'); 27 res.end('OK');
25 sender(req.query, res.locals.xid); 28 sender(req.query, res.locals.xid);
26 }); 29 });
27 30
28 const port = (config.listener && config.listener.core && config.listener.core.port) 31 const port = (config.listener && config.listener.core && config.listener.core.port)
29 || DEFAULT_LISTENER_FROM_CORE; 32 || DEFAULT_LISTENER_FROM_CORE;
30 33
31 app.listen(port, () => { 34 app.listen(port, () => {
32 logger.info(`${MODULE_NAME} 0375DC4E: Listen from CORE callback on port ${port}`); 35 logger.info(`${MODULE_NAME} 0375DC4E: Listen from CORE callback on port ${port}`);
33 }).on('error', (e) => { 36 }).on('error', (e) => {
34 logger.error(`${MODULE_NAME} A90E42D5: Can not listen CORE callback on port ${port}. ${e.toString()}`); 37 logger.error(`${MODULE_NAME} A90E42D5: Can not listen CORE callback on port ${port}. ${e.toString()}`);
35 process.exit(1); 38 process.exit(1);
36 }); 39 });
37 40
lib/core-callback/sender.js
1 const MODULE_NAME = 'CORE-CALLBACK.SENDER'; 1 const MODULE_NAME = 'CORE-CALLBACK.SENDER';
2 2
3 const axios = require('axios').default; 3 const axios = require('axios').default;
4 const config = require('komodo-sdk/config'); 4 const config = require('komodo-sdk/config');
5 const logger = require('komodo-sdk/logger'); 5 const logger = require('komodo-sdk/logger');
6 6
7 const matrix = require('../matrix');
8
7 const HTTP_TIMEOUT = Number( 9 const HTTP_TIMEOUT = Number(
8 config.callback_sender && config.callback_sender.http_timeout_ms, 10 config.callback_sender && config.callback_sender.http_timeout_ms,
9 ) || 30 * 1000; 11 ) || 30 * 1000;
10 12
11 const SLEEP_BEFORE_RETRY_MS = Number( 13 const SLEEP_BEFORE_RETRY_MS = Number(
12 config.callback_sender && config.callback_sender.sleep_before_retry_ms, 14 config.callback_sender && config.callback_sender.sleep_before_retry_ms,
13 ) || 10 * 1000; 15 ) || 10 * 1000;
14 16
15 const MAX_RETRY = Number( 17 const MAX_RETRY = Number(
16 config.callback_sender && config.callback_sender.max_retry, 18 config.callback_sender && config.callback_sender.max_retry,
17 ) || 10; 19 ) || 10;
18 20
19 logger.verbose(`${MODULE_NAME} 848B9104: Initialized`, { 21 logger.verbose(`${MODULE_NAME} 848B9104: Initialized`, {
20 HTTP_TIMEOUT, 22 HTTP_TIMEOUT,
21 SLEEP_BEFORE_RETRY_MS, 23 SLEEP_BEFORE_RETRY_MS,
22 MAX_RETRY, 24 MAX_RETRY,
23 }); 25 });
24 26
25 const axiosHeaders = { 27 const axiosHeaders = {
26 'Content-Type': 'application/json', 28 'Content-Type': 'application/json',
27 'User-Agent': 'KOMODO-HTTPGETX callback sender', 29 'User-Agent': 'KOMODO-HTTPGETX callback sender',
28 }; 30 };
29 31
30 const sleep = require('../sleep'); 32 const sleep = require('../sleep');
31 const urlConcatQs = require('../url-concat-qs'); 33 const urlConcatQs = require('../url-concat-qs');
32 34
33 const sender = async (data, xid, retry) => { 35 const sender = async (data, xid, retry) => {
34 if (!data.reverse_url) { 36 if (!data.reverse_url) {
35 logger.verbose(`${MODULE_NAME} C4FF18FB: Ignoring missing reverse url`, { 37 logger.verbose(`${MODULE_NAME} C4FF18FB: Ignoring missing reverse url`, {
36 xid, 38 xid,
37 dataFromCore: data, 39 dataFromCore: data,
38 }); 40 });
39 41
40 return; 42 return;
41 } 43 }
42 44
43 const params = { 45 const params = {
44 httpgetx_xid: xid, 46 httpgetx_xid: xid,
45 command: data.command, 47 command: data.command,
46 48
47 request_id: data.request_id && data.request_id.toString(), 49 request_id: data.request_id && data.request_id.toString(),
48 transaction_id: data.transaction_id && data.transaction_id.toString(), 50 transaction_id: data.transaction_id && data.transaction_id.toString(),
49 transaction_date: data.transaction_date, 51 transaction_date: data.transaction_date,
50 52
51 store_name: data.store_name, 53 store_name: data.store_name,
52 terminal_name: data.terminal_name, 54 terminal_name: data.terminal_name,
53 55
54 product_name: data.product_name, 56 product_name: data.product_name,
55 destination: data.destination, 57 destination: data.destination,
56 58
57 rc: data.rc, 59 rc: data.rc,
58 sn: data.sn || undefined, 60 sn: data.sn || undefined,
59 amount: Number(data.amount) || undefined, 61 amount: Number(data.amount) || undefined,
60 ending_balance: Number(data.ending_balance) || undefined, 62 ending_balance: Number(data.ending_balance) || undefined,
61 63
62 message: data.message, 64 message: data.message,
63 65
64 bill_count: Number(data.bill_count) || undefined, 66 bill_count: Number(data.bill_count) || undefined,
65 bill_amount: Number(data.bill_amount) || undefined, 67 bill_amount: Number(data.bill_amount) || undefined,
66 fee_per_bill: Number(data.fee) || undefined, 68 fee_per_bill: Number(data.fee) || undefined,
67 fee_total: Number(data.fee_total) || undefined, 69 fee_total: Number(data.fee_total) || undefined,
68 70
69 bill_detail: data.bill_detail || undefined, 71 bill_detail: data.bill_detail || undefined,
70 }; 72 };
71 73
72 if (data.command === 'INQUIRY' && data.amount_to_charge) { 74 if (data.command === 'INQUIRY' && data.amount_to_charge) {
73 params.amount_to_charge = data.amount_to_charge; 75 params.amount_to_charge = data.amount_to_charge;
74 } 76 }
75 77
76 const isPostpaid = ['INQUIRY', 'PAY'].indexOf(data.command) >= 0; 78 const isPostpaid = ['INQUIRY', 'PAY'].indexOf(data.command) >= 0;
77 const isHttpPost = isPostpaid; 79 const isHttpPost = isPostpaid;
78 80
79 const endpointUrl = isHttpPost ? data.reverse_url : urlConcatQs(data.reverse_url, params); 81 const endpointUrl = isHttpPost ? data.reverse_url : urlConcatQs(data.reverse_url, params);
80 82
81 logger.info(`${MODULE_NAME} 8B6A4CEC: Sending to PARTNER`, { 83 logger.info(`${MODULE_NAME} 8B6A4CEC: Sending to PARTNER`, {
82 xid, 84 xid,
83 retry, 85 retry,
84 isPostpaid, 86 isPostpaid,
85 isHttpPost, 87 isHttpPost,
86 endpointUrl, 88 endpointUrl,
87 }); 89 });
88 90
89 try { 91 try {
90 const response = isHttpPost 92 const response = isHttpPost
91 ? await axios.post(data.reverse_url, params, { 93 ? await axios.post(data.reverse_url, params, {
92 timeout: HTTP_TIMEOUT, 94 timeout: HTTP_TIMEOUT,
93 headers: axiosHeaders, 95 headers: axiosHeaders,
94 }) 96 })
95 : await axios.get(data.reverse_url, { 97 : await axios.get(data.reverse_url, {
96 params, 98 params,
97 timeout: HTTP_TIMEOUT, 99 timeout: HTTP_TIMEOUT,
98 headers: axiosHeaders, 100 headers: axiosHeaders,
99 }); 101 });
100 102
103 matrix.callback_sender.message_sent += 1;
104
105 if (isPostpaid) {
106 matrix.callback_sender.message_sent_using_post_method += 1;
107 } else {
108 matrix.callback_sender.message_sent_using_get_method += 1;
109 }
110
101 logger.info(`${MODULE_NAME} 3641FBD7: Has been sent to PARTNER successfully`, { 111 logger.info(`${MODULE_NAME} 3641FBD7: Has been sent to PARTNER successfully`, {
102 xid, 112 xid,
103 retry, 113 retry,
104 httpStatus: response.status, 114 httpStatus: response.status,
105 responseBody: response && response.data, 115 responseBody: response && response.data,
106 }); 116 });
107 } catch (e) { 117 } catch (e) {
118 matrix.callback_sender.message_sent_failed += 1;
119
108 logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending to PARTNER`, { 120 logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending to PARTNER`, {
109 xid, 121 xid,
110 retry, 122 retry,
111 maxRetry: MAX_RETRY, 123 maxRetry: MAX_RETRY,
112 errCode: e.code, 124 errCode: e.code,
113 errMessage: e.message, 125 errMessage: e.message,
114 reverseUrl: data.reverse_url, 126 reverseUrl: data.reverse_url,
115 endpointUrl, 127 endpointUrl,
116 httpStatus: e.response && e.response.status, 128 httpStatus: e.response && e.response.status,
117 responseBody: e.response && e.response.data, 129 responseBody: e.response && e.response.data,
118 }); 130 });
119 131
120 if ((retry || 0) < MAX_RETRY) { 132 if ((retry || 0) < MAX_RETRY) {
121 await sleep(SLEEP_BEFORE_RETRY_MS); 133 await sleep(SLEEP_BEFORE_RETRY_MS);
122 logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, { 134 logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, {
123 xid, sleepTime: SLEEP_BEFORE_RETRY_MS, 135 xid, sleepTime: SLEEP_BEFORE_RETRY_MS,
124 }); 136 });
125 sender(data, xid, (retry || 0) + 1); 137 sender(data, xid, (retry || 0) + 1);
126 } 138 }
127 } 139 }
128 }; 140 };
129 141
130 module.exports = sender; 142 module.exports = sender;
131 143
File was created 1 const os = require('os');
2 // const config = require('komodo-sdk/config');
3
4 module.exports = {
5 pid: process.pid,
6 start_time: new Date(),
7 uptime: process.uptime(),
8 hostname: os.hostname(),
9 loadavg: os.loadavg(),
10 workdir: process.cwd(),
11 memory_usage: process.memoryUsage(),
12 messages_from_core: 0,
13 messages_to_core: 0,
14 callback_sender: {
15 message_sent: 0,
16 message_sent_failed: 0,
17 message_sent_using_get_method: 0,
18 message_sent_using_post_method: 0,
19 },
20 };
21
lib/middlewares/common.js
1 // const uuidv1 = require('uuid/v1'); 1 const MODULE_NAME = 'MIDDLEWARES';
2
3 const uuidv1 = require('uuid/v1');
2 const uniqid = require('uniqid'); 4 const uniqid = require('uniqid');
5
6 const config = require('komodo-sdk/config');
3 const logger = require('komodo-sdk/logger'); 7 const logger = require('komodo-sdk/logger');
4 8
5 module.exports = function common(req, res, next) { 9 module.exports = function common(req, res, next) {
6 if (req.url.search('/favicon.ico') === 0) { 10 if (req.url.search('/favicon.ico') === 0) {
7 res.sendStatus(404); 11 res.sendStatus(404);
8 return; 12 return;
9 } 13 }
10 14
11 res.locals.xid = uniqid(); 15 res.locals.xid = config.xid_from_uuid ? uuidv1()
16 : uniqid();
17
12 res.locals.x_http_request_ts = new Date(); 18 res.locals.x_http_request_ts = new Date();
13 19
14 logger.info(`Got request from ${res.locals.httpgetx_subsystem === 'CORE-CALLBACK' ? 'CORE' : 'PARTNER'}`, { 20 logger.info(`${MODULE_NAME}.COMMON B6257542: Got a request`, {
15 xid: res.locals.xid, 21 xid: res.locals.xid,
16 pid: process.pid, 22 pid: process.pid,
23 subsystem: res.locals.httpgetx_subsystem,
17 requester_ip: req.ip, 24 requester_ip: req.ip,
18 method: req.method, 25 method: req.method,
19 path: req.path, 26 path: req.path,
20 url: req.url, 27 url: req.url,
21 qs: req.query, 28 qs: req.query,
22 body: req.body, 29 body: req.body,
23 }); 30 });
24 next(); 31 next();
25 }; 32 };
26 33
lib/partner-listener/index.js
1 const MODULE_NAME = 'PARTNER-LISTENER';
2
1 const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614; 3 const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614;
2 4
3 const express = require('express'); 5 const express = require('express');
4 6
5 const config = require('komodo-sdk/config'); 7 const config = require('komodo-sdk/config');
6 const logger = require('komodo-sdk/logger'); 8 const logger = require('komodo-sdk/logger');
7 9
8 const middlewareCommon = require('../middlewares/common'); 10 const middlewareCommon = require('../middlewares/common');
9 11
10 const routerInquiry = require('./routers/inquiry'); 12 const routerInquiry = require('./routers/inquiry');
11 const routerPay = require('./routers/pay'); 13 const routerPay = require('./routers/pay');
12 const routerTopup = require('./routers/topup'); 14 const routerTopup = require('./routers/topup');
13 const routerTrxStatus = require('./routers/trx-status'); 15 const routerTrxStatus = require('./routers/trx-status');
14 16
15 const app = express(); 17 const app = express();
16 18
17 if (config.partner && config.partner.trust_proxy) { 19 if (config.partner && config.partner.trust_proxy) {
18 app.set('trust proxy', config.partner.trust_proxy); 20 app.set('trust proxy', config.partner.trust_proxy);
19 } 21 }
20 22
23 app.use((req, res, next) => {
24 res.locals.httpgetx_subsystem = MODULE_NAME;
25 next();
26 });
27
21 app.use(express.json({ extended: true })); 28 app.use(express.json({ extended: true }));
22 app.use(express.urlencoded({ extended: true })); 29 app.use(express.urlencoded({ extended: true }));
23 app.use(middlewareCommon); 30 app.use(middlewareCommon);
24 31
25 app.use('/ping', (req, res) => { 32 app.use('/ping', (req, res) => {
26 res.json({ 33 res.json({
27 error: false, 34 error: false,
28 xid: res.locals.xid, 35 xid: res.locals.xid,
29 from_ip: req.ip, 36 from_ip: req.ip,
30 ts: new Date(), 37 ts: new Date(),
31 request: { 38 request: {
32 method: req.method, 39 method: req.method,
33 userAgent: req.get('user-agent'), 40 userAgent: req.get('user-agent'),
34 contentType: req.get('content-type'), 41 contentType: req.get('content-type'),
35 qs: req.query, 42 qs: req.query,
36 body: req.body, 43 body: req.body,
37 }, 44 },
38 }); 45 });
39 }); 46 });
40 app.use('/inquiry', routerInquiry); 47 app.use('/inquiry', routerInquiry);
41 app.use('/pay', routerPay); 48 app.use('/pay', routerPay);
42 app.use('/topup', routerTopup); 49 app.use('/topup', routerTopup);
43 app.use('/trx-status', routerTrxStatus); 50 app.use('/trx-status', routerTrxStatus);
44 51
45 app.use((req, res) => { 52 app.use((req, res) => {
46 const { xid } = res.locals; 53 const { xid } = res.locals;
47 res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`); 54 res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`);
48 }); 55 });
49 56
50 app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => { 57 app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => {
51 logger.info(`Listen from partner request on port ${config.listener.partner.port}`); 58 logger.info(`Listen from partner request on port ${config.listener.partner.port}`);
52 }).on('error', (e) => { 59 }).on('error', (e) => {
53 logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`); 60 logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`);
54 process.exit(1); 61 process.exit(1);
55 }); 62 });
56 63
lib/partner-listener/routers/topup.js
1 const MODULE_NAME = 'PARTNER-LISTENER.ROUTER.TOPUP'; 1 const MODULE_NAME = 'PARTNER-LISTENER.ROUTER.TOPUP';
2 2
3 const express = require('express'); 3 const express = require('express');
4 4
5 const config = require('komodo-sdk/config'); 5 const config = require('komodo-sdk/config');
6 const logger = require('komodo-sdk/logger'); 6 const logger = require('komodo-sdk/logger');
7 const coreapi = require('komodo-sdk/coreapi'); 7 const coreapi = require('komodo-sdk/coreapi');
8 // const coreapi = require('../../coreapi'); 8 // const coreapi = require('../../coreapi');
9 const matrix = require('../../matrix');
9 10
10 const router = express.Router(); 11 const router = express.Router();
11 module.exports = router; 12 module.exports = router;
12 13
13 function onInvalidParameter(missingParameter, req, res) { 14 function onInvalidParameter(missingParameter, req, res) {
14 logger.verbose(`${MODULE_NAME} 1536D577: Undefined ${missingParameter} parameter`, { 15 logger.verbose(`${MODULE_NAME} 1536D577: Undefined ${missingParameter} parameter`, {
15 xid: res.locals.xid, 16 xid: res.locals.xid,
16 ip: req.ip, 17 ip: req.ip,
17 terminal_name: req.body.terminal_name || req.query.terminal_name, 18 terminal_name: req.body.terminal_name || req.query.terminal_name,
18 request_id: req.body.request_id || req.query.request_id, 19 request_id: req.body.request_id || req.query.request_id,
19 product_name: req.body.product_name || req.query.product_name, 20 product_name: req.body.product_name || req.query.product_name,
20 destination: req.body.destination || req.query.destination, 21 destination: req.body.destination || req.query.destination,
21 }); 22 });
22 res.end('INVALID REQUEST'); 23 res.end('INVALID REQUEST');
23 } 24 }
24 25
25 function pagePrerequisite(req, res, next) { 26 function pagePrerequisite(req, res, next) {
26 if (!req.body) req.body = {}; 27 if (!req.body) req.body = {};
27 28
28 if (!req.body.terminal_name && !req.query.terminal_name) { 29 if (!req.body.terminal_name && !req.query.terminal_name) {
29 onInvalidParameter('terminal_name', req, res); 30 onInvalidParameter('terminal_name', req, res);
30 return; 31 return;
31 } 32 }
32 33
33 if (!req.body.password && !req.query.password) { 34 if (!req.body.password && !req.query.password) {
34 onInvalidParameter('password', req, res); 35 onInvalidParameter('password', req, res);
35 return; 36 return;
36 } 37 }
37 38
38 if (!req.body.request_id && !req.query.request_id) { 39 if (!req.body.request_id && !req.query.request_id) {
39 onInvalidParameter('request_id', req, res); 40 onInvalidParameter('request_id', req, res);
40 return; 41 return;
41 } 42 }
42 43
43 if (!req.body.product_name && !req.query.product_name) { 44 if (!req.body.product_name && !req.query.product_name) {
44 onInvalidParameter('product_name', req, res); 45 onInvalidParameter('product_name', req, res);
45 return; 46 return;
46 } 47 }
47 48
48 if (!req.body.destination && !req.query.destination) { 49 if (!req.body.destination && !req.query.destination) {
49 onInvalidParameter('destination', req, res); 50 onInvalidParameter('destination', req, res);
50 return; 51 return;
51 } 52 }
52 53
53 next(); 54 next();
54 } 55 }
55 56
56 async function pageIndex(req, res) { 57 async function pageIndex(req, res) {
57 const { xid } = res.locals; 58 const { xid } = res.locals;
58 59
59 const terminalName = `${req.body.terminal_name || req.query.terminal_name}@${req.ip.replace(/^::ffff:/, '')}`; 60 const terminalName = `${req.body.terminal_name || req.query.terminal_name}@${req.ip.replace(/^::ffff:/, '')}`;
60 61
62 matrix.messages_to_core += 1;
63
61 const [err, coreResponse] = await coreapi({ 64 const [err, coreResponse] = await coreapi({
62 xid, 65 xid,
63 path: '/prepaid/buy', 66 path: '/prepaid/buy',
64 qs: { 67 qs: {
65 terminal_name: terminalName, 68 terminal_name: terminalName,
66 password: req.body.password || req.query.password, 69 password: req.body.password || req.query.password,
67 request_id: req.body.request_id || req.query.request_id, 70 request_id: req.body.request_id || req.query.request_id,
68 product_name: req.body.product_name || req.query.product_name, 71 product_name: req.body.product_name || req.query.product_name,
69 destination: req.body.destination || req.query.destination, 72 destination: req.body.destination || req.query.destination,
70 origin: config.name || 'HTTPGETX', 73 origin: config.name || 'HTTPGETX',
71 report_ip: config.listener.core.ip || null, 74 report_ip: config.listener.core.ip || null,
72 report_port: config.listener.core.port, 75 report_port: config.listener.core.port,
73 reverse_url: req.body.reverse_url || req.query.reverse_url || null, 76 reverse_url: req.body.reverse_url || req.query.reverse_url || null,
74 }, 77 },
75 }); 78 });
76 79
77 if (err || !coreResponse) { 80 if (err || !coreResponse) {
78 logger.warn(`${MODULE_NAME} 8DEBE15F: ERROR on /prepaid/buy response`, { 81 logger.warn(`${MODULE_NAME} 8DEBE15F: ERROR on /prepaid/buy response`, {
79 xid, 82 xid,
80 err, 83 err,
81 coreResponseTypeof: typeof coreResponse, 84 coreResponseTypeof: typeof coreResponse,
82 coreResponse, 85 coreResponse,
83 }); 86 });
84 res.end('INVALID CORE RESPONSE'); 87 res.end('INVALID CORE RESPONSE');
85 return; 88 return;
86 } 89 }
87 90
88 logger.verbose(`${MODULE_NAME} 2528A9B4: Got CORE response`, { 91 logger.verbose(`${MODULE_NAME} 2528A9B4: Got CORE response`, {
89 xid, 92 xid,
90 coreResponse, 93 coreResponse,
91 }); 94 });
92 95
93 const responseToPartner = { 96 const responseToPartner = {
94 httpgetx_xid: xid, 97 httpgetx_xid: xid,
95 request_id: coreResponse.request_id, 98 request_id: coreResponse.request_id,
96 transaction_id: coreResponse.transaction_id, 99 transaction_id: coreResponse.transaction_id,
97 transaction_date: coreResponse.transaction_date, 100 transaction_date: coreResponse.transaction_date,
98 store_name: coreResponse.store_name, 101 store_name: coreResponse.store_name,
99 terminal_name: coreResponse.terminal_name, 102 terminal_name: coreResponse.terminal_name,
100 product_name: coreResponse.product_name, 103 product_name: coreResponse.product_name,
101 destination: coreResponse.destination, 104 destination: coreResponse.destination,
102 rc: coreResponse.rc, 105 rc: coreResponse.rc,
103 sn: coreResponse.sn || undefined, 106 sn: coreResponse.sn || undefined,
104 amount: Number(coreResponse.amount) || undefined, 107 amount: Number(coreResponse.amount) || undefined,
105 ending_balance: Number(coreResponse.ending_balance) || undefined, 108 ending_balance: Number(coreResponse.ending_balance) || undefined,
106 message: coreResponse.message, 109 message: coreResponse.message,
107 }; 110 };
108 111
109 res.json(responseToPartner); 112 res.json(responseToPartner);
110 } 113 }
111 114
112 // router.all('/', (req, res) => { res.status(404).end('404: Not implemented yet'); }); 115 // router.all('/', (req, res) => { res.status(404).end('404: Not implemented yet'); });
113 router.get('/', pagePrerequisite, pageIndex); 116 router.get('/', pagePrerequisite, pageIndex);
114 117