Commit 810fa18dae9eb5c2f21cea9bbc42524ccb4e76d4

Authored by Adhidarma Hadiwinoto
1 parent 4978f3b374
Exists in master and in 1 other branch dev

Migrate to tektrans-logger

Showing 14 changed files with 14 additions and 14 deletions Inline Diff

lib/apiserver/index.js
1 const MODULE_NAME = 'APISERVER'; 1 const MODULE_NAME = 'APISERVER';
2 2
3 const express = require('express'); 3 const express = require('express');
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('tektrans-logger');
6 6
7 const validApikey = require('./valid-apikey'); 7 const validApikey = require('./valid-apikey');
8 8
9 const middlewareCommon = require('../middlewares/common'); 9 const middlewareCommon = require('../middlewares/common');
10 const routerMatrix = require('./routers/matrix'); 10 const routerMatrix = require('./routers/matrix');
11 11
12 const app = express(); 12 const app = express();
13 13
14 app.use((req, res, next) => { 14 app.use((req, res, next) => {
15 res.locals.httpgetx_subsystem = MODULE_NAME; 15 res.locals.httpgetx_subsystem = MODULE_NAME;
16 next(); 16 next();
17 }); 17 });
18 18
19 const apikeyChecker = (req, res, next) => { 19 const apikeyChecker = (req, res, next) => {
20 if (validApikey(req.params.apikey)) { 20 if (validApikey(req.params.apikey)) {
21 next(); 21 next();
22 } else { 22 } else {
23 res.status(403).end('Invalid APIKEY'); 23 res.status(403).end('Invalid APIKEY');
24 } 24 }
25 }; 25 };
26 26
27 app.use(middlewareCommon); 27 app.use(middlewareCommon);
28 28
29 app.use('/apikey/:apikey', apikeyChecker); 29 app.use('/apikey/:apikey', apikeyChecker);
30 app.use('/apikey/:apikey/matrix', routerMatrix); 30 app.use('/apikey/:apikey/matrix', routerMatrix);
31 31
32 app.use((req, res) => { 32 app.use((req, res) => {
33 const { xid } = res.locals; 33 const { xid } = res.locals;
34 res.status(404).end(`KOMODO-HTTP-GET-X CENTER (APISERVER).\n404: Method not found.\n\nXID: ${xid}.\n`); 34 res.status(404).end(`KOMODO-HTTP-GET-X CENTER (APISERVER).\n404: Method not found.\n\nXID: ${xid}.\n`);
35 }); 35 });
36 36
37 const listenPort = config.listener && config.listener.apiserver && config.listener.apiserver.port; 37 const listenPort = config.listener && config.listener.apiserver && config.listener.apiserver.port;
38 if ( 38 if (
39 listenPort 39 listenPort
40 && config.listener && config.listener.apiserver && config.listener.apiserver.apikey 40 && config.listener && config.listener.apiserver && config.listener.apiserver.apikey
41 ) { 41 ) {
42 app.listen(listenPort, () => { 42 app.listen(listenPort, () => {
43 logger.info(`${MODULE_NAME} FAEE1E47: Listening`, { port: listenPort }); 43 logger.info(`${MODULE_NAME} FAEE1E47: Listening`, { port: listenPort });
44 }); 44 });
45 } else { 45 } else {
46 logger.info(`${MODULE_NAME}: Disabled because of missing configuration`); 46 logger.info(`${MODULE_NAME}: Disabled because of missing configuration`);
47 } 47 }
48 48
lib/core-callback/dumper/req.js
1 const MODULE_NAME = 'CORE-CALLBACK.DUMPER.REQ'; 1 const MODULE_NAME = 'CORE-CALLBACK.DUMPER.REQ';
2 2
3 // const fs = require('fs'); 3 // const fs = require('fs');
4 const fsPromise = require('fs').promises; 4 const fsPromise = require('fs').promises;
5 const path = require('path'); 5 const path = require('path');
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('tektrans-logger');
8 const moment = require('moment'); 8 const moment = require('moment');
9 9
10 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists'); 10 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists');
11 11
12 const baseDumpDir = path.join('dump', 'core-callback'); 12 const baseDumpDir = path.join('dump', 'core-callback');
13 const lastDumpFileName = path.join(baseDumpDir, 'last-req'); 13 const lastDumpFileName = path.join(baseDumpDir, 'last-req');
14 14
15 module.exports = async (req, res, next) => { 15 module.exports = async (req, res, next) => {
16 if ( 16 if (
17 !config 17 !config
18 || !config.listener 18 || !config.listener
19 || !config.listener.core 19 || !config.listener.core
20 || !config.listener.core.dump 20 || !config.listener.core.dump
21 ) { 21 ) {
22 next(); 22 next();
23 return; 23 return;
24 } 24 }
25 25
26 const { xid } = res.locals; 26 const { xid } = res.locals;
27 27
28 const data = `-------- 28 const data = `--------
29 XID: ${xid} 29 XID: ${xid}
30 PID: ${process.pid} 30 PID: ${process.pid}
31 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')} 31 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')}
32 32
33 REQ-CONTENT-TYPE: ${req.get('content-type')} 33 REQ-CONTENT-TYPE: ${req.get('content-type')}
34 34
35 REQ QUERY-STRING: 35 REQ QUERY-STRING:
36 ${JSON.stringify(req.query, null, 2)} 36 ${JSON.stringify(req.query, null, 2)}
37 37
38 REQ BODY: 38 REQ BODY:
39 ${JSON.stringify(req.body, null, 2)} 39 ${JSON.stringify(req.body, null, 2)}
40 `; 40 `;
41 41
42 42
43 const dumpFileName = path.join( 43 const dumpFileName = path.join(
44 baseDumpDir, 44 baseDumpDir,
45 moment().format('YYYY-MM-DD'), 45 moment().format('YYYY-MM-DD'),
46 [ 46 [
47 'req', 47 'req',
48 moment().format('YYMMDD_HHmmss_SSS'), 48 moment().format('YYMMDD_HHmmss_SSS'),
49 xid, 49 xid,
50 ].join('_'), 50 ].join('_'),
51 ); 51 );
52 52
53 try { 53 try {
54 await mkdirIfNotExists(xid, path.dirname(dumpFileName)); 54 await mkdirIfNotExists(xid, path.dirname(dumpFileName));
55 await fsPromise.writeFile(lastDumpFileName, data); 55 await fsPromise.writeFile(lastDumpFileName, data);
56 await fsPromise.writeFile(dumpFileName, data); 56 await fsPromise.writeFile(dumpFileName, data);
57 } catch (e) { 57 } catch (e) {
58 logger.warn(`${MODULE_NAME} E77C2B23: Exception on dumping file`, { 58 logger.warn(`${MODULE_NAME} E77C2B23: Exception on dumping file`, {
59 xid, 59 xid,
60 eCode: e.code, 60 eCode: e.code,
61 eMessage: e.eMessage, 61 eMessage: e.eMessage,
62 }); 62 });
63 } 63 }
64 64
65 next(); 65 next();
66 }; 66 };
67 67
lib/core-callback/dumper/sender.js
1 const MODULE_NAME = 'CORE-CALLBACK.DUMPER.SENDER'; 1 const MODULE_NAME = 'CORE-CALLBACK.DUMPER.SENDER';
2 2
3 const fsPromise = require('fs').promises; 3 const fsPromise = require('fs').promises;
4 const path = require('path'); 4 const path = require('path');
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('tektrans-logger');
7 const moment = require('moment'); 7 const moment = require('moment');
8 8
9 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists'); 9 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists');
10 10
11 const baseDumpDir = path.join('dump', 'core-callback'); 11 const baseDumpDir = path.join('dump', 'core-callback');
12 const lastDumpFileName = path.join(baseDumpDir, 'last-sent'); 12 const lastDumpFileName = path.join(baseDumpDir, 'last-sent');
13 13
14 module.exports = async (xid, httpMethod, endpointUrl, params, axiosResponse, axiosError) => { 14 module.exports = async (xid, httpMethod, endpointUrl, params, axiosResponse, axiosError) => {
15 if ( 15 if (
16 !config 16 !config
17 || !config.listener 17 || !config.listener
18 || !config.listener.core 18 || !config.listener.core
19 || !config.listener.core.dump 19 || !config.listener.core.dump
20 ) { 20 ) {
21 return; 21 return;
22 } 22 }
23 23
24 const data = `-------- 24 const data = `--------
25 XID: ${xid} 25 XID: ${xid}
26 PID: ${process.pid} 26 PID: ${process.pid}
27 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')} 27 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')}
28 28
29 HTTP METHOD: ${httpMethod} 29 HTTP METHOD: ${httpMethod}
30 ENDPOINT URL: ${endpointUrl} 30 ENDPOINT URL: ${endpointUrl}
31 31
32 REQ PARAMS: 32 REQ PARAMS:
33 ${JSON.stringify(params, null, 2)} 33 ${JSON.stringify(params, null, 2)}
34 34
35 ERROR CODE: ${(axiosError && axiosError.code) || ''} 35 ERROR CODE: ${(axiosError && axiosError.code) || ''}
36 ERROR MESSAGE: ${(axiosError && axiosError.message) || ''} 36 ERROR MESSAGE: ${(axiosError && axiosError.message) || ''}
37 37
38 RES HTTP STATUS: ${axiosResponse && axiosResponse.status} 38 RES HTTP STATUS: ${axiosResponse && axiosResponse.status}
39 RES BODY: 39 RES BODY:
40 ${ 40 ${
41 axiosResponse && axiosResponse.data && ( 41 axiosResponse && axiosResponse.data && (
42 ((typeof axiosResponse.data === 'string') && axiosResponse.data) 42 ((typeof axiosResponse.data === 'string') && axiosResponse.data)
43 || JSON.stringify(axiosResponse.data, null, 2) 43 || JSON.stringify(axiosResponse.data, null, 2)
44 ) 44 )
45 } 45 }
46 `; 46 `;
47 47
48 const dumpFileName = path.join( 48 const dumpFileName = path.join(
49 baseDumpDir, 49 baseDumpDir,
50 moment().format('YYYY-MM-DD'), 50 moment().format('YYYY-MM-DD'),
51 [ 51 [
52 'sent', 52 'sent',
53 moment().format('YYMMDD_HHmmss_SSS'), 53 moment().format('YYMMDD_HHmmss_SSS'),
54 xid, 54 xid,
55 ].join('_'), 55 ].join('_'),
56 ); 56 );
57 57
58 try { 58 try {
59 await mkdirIfNotExists(xid, path.dirname(dumpFileName)); 59 await mkdirIfNotExists(xid, path.dirname(dumpFileName));
60 await fsPromise.writeFile(lastDumpFileName, data); 60 await fsPromise.writeFile(lastDumpFileName, data);
61 await fsPromise.writeFile(dumpFileName, data); 61 await fsPromise.writeFile(dumpFileName, data);
62 } catch (e) { 62 } catch (e) {
63 logger.warn(`${MODULE_NAME} 9BA99454: Exception on dumping file`, { 63 logger.warn(`${MODULE_NAME} 9BA99454: Exception on dumping file`, {
64 xid, 64 xid,
65 eCode: e.code, 65 eCode: e.code,
66 eMessage: e.eMessage, 66 eMessage: e.eMessage,
67 }); 67 });
68 } 68 }
69 }; 69 };
70 70
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('tektrans-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 dumperReq = require('./dumper/req'); 10 const dumperReq = require('./dumper/req');
11 const matrix = require('../matrix'); 11 const matrix = require('../matrix');
12 12
13 const app = express(); 13 const app = express();
14 14
15 app.use(express.json({ extended: true })); 15 app.use(express.json({ extended: true }));
16 app.use(express.urlencoded({ extended: true })); 16 app.use(express.urlencoded({ extended: true }));
17 17
18 app.use((req, res, next) => { 18 app.use((req, res, next) => {
19 res.locals.httpgetx_subsystem = MODULE_NAME; 19 res.locals.httpgetx_subsystem = MODULE_NAME;
20 next(); 20 next();
21 }); 21 });
22 22
23 app.use(middlewareCommon); 23 app.use(middlewareCommon);
24 app.use(dumperReq); 24 app.use(dumperReq);
25 25
26 app.use((req, res) => { 26 app.use((req, res) => {
27 matrix.core.received += 1; 27 matrix.core.received += 1;
28 res.end('OK'); 28 res.end('OK');
29 29
30 const data = req.method === 'GET' ? req.query : req.body; 30 const data = req.method === 'GET' ? req.query : req.body;
31 sender(data, res.locals.xid); 31 sender(data, res.locals.xid);
32 }); 32 });
33 33
34 const port = (config.listener && config.listener.core && config.listener.core.port) 34 const port = (config.listener && config.listener.core && config.listener.core.port)
35 || DEFAULT_LISTENER_FROM_CORE; 35 || DEFAULT_LISTENER_FROM_CORE;
36 36
37 app.listen(port, () => { 37 app.listen(port, () => {
38 logger.info(`${MODULE_NAME} 0375DC4E: Listen from CORE callback on port ${port}`); 38 logger.info(`${MODULE_NAME} 0375DC4E: Listen from CORE callback on port ${port}`);
39 }).on('error', (e) => { 39 }).on('error', (e) => {
40 logger.error(`${MODULE_NAME} A90E42D5: Can not listen CORE callback on port ${port}. ${e.toString()}`); 40 logger.error(`${MODULE_NAME} A90E42D5: Can not listen CORE callback on port ${port}. ${e.toString()}`);
41 process.exit(1); 41 process.exit(1);
42 }); 42 });
43 43
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('tektrans-logger');
6 6
7 const dumper = require('./dumper/sender'); 7 const dumper = require('./dumper/sender');
8 const matrix = require('../matrix'); 8 const matrix = require('../matrix');
9 9
10 const HTTP_TIMEOUT = Number( 10 const HTTP_TIMEOUT = Number(
11 config.callback_sender && config.callback_sender.http_timeout_ms, 11 config.callback_sender && config.callback_sender.http_timeout_ms,
12 ) || 30 * 1000; 12 ) || 30 * 1000;
13 13
14 const SLEEP_BEFORE_RETRY_MS = Number( 14 const SLEEP_BEFORE_RETRY_MS = Number(
15 config.callback_sender && config.callback_sender.sleep_before_retry_ms, 15 config.callback_sender && config.callback_sender.sleep_before_retry_ms,
16 ) || 10 * 1000; 16 ) || 10 * 1000;
17 17
18 const MAX_RETRY = Number( 18 const MAX_RETRY = Number(
19 config.callback_sender && config.callback_sender.max_retry, 19 config.callback_sender && config.callback_sender.max_retry,
20 ) || 10; 20 ) || 10;
21 21
22 logger.verbose(`${MODULE_NAME} 848B9104: Initialized`, { 22 logger.verbose(`${MODULE_NAME} 848B9104: Initialized`, {
23 HTTP_TIMEOUT, 23 HTTP_TIMEOUT,
24 SLEEP_BEFORE_RETRY_MS, 24 SLEEP_BEFORE_RETRY_MS,
25 MAX_RETRY, 25 MAX_RETRY,
26 }); 26 });
27 27
28 const axiosHeaders = { 28 const axiosHeaders = {
29 'Content-Type': 'application/json', 29 'Content-Type': 'application/json',
30 'User-Agent': 'KOMODO-HTTPGETX callback sender', 30 'User-Agent': 'KOMODO-HTTPGETX callback sender',
31 }; 31 };
32 32
33 const sleep = require('../sleep'); 33 const sleep = require('../sleep');
34 const urlConcatQs = require('../url-concat-qs'); 34 const urlConcatQs = require('../url-concat-qs');
35 35
36 const sender = async (data, xid, retry) => { 36 const sender = async (data, xid, retry) => {
37 if (!data.reverse_url) { 37 if (!data.reverse_url) {
38 logger.verbose(`${MODULE_NAME} C4FF18FB: Ignoring missing reverse url`, { 38 logger.verbose(`${MODULE_NAME} C4FF18FB: Ignoring missing reverse url`, {
39 xid, 39 xid,
40 dataFromCore: data, 40 dataFromCore: data,
41 }); 41 });
42 42
43 return; 43 return;
44 } 44 }
45 45
46 const params = { 46 const params = {
47 httpgetx_xid: xid, 47 httpgetx_xid: xid,
48 command: data.command, 48 command: data.command,
49 49
50 request_id: data.request_id && data.request_id.toString(), 50 request_id: data.request_id && data.request_id.toString(),
51 transaction_id: data.transaction_id && data.transaction_id.toString(), 51 transaction_id: data.transaction_id && data.transaction_id.toString(),
52 transaction_date: data.transaction_date, 52 transaction_date: data.transaction_date,
53 53
54 store_name: data.store_name, 54 store_name: data.store_name,
55 terminal_name: data.terminal_name, 55 terminal_name: data.terminal_name,
56 56
57 product_name: data.product_name, 57 product_name: data.product_name,
58 destination: data.destination, 58 destination: data.destination,
59 59
60 rc: data.rc, 60 rc: data.rc,
61 sn: data.sn || undefined, 61 sn: data.sn || undefined,
62 amount: Number(data.amount) || undefined, 62 amount: Number(data.amount) || undefined,
63 ending_balance: Number(data.ending_balance) || undefined, 63 ending_balance: Number(data.ending_balance) || undefined,
64 64
65 message: data.message, 65 message: data.message,
66 66
67 bill_count: Number(data.bill_count) || undefined, 67 bill_count: Number(data.bill_count) || undefined,
68 bill_amount: Number(data.bill_amount) || undefined, 68 bill_amount: Number(data.bill_amount) || undefined,
69 fee_per_bill: Number(data.fee) || undefined, 69 fee_per_bill: Number(data.fee) || undefined,
70 fee_total: Number(data.fee_total) || undefined, 70 fee_total: Number(data.fee_total) || undefined,
71 71
72 bill_detail: data.bill_detail || undefined, 72 bill_detail: data.bill_detail || undefined,
73 struk: data.struk || undefined, 73 struk: data.struk || undefined,
74 }; 74 };
75 75
76 if (data.command === 'INQUIRY' && data.amount_to_charge) { 76 if (data.command === 'INQUIRY' && data.amount_to_charge) {
77 params.amount_to_charge = data.amount_to_charge; 77 params.amount_to_charge = data.amount_to_charge;
78 } 78 }
79 79
80 const isPostpaid = ['INQUIRY', 'PAY'].indexOf(data.command) >= 0; 80 const isPostpaid = ['INQUIRY', 'PAY'].indexOf(data.command) >= 0;
81 const isHttpPost = isPostpaid; 81 const isHttpPost = isPostpaid;
82 82
83 const endpointUrl = isHttpPost ? data.reverse_url : urlConcatQs(data.reverse_url, params); 83 const endpointUrl = isHttpPost ? data.reverse_url : urlConcatQs(data.reverse_url, params);
84 84
85 logger.info(`${MODULE_NAME} 8B6A4CEC: Sending to PARTNER`, { 85 logger.info(`${MODULE_NAME} 8B6A4CEC: Sending to PARTNER`, {
86 xid, 86 xid,
87 retry, 87 retry,
88 isPostpaid, 88 isPostpaid,
89 isHttpPost, 89 isHttpPost,
90 endpointUrl, 90 endpointUrl,
91 }); 91 });
92 92
93 let responseToDump; 93 let responseToDump;
94 let errorResponseToDump; 94 let errorResponseToDump;
95 95
96 try { 96 try {
97 const response = isHttpPost 97 const response = isHttpPost
98 ? await axios.post(data.reverse_url, params, { 98 ? await axios.post(data.reverse_url, params, {
99 timeout: HTTP_TIMEOUT, 99 timeout: HTTP_TIMEOUT,
100 headers: axiosHeaders, 100 headers: axiosHeaders,
101 }) 101 })
102 : await axios.get(data.reverse_url, { 102 : await axios.get(data.reverse_url, {
103 params, 103 params,
104 timeout: HTTP_TIMEOUT, 104 timeout: HTTP_TIMEOUT,
105 headers: axiosHeaders, 105 headers: axiosHeaders,
106 }); 106 });
107 107
108 responseToDump = response; 108 responseToDump = response;
109 109
110 matrix.callback_sender.sent += 1; 110 matrix.callback_sender.sent += 1;
111 matrix.callback_sender.active_count += 1; 111 matrix.callback_sender.active_count += 1;
112 matrix.callback_sender.active_sending[xid] = { 112 matrix.callback_sender.active_sending[xid] = {
113 ts: new Date(), 113 ts: new Date(),
114 trxId: data.trx_id, 114 trxId: data.trx_id,
115 reverseUrl: data.reverse_url, 115 reverseUrl: data.reverse_url,
116 }; 116 };
117 117
118 if (isPostpaid) { 118 if (isPostpaid) {
119 matrix.callback_sender.sent_using_post += 1; 119 matrix.callback_sender.sent_using_post += 1;
120 } else { 120 } else {
121 matrix.callback_sender.sent_using_get += 1; 121 matrix.callback_sender.sent_using_get += 1;
122 } 122 }
123 123
124 logger.info(`${MODULE_NAME} 3641FBD7: Has been sent to PARTNER successfully`, { 124 logger.info(`${MODULE_NAME} 3641FBD7: Has been sent to PARTNER successfully`, {
125 xid, 125 xid,
126 retry, 126 retry,
127 httpStatus: response.status, 127 httpStatus: response.status,
128 responseBody: response && response.data, 128 responseBody: response && response.data,
129 }); 129 });
130 } catch (e) { 130 } catch (e) {
131 matrix.callback_sender.sent_failed += 1; 131 matrix.callback_sender.sent_failed += 1;
132 matrix.callback_sender.last_error = { 132 matrix.callback_sender.last_error = {
133 xid, 133 xid,
134 ts: new Date(), 134 ts: new Date(),
135 eCode: e.code, 135 eCode: e.code,
136 eMessage: e.message, 136 eMessage: e.message,
137 trxId: data.trx_id, 137 trxId: data.trx_id,
138 reverseUrl: data.reverse_url, 138 reverseUrl: data.reverse_url,
139 httpStatus: e.response && e.response.status, 139 httpStatus: e.response && e.response.status,
140 responseBody: e.response && e.response.data, 140 responseBody: e.response && e.response.data,
141 }; 141 };
142 142
143 responseToDump = e.response && e.response.data; 143 responseToDump = e.response && e.response.data;
144 errorResponseToDump = e; 144 errorResponseToDump = e;
145 145
146 logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending to PARTNER`, { 146 logger.warn(`${MODULE_NAME} A1EC9E70: Failed on sending to PARTNER`, {
147 xid, 147 xid,
148 retry, 148 retry,
149 maxRetry: MAX_RETRY, 149 maxRetry: MAX_RETRY,
150 errCode: e.code, 150 errCode: e.code,
151 errMessage: e.message, 151 errMessage: e.message,
152 reverseUrl: data.reverse_url, 152 reverseUrl: data.reverse_url,
153 endpointUrl, 153 endpointUrl,
154 httpStatus: e.response && e.response.status, 154 httpStatus: e.response && e.response.status,
155 responseBody: e.response && e.response.data, 155 responseBody: e.response && e.response.data,
156 }); 156 });
157 157
158 if ((retry || 0) < MAX_RETRY) { 158 if ((retry || 0) < MAX_RETRY) {
159 await sleep(SLEEP_BEFORE_RETRY_MS); 159 await sleep(SLEEP_BEFORE_RETRY_MS);
160 logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, { 160 logger.verbose(`${MODULE_NAME} D8958695: Going to retry sending CORE-CALLBACK TO PARTNER`, {
161 xid, sleepTime: SLEEP_BEFORE_RETRY_MS, 161 xid, sleepTime: SLEEP_BEFORE_RETRY_MS,
162 }); 162 });
163 sender(data, xid, (retry || 0) + 1); 163 sender(data, xid, (retry || 0) + 1);
164 } 164 }
165 } finally { 165 } finally {
166 matrix.callback_sender.active_count -= 1; 166 matrix.callback_sender.active_count -= 1;
167 if (matrix.callback_sender.active_sending[xid]) { 167 if (matrix.callback_sender.active_sending[xid]) {
168 delete matrix.callback_sender.active_sending[xid]; 168 delete matrix.callback_sender.active_sending[xid];
169 } 169 }
170 170
171 dumper( 171 dumper(
172 xid, 172 xid,
173 isHttpPost ? 'POST' : 'GET', 173 isHttpPost ? 'POST' : 'GET',
174 endpointUrl, 174 endpointUrl,
175 params, 175 params,
176 responseToDump, 176 responseToDump,
177 errorResponseToDump, 177 errorResponseToDump,
178 ); 178 );
179 } 179 }
180 }; 180 };
181 181
182 module.exports = sender; 182 module.exports = sender;
183 183
1 const request = require('request'); 1 const request = require('request');
2 2
3 const logger = require('komodo-sdk/logger'); 3 const logger = require('tektrans-logger');
4 const coreUrl = require('komodo-sdk/core-url'); 4 const coreUrl = require('komodo-sdk/core-url');
5 5
6 logger.verbose(`CORE URL: ${coreUrl}`); 6 logger.verbose(`CORE URL: ${coreUrl}`);
7 7
8 function doRequest(params, cb) { 8 function doRequest(params, cb) {
9 return new Promise((resolve) => { 9 return new Promise((resolve) => {
10 const options = { 10 const options = {
11 url: `${coreUrl}/${params.path.replace(/^\/+/, '')}`, 11 url: `${coreUrl}/${params.path.replace(/^\/+/, '')}`,
12 method: params.method || 'GET', 12 method: params.method || 'GET',
13 qs: params.qs || null, 13 qs: params.qs || null,
14 }; 14 };
15 15
16 logger.verbose('Requesting to CORE', { 16 logger.verbose('Requesting to CORE', {
17 xid: params.xid, method: options.method, fullpath: options.url, qs: options.qs, 17 xid: params.xid, method: options.method, fullpath: options.url, qs: options.qs,
18 }); 18 });
19 19
20 request(options, (err, res, body) => { 20 request(options, (err, res, body) => {
21 if (err) { 21 if (err) {
22 logger.warn(`COREAPI: Error doing HTTP ${options.method} to CORE. ${err.toString()}`, { xid: params.xid }); 22 logger.warn(`COREAPI: Error doing HTTP ${options.method} to CORE. ${err.toString()}`, { xid: params.xid });
23 resolve(null); 23 resolve(null);
24 if (typeof cb === 'function') cb(err); 24 if (typeof cb === 'function') cb(err);
25 return; 25 return;
26 } 26 }
27 27
28 if (res.statusCode !== 200) { 28 if (res.statusCode !== 200) {
29 logger.warn(`COREAPI: CORE returning HTTP STATUS CODE ${res.statusCode}, not 200`, { xid: params.xid, body }); 29 logger.warn(`COREAPI: CORE returning HTTP STATUS CODE ${res.statusCode}, not 200`, { xid: params.xid, body });
30 resolve(null); 30 resolve(null);
31 if (typeof cb === 'function') cb('NON_HTTP_STATUS_200'); 31 if (typeof cb === 'function') cb('NON_HTTP_STATUS_200');
32 return; 32 return;
33 } 33 }
34 34
35 let bodyObject; 35 let bodyObject;
36 try { 36 try {
37 bodyObject = JSON.parse(body); 37 bodyObject = JSON.parse(body);
38 } catch (e) { 38 } catch (e) {
39 logger.verbose('COREAPI: CORE respond is not a JSON string'); 39 logger.verbose('COREAPI: CORE respond is not a JSON string');
40 resolve(body); 40 resolve(body);
41 if (typeof cb === 'function') cb(e, body); 41 if (typeof cb === 'function') cb(e, body);
42 return; 42 return;
43 } 43 }
44 44
45 resolve(bodyObject); 45 resolve(bodyObject);
46 if (typeof cb === 'function') cb(null, bodyObject); 46 if (typeof cb === 'function') cb(null, bodyObject);
47 }); 47 });
48 }); 48 });
49 } 49 }
50 50
51 module.exports = doRequest; 51 module.exports = doRequest;
52 52
lib/middlewares/common.js
1 const MODULE_NAME = 'MIDDLEWARES'; 1 const MODULE_NAME = 'MIDDLEWARES';
2 2
3 const uuidv1 = require('uuid/v1'); 3 const uuidv1 = require('uuid/v1');
4 const uniqid = require('uniqid'); 4 const uniqid = require('uniqid');
5 5
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('tektrans-logger');
8 8
9 module.exports = function common(req, res, next) { 9 module.exports = function common(req, res, next) {
10 if (req.url.search('/favicon.ico') === 0) { 10 if (req.url.search('/favicon.ico') === 0) {
11 res.sendStatus(404); 11 res.sendStatus(404);
12 return; 12 return;
13 } 13 }
14 14
15 res.locals.xid = config.xid_from_uuid ? uuidv1() 15 res.locals.xid = config.xid_from_uuid ? uuidv1()
16 : uniqid(); 16 : uniqid();
17 17
18 res.locals.x_http_request_ts = new Date(); 18 res.locals.x_http_request_ts = new Date();
19 19
20 logger.info(`${MODULE_NAME}.COMMON B6257542: Got a request`, { 20 logger.info(`${MODULE_NAME}.COMMON B6257542: Got a request`, {
21 xid: res.locals.xid, 21 xid: res.locals.xid,
22 pid: process.pid, 22 pid: process.pid,
23 subsystem: res.locals.httpgetx_subsystem, 23 subsystem: res.locals.httpgetx_subsystem,
24 requester_ip: req.ip, 24 requester_ip: req.ip,
25 method: req.method, 25 method: req.method,
26 path: req.path, 26 path: req.path,
27 url: req.url, 27 url: req.url,
28 qs: req.query, 28 qs: req.query,
29 body: req.body, 29 body: req.body,
30 }); 30 });
31 next(); 31 next();
32 }; 32 };
33 33
lib/partner-listener/dumper/index.js
1 const MODULE_NAME = 'PARTNER-LISTENER.DUMPER'; 1 const MODULE_NAME = 'PARTNER-LISTENER.DUMPER';
2 2
3 const fsPromise = require('fs').promises; 3 const fsPromise = require('fs').promises;
4 const path = require('path'); 4 const path = require('path');
5 const moment = require('moment'); 5 const moment = require('moment');
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('tektrans-logger');
8 8
9 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists'); 9 const mkdirIfNotExists = require('../../utils/mkdir-if-not-exists');
10 10
11 const baseDumpDir = path.join('dump', 'partner-listener'); 11 const baseDumpDir = path.join('dump', 'partner-listener');
12 const lastDumpFileName = path.join(baseDumpDir, 'last'); 12 const lastDumpFileName = path.join(baseDumpDir, 'last');
13 13
14 module.exports = async (xid, req, responseBody) => { 14 module.exports = async (xid, req, responseBody) => {
15 if ( 15 if (
16 !config 16 !config
17 || !config.listener 17 || !config.listener
18 || !config.listener.partner 18 || !config.listener.partner
19 || !config.listener.partner.dump 19 || !config.listener.partner.dump
20 ) return; 20 ) return;
21 21
22 const data = `-------- 22 const data = `--------
23 XID: ${xid} 23 XID: ${xid}
24 TS: ${moment().format('YYYY-MM-DD HH:mm:ss')} 24 TS: ${moment().format('YYYY-MM-DD HH:mm:ss')}
25 25
26 REQ FROM: ${req.ip} 26 REQ FROM: ${req.ip}
27 REQ CONTENT-TYPE: ${req.get('content-type')} 27 REQ CONTENT-TYPE: ${req.get('content-type')}
28 REQ METHOD: ${req.method} 28 REQ METHOD: ${req.method}
29 REQ URL: ${req.url} 29 REQ URL: ${req.url}
30 30
31 REQ QUERY-STRING: 31 REQ QUERY-STRING:
32 ${JSON.stringify(req.query, null, 2)} 32 ${JSON.stringify(req.query, null, 2)}
33 33
34 REQ BODY: 34 REQ BODY:
35 ${typeof req.body === 'string' ? req.body : JSON.stringify(req.body, null, 2)} 35 ${typeof req.body === 'string' ? req.body : JSON.stringify(req.body, null, 2)}
36 36
37 RES BODY: 37 RES BODY:
38 ${typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody, null, 2)} 38 ${typeof responseBody === 'string' ? responseBody : JSON.stringify(responseBody, null, 2)}
39 `; 39 `;
40 40
41 const dumpFileName = path.join( 41 const dumpFileName = path.join(
42 baseDumpDir, 42 baseDumpDir,
43 moment().format('YYYY-MM-DD'), 43 moment().format('YYYY-MM-DD'),
44 [ 44 [
45 moment().format('YYMMDD_HHmmss_SSS'), 45 moment().format('YYMMDD_HHmmss_SSS'),
46 xid, 46 xid,
47 ].join('_'), 47 ].join('_'),
48 ); 48 );
49 49
50 try { 50 try {
51 await mkdirIfNotExists(xid, path.dirname(dumpFileName), MODULE_NAME); 51 await mkdirIfNotExists(xid, path.dirname(dumpFileName), MODULE_NAME);
52 await fsPromise.writeFile(lastDumpFileName, data); 52 await fsPromise.writeFile(lastDumpFileName, data);
53 await fsPromise.writeFile(dumpFileName, data); 53 await fsPromise.writeFile(dumpFileName, data);
54 } catch (e) { 54 } catch (e) {
55 logger.warn(`${MODULE_NAME} FBC46420: Exception on dumping file`, { 55 logger.warn(`${MODULE_NAME} FBC46420: Exception on dumping file`, {
56 xid, 56 xid,
57 eCode: e.code, 57 eCode: e.code,
58 eMessage: e.eMessage, 58 eMessage: e.eMessage,
59 }); 59 });
60 } 60 }
61 }; 61 };
62 62
lib/partner-listener/index.js
1 const MODULE_NAME = 'PARTNER-LISTENER'; 1 const MODULE_NAME = 'PARTNER-LISTENER';
2 2
3 const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614; 3 const DEFAULT_LISTENER_FROM_PARTNER_PORT = 25614;
4 4
5 const express = require('express'); 5 const express = require('express');
6 6
7 const config = require('komodo-sdk/config'); 7 const config = require('komodo-sdk/config');
8 const logger = require('komodo-sdk/logger'); 8 const logger = require('tektrans-logger');
9 9
10 const middlewareCommon = require('../middlewares/common'); 10 const middlewareCommon = require('../middlewares/common');
11 11
12 const routerInquiry = require('./routers/inquiry'); 12 const routerInquiry = require('./routers/inquiry');
13 const routerPay = require('./routers/pay'); 13 const routerPay = require('./routers/pay');
14 const routerTopup = require('./routers/topup'); 14 const routerTopup = require('./routers/topup');
15 const routerTrxStatus = require('./routers/trx-status'); 15 const routerTrxStatus = require('./routers/trx-status');
16 16
17 const app = express(); 17 const app = express();
18 18
19 if (config.partner && config.partner.trust_proxy) { 19 if (config.partner && config.partner.trust_proxy) {
20 app.set('trust proxy', config.partner.trust_proxy); 20 app.set('trust proxy', config.partner.trust_proxy);
21 } 21 }
22 22
23 app.use((req, res, next) => { 23 app.use((req, res, next) => {
24 res.locals.httpgetx_subsystem = MODULE_NAME; 24 res.locals.httpgetx_subsystem = MODULE_NAME;
25 next(); 25 next();
26 }); 26 });
27 27
28 app.use(express.json({ extended: true })); 28 app.use(express.json({ extended: true }));
29 app.use(express.urlencoded({ extended: true })); 29 app.use(express.urlencoded({ extended: true }));
30 app.use(middlewareCommon); 30 app.use(middlewareCommon);
31 31
32 app.use('/ping', (req, res) => { 32 app.use('/ping', (req, res) => {
33 res.json({ 33 res.json({
34 error: false, 34 error: false,
35 xid: res.locals.xid, 35 xid: res.locals.xid,
36 from_ip: req.ip, 36 from_ip: req.ip,
37 ts: new Date(), 37 ts: new Date(),
38 request: { 38 request: {
39 method: req.method, 39 method: req.method,
40 userAgent: req.get('user-agent'), 40 userAgent: req.get('user-agent'),
41 contentType: req.get('content-type'), 41 contentType: req.get('content-type'),
42 qs: req.query, 42 qs: req.query,
43 body: req.body, 43 body: req.body,
44 }, 44 },
45 }); 45 });
46 }); 46 });
47 app.use('/inquiry', routerInquiry); 47 app.use('/inquiry', routerInquiry);
48 app.use('/pay', routerPay); 48 app.use('/pay', routerPay);
49 app.use('/topup', routerTopup); 49 app.use('/topup', routerTopup);
50 app.use('/trx-status', routerTrxStatus); 50 app.use('/trx-status', routerTrxStatus);
51 app.use('/', routerTopup); 51 app.use('/', routerTopup);
52 52
53 app.use((req, res) => { 53 app.use((req, res) => {
54 const { xid } = res.locals; 54 const { xid } = res.locals;
55 res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`); 55 res.status(404).end(`KOMODO-HTTP-GET-X CENTER.\n404: Method not found.\n\nXID: ${xid}.\n`);
56 }); 56 });
57 57
58 app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => { 58 app.listen(config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT, () => {
59 logger.info(`Listen from partner request on port ${config.listener.partner.port}`); 59 logger.info(`Listen from partner request on port ${config.listener.partner.port}`);
60 }).on('error', (e) => { 60 }).on('error', (e) => {
61 logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`); 61 logger.error(`Can not listen request from partner on port ${config.listener.partner.port || DEFAULT_LISTENER_FROM_PARTNER_PORT}. ${e.toString()}`);
62 process.exit(1); 62 process.exit(1);
63 }); 63 });
64 64
lib/partner-listener/routers/inquiry.js
1 const axios = require('axios').default; 1 const axios = require('axios').default;
2 const express = require('express'); 2 const express = require('express');
3 const coreUrl = require('komodo-sdk/core-url'); 3 const coreUrl = require('komodo-sdk/core-url');
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('tektrans-logger');
7 7
8 const getFromBodyQsParams = require('../../get-from-body-qs-params'); 8 const getFromBodyQsParams = require('../../get-from-body-qs-params');
9 const ipv6ToIpv4 = require('../../ipv6-to-ipv4'); 9 const ipv6ToIpv4 = require('../../ipv6-to-ipv4');
10 const dumper = require('../dumper'); 10 const dumper = require('../dumper');
11 11
12 const router = express.Router(); 12 const router = express.Router();
13 module.exports = router; 13 module.exports = router;
14 14
15 const CORE_ENDPOINT = `${coreUrl}/postpaid2/inquiry`; 15 const CORE_ENDPOINT = `${coreUrl}/postpaid2/inquiry`;
16 16
17 const mainHandler = async (req, res) => { 17 const mainHandler = async (req, res) => {
18 const { xid } = res.locals; 18 const { xid } = res.locals;
19 19
20 const requestId = (getFromBodyQsParams(req, 'request_id') || '').toString().trim(); 20 const requestId = (getFromBodyQsParams(req, 'request_id') || '').toString().trim();
21 const terminalNameWithoutIp = (getFromBodyQsParams(req, 'terminal_name') || '').toString().trim(); 21 const terminalNameWithoutIp = (getFromBodyQsParams(req, 'terminal_name') || '').toString().trim();
22 const terminalName = `${terminalNameWithoutIp}@${ipv6ToIpv4(req.ip)}`; 22 const terminalName = `${terminalNameWithoutIp}@${ipv6ToIpv4(req.ip)}`;
23 const productName = (getFromBodyQsParams(req, 'product_name') || '').trim().toUpperCase(); 23 const productName = (getFromBodyQsParams(req, 'product_name') || '').trim().toUpperCase();
24 const destination = (getFromBodyQsParams(req, 'destination') || '').toString().trim(); 24 const destination = (getFromBodyQsParams(req, 'destination') || '').toString().trim();
25 const password = getFromBodyQsParams(req, 'password'); 25 const password = getFromBodyQsParams(req, 'password');
26 const reverseUrl = getFromBodyQsParams(req, 'reverse_url'); 26 const reverseUrl = getFromBodyQsParams(req, 'reverse_url');
27 27
28 if (!requestId || !terminalNameWithoutIp || !productName || !destination) { 28 if (!requestId || !terminalNameWithoutIp || !productName || !destination) {
29 const msg = 'INVALID REQUEST. Missing request_id or terminal_name or product_name or destination.'; 29 const msg = 'INVALID REQUEST. Missing request_id or terminal_name or product_name or destination.';
30 res.end(msg); 30 res.end(msg);
31 31
32 dumper(xid, req, msg); 32 dumper(xid, req, msg);
33 return; 33 return;
34 } 34 }
35 35
36 const params = { 36 const params = {
37 origin: config.name, 37 origin: config.name,
38 report_ip: config.listener.core.from_ip, 38 report_ip: config.listener.core.from_ip,
39 report_port: config.listener.core.port || 25614, 39 report_port: config.listener.core.port || 25614,
40 request_id: requestId, 40 request_id: requestId,
41 terminal_name: terminalName, 41 terminal_name: terminalName,
42 product_name: productName, 42 product_name: productName,
43 destination, 43 destination,
44 terminal_password: password, 44 terminal_password: password,
45 reverse_url: reverseUrl, 45 reverse_url: reverseUrl,
46 }; 46 };
47 47
48 logger.info('Forwarding INQUIRY request to CORE', { xid, params }); 48 logger.info('Forwarding INQUIRY request to CORE', { xid, params });
49 try { 49 try {
50 const result = await axios.get(CORE_ENDPOINT, { 50 const result = await axios.get(CORE_ENDPOINT, {
51 params, 51 params,
52 timeout: 10000, 52 timeout: 10000,
53 }); 53 });
54 54
55 if (!result || !result.data) { 55 if (!result || !result.data) {
56 const newError = new Error('8002EB0D: Empty CORE INQUIRY direct-response'); 56 const newError = new Error('8002EB0D: Empty CORE INQUIRY direct-response');
57 logger.warn(newError.message, { xid }); 57 logger.warn(newError.message, { xid });
58 throw newError; 58 throw newError;
59 } 59 }
60 60
61 logger.verbose('Got INQUIRY direct-response from CORE', { 61 logger.verbose('Got INQUIRY direct-response from CORE', {
62 xid, 62 xid,
63 coreResponse: result.data, 63 coreResponse: result.data,
64 }); 64 });
65 65
66 const resultForPartner = { 66 const resultForPartner = {
67 httpgetx_xid: xid, 67 httpgetx_xid: xid,
68 command: result.data.command, 68 command: result.data.command,
69 request_id: result.data.request_id && result.data.request_id.toString(), 69 request_id: result.data.request_id && result.data.request_id.toString(),
70 transaction_id: result.data.transaction_id && result.data.transaction_id.toString(), 70 transaction_id: result.data.transaction_id && result.data.transaction_id.toString(),
71 transaction_date: result.data.transaction_date, 71 transaction_date: result.data.transaction_date,
72 store_name: result.data.store_name, 72 store_name: result.data.store_name,
73 terminal_name: result.data.terminal_name, 73 terminal_name: result.data.terminal_name,
74 product_name: result.data.product_name, 74 product_name: result.data.product_name,
75 destination: result.data.destination, 75 destination: result.data.destination,
76 rc: result.data.rc, 76 rc: result.data.rc,
77 sn: result.data.sn, 77 sn: result.data.sn,
78 message: result.data.message, 78 message: result.data.message,
79 amount: result.data.amount, 79 amount: result.data.amount,
80 ending_balance: result.data.ending_balance, 80 ending_balance: result.data.ending_balance,
81 amount_to_charge: result.data.amount_to_charge, 81 amount_to_charge: result.data.amount_to_charge,
82 }; 82 };
83 83
84 logger.verbose('Forwarding CORE direct-response to partner', { 84 logger.verbose('Forwarding CORE direct-response to partner', {
85 xid, 85 xid,
86 resultForPartner, 86 resultForPartner,
87 }); 87 });
88 88
89 res.json(resultForPartner); 89 res.json(resultForPartner);
90 90
91 dumper(xid, req, resultForPartner); 91 dumper(xid, req, resultForPartner);
92 } catch (e) { 92 } catch (e) {
93 logger.warn('EXCEPTION on forwarding INQUIRY request to CORE', { 93 logger.warn('EXCEPTION on forwarding INQUIRY request to CORE', {
94 xid, 94 xid,
95 errCode: e.code, 95 errCode: e.code,
96 errMessage: e.message, 96 errMessage: e.message,
97 }); 97 });
98 98
99 const resultForPartner = { 99 const resultForPartner = {
100 httpgetx_xid: xid, 100 httpgetx_xid: xid,
101 command: 'INQUIRY', 101 command: 'INQUIRY',
102 request_id: requestId, 102 request_id: requestId,
103 terminal_name: terminalName, 103 terminal_name: terminalName,
104 product_name: productName, 104 product_name: productName,
105 destination, 105 destination,
106 rc: '68', 106 rc: '68',
107 message: 'CORE tidak merespon dengan benar, tidak dapat mengetahui status request anda', 107 message: 'CORE tidak merespon dengan benar, tidak dapat mengetahui status request anda',
108 }; 108 };
109 109
110 res.json(resultForPartner); 110 res.json(resultForPartner);
111 dumper(xid, req, resultForPartner); 111 dumper(xid, req, resultForPartner);
112 } 112 }
113 }; 113 };
114 114
115 router.all('/', mainHandler); 115 router.all('/', mainHandler);
116 116
lib/partner-listener/routers/pay.js
1 const axios = require('axios').default; 1 const axios = require('axios').default;
2 const express = require('express'); 2 const express = require('express');
3 const coreUrl = require('komodo-sdk/core-url'); 3 const coreUrl = require('komodo-sdk/core-url');
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('tektrans-logger');
7 7
8 const getFromBodyQsParams = require('../../get-from-body-qs-params'); 8 const getFromBodyQsParams = require('../../get-from-body-qs-params');
9 const ipv6ToIpv4 = require('../../ipv6-to-ipv4'); 9 const ipv6ToIpv4 = require('../../ipv6-to-ipv4');
10 const dumper = require('../dumper'); 10 const dumper = require('../dumper');
11 11
12 const router = express.Router(); 12 const router = express.Router();
13 module.exports = router; 13 module.exports = router;
14 14
15 const CORE_ENDPOINT = `${coreUrl}/postpaid2/pay`; 15 const CORE_ENDPOINT = `${coreUrl}/postpaid2/pay`;
16 16
17 const mainHandler = async (req, res) => { 17 const mainHandler = async (req, res) => {
18 const { xid } = res.locals; 18 const { xid } = res.locals;
19 19
20 const requestId = (getFromBodyQsParams(req, 'request_id') || '').toString().trim(); 20 const requestId = (getFromBodyQsParams(req, 'request_id') || '').toString().trim();
21 const terminalNameWithoutIp = (getFromBodyQsParams(req, 'terminal_name') || '').toString().trim(); 21 const terminalNameWithoutIp = (getFromBodyQsParams(req, 'terminal_name') || '').toString().trim();
22 const terminalName = `${terminalNameWithoutIp}@${ipv6ToIpv4(req.ip)}`; 22 const terminalName = `${terminalNameWithoutIp}@${ipv6ToIpv4(req.ip)}`;
23 const productName = (getFromBodyQsParams(req, 'product_name') || '').trim().toUpperCase(); 23 const productName = (getFromBodyQsParams(req, 'product_name') || '').trim().toUpperCase();
24 const destination = (getFromBodyQsParams(req, 'destination') || '').toString().trim(); 24 const destination = (getFromBodyQsParams(req, 'destination') || '').toString().trim();
25 const password = getFromBodyQsParams(req, 'password'); 25 const password = getFromBodyQsParams(req, 'password');
26 const reverseUrl = getFromBodyQsParams(req, 'reverse_url'); 26 const reverseUrl = getFromBodyQsParams(req, 'reverse_url');
27 27
28 if (!requestId || !terminalNameWithoutIp || !productName || !destination) { 28 if (!requestId || !terminalNameWithoutIp || !productName || !destination) {
29 const msg = 'INVALID REQUEST. Missing request_id or terminal_name or product_name or destination.'; 29 const msg = 'INVALID REQUEST. Missing request_id or terminal_name or product_name or destination.';
30 res.end(msg); 30 res.end(msg);
31 dumper(xid, req, msg); 31 dumper(xid, req, msg);
32 return; 32 return;
33 } 33 }
34 34
35 const params = { 35 const params = {
36 origin: config.name, 36 origin: config.name,
37 report_ip: config.listener.core.from_ip, 37 report_ip: config.listener.core.from_ip,
38 report_port: config.listener.core.port || 25614, 38 report_port: config.listener.core.port || 25614,
39 request_id: requestId, 39 request_id: requestId,
40 terminal_name: terminalName, 40 terminal_name: terminalName,
41 product_name: productName, 41 product_name: productName,
42 destination, 42 destination,
43 terminal_password: password, 43 terminal_password: password,
44 reverse_url: reverseUrl, 44 reverse_url: reverseUrl,
45 }; 45 };
46 46
47 logger.info('Forwarding PAY request to CORE', { xid, params }); 47 logger.info('Forwarding PAY request to CORE', { xid, params });
48 try { 48 try {
49 const result = await axios.get(CORE_ENDPOINT, { 49 const result = await axios.get(CORE_ENDPOINT, {
50 params, 50 params,
51 timeout: 10000, 51 timeout: 10000,
52 }); 52 });
53 53
54 if (!result || !result.data) { 54 if (!result || !result.data) {
55 const newError = new Error('0D428E4C: Empty CORE PAY direct-response'); 55 const newError = new Error('0D428E4C: Empty CORE PAY direct-response');
56 logger.warn(newError.message, { xid }); 56 logger.warn(newError.message, { xid });
57 throw newError; 57 throw newError;
58 } 58 }
59 59
60 logger.verbose('Got PAY direct-response from CORE', { 60 logger.verbose('Got PAY direct-response from CORE', {
61 xid, 61 xid,
62 coreResponse: result.data, 62 coreResponse: result.data,
63 }); 63 });
64 64
65 const resultForPartner = { 65 const resultForPartner = {
66 httpgetx_xid: xid, 66 httpgetx_xid: xid,
67 command: result.data.command, 67 command: result.data.command,
68 request_id: result.data.request_id && result.data.request_id.toString(), 68 request_id: result.data.request_id && result.data.request_id.toString(),
69 transaction_id: result.data.transaction_id && result.data.transaction_id.toString(), 69 transaction_id: result.data.transaction_id && result.data.transaction_id.toString(),
70 transaction_date: result.data.transaction_date, 70 transaction_date: result.data.transaction_date,
71 store_name: result.data.store_name, 71 store_name: result.data.store_name,
72 terminal_name: result.data.terminal_name, 72 terminal_name: result.data.terminal_name,
73 product_name: result.data.product_name, 73 product_name: result.data.product_name,
74 destination: result.data.destination, 74 destination: result.data.destination,
75 rc: result.data.rc, 75 rc: result.data.rc,
76 sn: result.data.sn, 76 sn: result.data.sn,
77 message: result.data.message, 77 message: result.data.message,
78 amount: result.data.amount, 78 amount: result.data.amount,
79 ending_balance: result.data.ending_balance, 79 ending_balance: result.data.ending_balance,
80 }; 80 };
81 81
82 logger.verbose('Forwarding CORE PAY direct-response to partner', { 82 logger.verbose('Forwarding CORE PAY direct-response to partner', {
83 xid, 83 xid,
84 resultForPartner, 84 resultForPartner,
85 }); 85 });
86 86
87 res.json(resultForPartner); 87 res.json(resultForPartner);
88 dumper(xid, req, resultForPartner); 88 dumper(xid, req, resultForPartner);
89 } catch (e) { 89 } catch (e) {
90 logger.warn('EXCEPTION on forwarding PAY request to CORE', { 90 logger.warn('EXCEPTION on forwarding PAY request to CORE', {
91 xid, 91 xid,
92 errCode: e.code, 92 errCode: e.code,
93 errMessage: e.message, 93 errMessage: e.message,
94 }); 94 });
95 95
96 const resultForPartner = { 96 const resultForPartner = {
97 httpgetx_xid: xid, 97 httpgetx_xid: xid,
98 command: 'PAY', 98 command: 'PAY',
99 request_id: requestId, 99 request_id: requestId,
100 terminal_name: terminalName, 100 terminal_name: terminalName,
101 product_name: productName, 101 product_name: productName,
102 destination, 102 destination,
103 rc: '68', 103 rc: '68',
104 message: 'CORE tidak merespon dengan benar, tidak dapat mengetahui status request anda', 104 message: 'CORE tidak merespon dengan benar, tidak dapat mengetahui status request anda',
105 }; 105 };
106 106
107 dumper(xid, req, resultForPartner); 107 dumper(xid, req, resultForPartner);
108 } 108 }
109 }; 109 };
110 110
111 router.all('/', mainHandler); 111 router.all('/', mainHandler);
112 112
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('tektrans-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 const matrix = require('../../matrix');
10 const dumper = require('../dumper'); 10 const dumper = require('../dumper');
11 11
12 const router = express.Router(); 12 const router = express.Router();
13 module.exports = router; 13 module.exports = router;
14 14
15 function onInvalidParameter(missingParameter, req, res) { 15 function onInvalidParameter(missingParameter, req, res) {
16 logger.verbose(`${MODULE_NAME} 1536D577: Undefined ${missingParameter} parameter`, { 16 logger.verbose(`${MODULE_NAME} 1536D577: Undefined ${missingParameter} parameter`, {
17 xid: res.locals.xid, 17 xid: res.locals.xid,
18 ip: req.ip, 18 ip: req.ip,
19 terminal_name: req.body.terminal_name || req.query.terminal_name, 19 terminal_name: req.body.terminal_name || req.query.terminal_name,
20 request_id: req.body.request_id || req.query.request_id, 20 request_id: req.body.request_id || req.query.request_id,
21 product_name: req.body.product_name || req.query.product_name, 21 product_name: req.body.product_name || req.query.product_name,
22 destination: req.body.destination || req.query.destination, 22 destination: req.body.destination || req.query.destination,
23 }); 23 });
24 res.end('INVALID REQUEST'); 24 res.end('INVALID REQUEST');
25 } 25 }
26 26
27 function pagePrerequisite(req, res, next) { 27 function pagePrerequisite(req, res, next) {
28 if (!req.body) req.body = {}; 28 if (!req.body) req.body = {};
29 29
30 if (!req.body.terminal_name && !req.query.terminal_name) { 30 if (!req.body.terminal_name && !req.query.terminal_name) {
31 onInvalidParameter('terminal_name', req, res); 31 onInvalidParameter('terminal_name', req, res);
32 return; 32 return;
33 } 33 }
34 34
35 if (!req.body.password && !req.query.password) { 35 if (!req.body.password && !req.query.password) {
36 onInvalidParameter('password', req, res); 36 onInvalidParameter('password', req, res);
37 return; 37 return;
38 } 38 }
39 39
40 if (!req.body.request_id && !req.query.request_id) { 40 if (!req.body.request_id && !req.query.request_id) {
41 onInvalidParameter('request_id', req, res); 41 onInvalidParameter('request_id', req, res);
42 return; 42 return;
43 } 43 }
44 44
45 if (!req.body.product_name && !req.query.product_name) { 45 if (!req.body.product_name && !req.query.product_name) {
46 onInvalidParameter('product_name', req, res); 46 onInvalidParameter('product_name', req, res);
47 return; 47 return;
48 } 48 }
49 49
50 if (!req.body.destination && !req.query.destination) { 50 if (!req.body.destination && !req.query.destination) {
51 onInvalidParameter('destination', req, res); 51 onInvalidParameter('destination', req, res);
52 return; 52 return;
53 } 53 }
54 54
55 next(); 55 next();
56 } 56 }
57 57
58 async function pageIndex(req, res) { 58 async function pageIndex(req, res) {
59 const { xid } = res.locals; 59 const { xid } = res.locals;
60 60
61 const terminalName = `${req.body.terminal_name || req.query.terminal_name}@${req.ip.replace(/^::ffff:/, '')}`; 61 const terminalName = `${req.body.terminal_name || req.query.terminal_name}@${req.ip.replace(/^::ffff:/, '')}`;
62 62
63 matrix.core.sent += 1; 63 matrix.core.sent += 1;
64 64
65 const [err, coreResponse] = await coreapi({ 65 const [err, coreResponse] = await coreapi({
66 xid, 66 xid,
67 path: '/prepaid/buy', 67 path: '/prepaid/buy',
68 qs: { 68 qs: {
69 terminal_name: terminalName, 69 terminal_name: terminalName,
70 password: req.body.password || req.query.password, 70 password: req.body.password || req.query.password,
71 request_id: req.body.request_id || req.query.request_id, 71 request_id: req.body.request_id || req.query.request_id,
72 product_name: req.body.product_name || req.query.product_name, 72 product_name: req.body.product_name || req.query.product_name,
73 destination: req.body.destination || req.query.destination, 73 destination: req.body.destination || req.query.destination,
74 origin: config.name || 'HTTPGETX', 74 origin: config.name || 'HTTPGETX',
75 report_ip: config.listener.core.ip || null, 75 report_ip: config.listener.core.ip || null,
76 report_port: config.listener.core.port, 76 report_port: config.listener.core.port,
77 reverse_url: req.body.reverse_url || req.query.reverse_url || null, 77 reverse_url: req.body.reverse_url || req.query.reverse_url || null,
78 }, 78 },
79 }); 79 });
80 80
81 if (err || !coreResponse) { 81 if (err || !coreResponse) {
82 matrix.core.sent_failed += 1; 82 matrix.core.sent_failed += 1;
83 matrix.core.last_error = { 83 matrix.core.last_error = {
84 xid, 84 xid,
85 ts: new Date(), 85 ts: new Date(),
86 e: err, 86 e: err,
87 eCode: err.code, 87 eCode: err.code,
88 eMessage: err.message, 88 eMessage: err.message,
89 }; 89 };
90 90
91 logger.warn(`${MODULE_NAME} 8DEBE15F: ERROR on /prepaid/buy response`, { 91 logger.warn(`${MODULE_NAME} 8DEBE15F: ERROR on /prepaid/buy response`, {
92 xid, 92 xid,
93 err, 93 err,
94 coreResponseTypeof: typeof coreResponse, 94 coreResponseTypeof: typeof coreResponse,
95 coreResponse, 95 coreResponse,
96 }); 96 });
97 res.end('INVALID CORE RESPONSE'); 97 res.end('INVALID CORE RESPONSE');
98 98
99 dumper(xid, req, 'INVALID CORE RESPONSE'); 99 dumper(xid, req, 'INVALID CORE RESPONSE');
100 return; 100 return;
101 } 101 }
102 102
103 logger.verbose(`${MODULE_NAME} 2528A9B4: Got CORE response`, { 103 logger.verbose(`${MODULE_NAME} 2528A9B4: Got CORE response`, {
104 xid, 104 xid,
105 coreResponse, 105 coreResponse,
106 }); 106 });
107 107
108 const responseToPartner = { 108 const responseToPartner = {
109 httpgetx_xid: xid, 109 httpgetx_xid: xid,
110 request_id: coreResponse.request_id, 110 request_id: coreResponse.request_id,
111 transaction_id: coreResponse.transaction_id, 111 transaction_id: coreResponse.transaction_id,
112 transaction_date: coreResponse.transaction_date, 112 transaction_date: coreResponse.transaction_date,
113 store_name: coreResponse.store_name, 113 store_name: coreResponse.store_name,
114 terminal_name: coreResponse.terminal_name, 114 terminal_name: coreResponse.terminal_name,
115 product_name: coreResponse.product_name, 115 product_name: coreResponse.product_name,
116 destination: coreResponse.destination, 116 destination: coreResponse.destination,
117 rc: coreResponse.rc, 117 rc: coreResponse.rc,
118 sn: coreResponse.sn || undefined, 118 sn: coreResponse.sn || undefined,
119 amount: Number(coreResponse.amount) || undefined, 119 amount: Number(coreResponse.amount) || undefined,
120 ending_balance: Number(coreResponse.ending_balance) || undefined, 120 ending_balance: Number(coreResponse.ending_balance) || undefined,
121 message: coreResponse.message, 121 message: coreResponse.message,
122 }; 122 };
123 123
124 res.json(responseToPartner); 124 res.json(responseToPartner);
125 dumper(xid, req, responseToPartner); 125 dumper(xid, req, responseToPartner);
126 } 126 }
127 127
128 // router.all('/', (req, res) => { res.status(404).end('404: Not implemented yet'); }); 128 // router.all('/', (req, res) => { res.status(404).end('404: Not implemented yet'); });
129 router.get('/', pagePrerequisite, pageIndex); 129 router.get('/', pagePrerequisite, pageIndex);
130 130
lib/partner-listener/routers/trx-status.js
1 const MODULE_NAME = 'PARTNER-LISTENER.ROUTERS.TRX-STATUS'; 1 const MODULE_NAME = 'PARTNER-LISTENER.ROUTERS.TRX-STATUS';
2 2
3 const express = require('express'); 3 const express = require('express');
4 const moment = require('moment'); 4 const moment = require('moment');
5 5
6 const logger = require('komodo-sdk/logger'); 6 const logger = require('tektrans-logger');
7 7
8 const coreapi = require('../../coreapi'); 8 const coreapi = require('../../coreapi');
9 const dumper = require('../dumper'); 9 const dumper = require('../dumper');
10 10
11 const router = express.Router(); 11 const router = express.Router();
12 module.exports = router; 12 module.exports = router;
13 13
14 async function pageIndex(req, res) { 14 async function pageIndex(req, res) {
15 const { xid } = res.locals; 15 const { xid } = res.locals;
16 if (!req.body) req.body = {}; 16 if (!req.body) req.body = {};
17 17
18 if (!req.body.terminal_name && !req.query.terminal_name) { 18 if (!req.body.terminal_name && !req.query.terminal_name) {
19 const msg = 'Parameter terminal_name tidak terdefinisi'; 19 const msg = 'Parameter terminal_name tidak terdefinisi';
20 res.json({ 20 res.json({
21 httpgetx_xid: xid, 21 httpgetx_xid: xid,
22 error: true, 22 error: true,
23 message: msg, 23 message: msg,
24 }); 24 });
25 25
26 dumper(xid, req, msg); 26 dumper(xid, req, msg);
27 return; 27 return;
28 } 28 }
29 29
30 if (!req.body.password && !req.query.password) { 30 if (!req.body.password && !req.query.password) {
31 const msg = 'Parameter password tidak terdefinisi'; 31 const msg = 'Parameter password tidak terdefinisi';
32 res.json({ 32 res.json({
33 httpgetx_xid: xid, 33 httpgetx_xid: xid,
34 error: true, 34 error: true,
35 message: msg, 35 message: msg,
36 }); 36 });
37 37
38 dumper(xid, req, msg); 38 dumper(xid, req, msg);
39 return; 39 return;
40 } 40 }
41 41
42 if (!req.body.request_id && !req.query.request_id) { 42 if (!req.body.request_id && !req.query.request_id) {
43 const msg = 'Parameter request_id tidak terdefinisi'; 43 const msg = 'Parameter request_id tidak terdefinisi';
44 res.json({ 44 res.json({
45 httpgetx_xid: xid, 45 httpgetx_xid: xid,
46 error: true, 46 error: true,
47 message: msg, 47 message: msg,
48 }); 48 });
49 49
50 dumper(xid, req, msg); 50 dumper(xid, req, msg);
51 return; 51 return;
52 } 52 }
53 53
54 const remoteIp = req.ip.replace(/^::ffff:/, ''); 54 const remoteIp = req.ip.replace(/^::ffff:/, '');
55 const askerTerminalName = `${req.body.terminal_name || req.query.terminal_name}@${remoteIp}`; 55 const askerTerminalName = `${req.body.terminal_name || req.query.terminal_name}@${remoteIp}`;
56 56
57 const coreResponse = await coreapi({ 57 const coreResponse = await coreapi({
58 xid, 58 xid,
59 path: '/trx-status/view', 59 path: '/trx-status/view',
60 qs: { 60 qs: {
61 asker_terminal_name: askerTerminalName, 61 asker_terminal_name: askerTerminalName,
62 asker_terminal_password: req.body.password || req.query.password, 62 asker_terminal_password: req.body.password || req.query.password,
63 request_id: req.body.request_id || req.query.request_id, 63 request_id: req.body.request_id || req.query.request_id,
64 }, 64 },
65 }); 65 });
66 66
67 if (!coreResponse || !coreResponse.status) { 67 if (!coreResponse || !coreResponse.status) {
68 const msg = 'Status transaksi tidak dapat diketahui karena suatu kesalahan pada sistem'; 68 const msg = 'Status transaksi tidak dapat diketahui karena suatu kesalahan pada sistem';
69 69
70 logger.warn(`${MODULE_NAME} 9983DB34: ${msg}`, { 70 logger.warn(`${MODULE_NAME} 9983DB34: ${msg}`, {
71 xid, 71 xid,
72 ip: req.ip, 72 ip: req.ip,
73 terminal_name: req.body.terminal_name || req.query.terminal_name, 73 terminal_name: req.body.terminal_name || req.query.terminal_name,
74 request_id: req.body.request_id || req.query.request_id, 74 request_id: req.body.request_id || req.query.request_id,
75 }); 75 });
76 76
77 const responseBody = { 77 const responseBody = {
78 httpgetx_xid: xid, 78 httpgetx_xid: xid,
79 error: true, 79 error: true,
80 from_ip: remoteIp, 80 from_ip: remoteIp,
81 terminal_name: req.body.terminal_name || req.query.terminal_name, 81 terminal_name: req.body.terminal_name || req.query.terminal_name,
82 full_terminal_name: askerTerminalName, 82 full_terminal_name: askerTerminalName,
83 password: req.body.password || req.query.password, 83 password: req.body.password || req.query.password,
84 message: msg, 84 message: msg,
85 }; 85 };
86 86
87 res.json(responseBody); 87 res.json(responseBody);
88 dumper(xid, req, responseBody); 88 dumper(xid, req, responseBody);
89 89
90 return; 90 return;
91 } 91 }
92 92
93 const trx = coreResponse && coreResponse.result ? { 93 const trx = coreResponse && coreResponse.result ? {
94 id: coreResponse.result.id, 94 id: coreResponse.result.id,
95 request_id: coreResponse.result.request_id, 95 request_id: coreResponse.result.request_id,
96 store_id: coreResponse.result.store_id, 96 store_id: coreResponse.result.store_id,
97 store_name: coreResponse.result.store_name, 97 store_name: coreResponse.result.store_name,
98 terminal_id: coreResponse.result.terminal_id, 98 terminal_id: coreResponse.result.terminal_id,
99 terminal_name: coreResponse.result.terminal_name, 99 terminal_name: coreResponse.result.terminal_name,
100 100
101 created: moment(coreResponse.result.created).format('YYYY-MM-DD HH:mm:ss'), 101 created: moment(coreResponse.result.created).format('YYYY-MM-DD HH:mm:ss'),
102 modified: moment(coreResponse.result.modified).format('YYYY-MM-DD HH:mm:ss'), 102 modified: moment(coreResponse.result.modified).format('YYYY-MM-DD HH:mm:ss'),
103 103
104 product_name: coreResponse.result.product_name, 104 product_name: coreResponse.result.product_name,
105 destination: coreResponse.result.destination, 105 destination: coreResponse.result.destination,
106 amount: coreResponse.result.amount, 106 amount: coreResponse.result.amount,
107 ending_balance: coreResponse.result.ending_balance, 107 ending_balance: coreResponse.result.ending_balance,
108 rc: coreResponse.result.rc, 108 rc: coreResponse.result.rc,
109 message: coreResponse.result.reply_message, 109 message: coreResponse.result.reply_message,
110 sn: coreResponse.result.sn, 110 sn: coreResponse.result.sn,
111 } 111 }
112 : null; 112 : null;
113 113
114 const result = { 114 const result = {
115 httpgetx_xid: xid, 115 httpgetx_xid: xid,
116 error: coreResponse.status !== 'OK', 116 error: coreResponse.status !== 'OK',
117 from_ip: remoteIp, 117 from_ip: remoteIp,
118 terminal_name: req.body.terminal_name || req.query.terminal_name, 118 terminal_name: req.body.terminal_name || req.query.terminal_name,
119 full_terminal_name: askerTerminalName, 119 full_terminal_name: askerTerminalName,
120 message: coreResponse.message, 120 message: coreResponse.message,
121 trx_found: !!trx, 121 trx_found: !!trx,
122 trx, 122 trx,
123 // original_trx: coreResponse.result, 123 // original_trx: coreResponse.result,
124 }; 124 };
125 125
126 res.json(result); 126 res.json(result);
127 127
128 logger.info(`${MODULE_NAME} 480C4BB0: Partner request responded`, { 128 logger.info(`${MODULE_NAME} 480C4BB0: Partner request responded`, {
129 xid, 129 xid,
130 processing_time_in_ms: new Date() - res.locals.x_http_request_ts, 130 processing_time_in_ms: new Date() - res.locals.x_http_request_ts,
131 result, 131 result,
132 }); 132 });
133 133
134 dumper(xid, req, result); 134 dumper(xid, req, result);
135 } 135 }
136 136
137 router.get('/', pageIndex); 137 router.get('/', pageIndex);
138 138
lib/utils/mkdir-if-not-exists.js
1 const MODULE_NAME = 'MKDIR-IF-NOT-EXISTS'; 1 const MODULE_NAME = 'MKDIR-IF-NOT-EXISTS';
2 2
3 const fsPromise = require('fs').promises; 3 const fsPromise = require('fs').promises;
4 const logger = require('komodo-sdk/logger'); 4 const logger = require('tektrans-logger');
5 5
6 const mkdir = async (xid, dirname, callerName) => { 6 const mkdir = async (xid, dirname, callerName) => {
7 try { 7 try {
8 logger.verbose(`${MODULE_NAME} 6B08D52D: Creating directory`, { 8 logger.verbose(`${MODULE_NAME} 6B08D52D: Creating directory`, {
9 xid, dirname, callerName, 9 xid, dirname, callerName,
10 }); 10 });
11 11
12 await fsPromise.mkdir(dirname, { recursive: true }); 12 await fsPromise.mkdir(dirname, { recursive: true });
13 } catch (e) { 13 } catch (e) {
14 logger.warn(`${MODULE_NAME} 857718E9: Exception on creating directory`, { 14 logger.warn(`${MODULE_NAME} 857718E9: Exception on creating directory`, {
15 xid, 15 xid,
16 dirname, 16 dirname,
17 callerName, 17 callerName,
18 eCode: e.code, 18 eCode: e.code,
19 eMessage: e.message, 19 eMessage: e.message,
20 }); 20 });
21 } 21 }
22 }; 22 };
23 23
24 module.exports = async (xid, dirname, callerName) => { 24 module.exports = async (xid, dirname, callerName) => {
25 try { 25 try {
26 await fsPromise.stat(dirname); 26 await fsPromise.stat(dirname);
27 } catch (e) { 27 } catch (e) {
28 await mkdir(xid, dirname, callerName); 28 await mkdir(xid, dirname, callerName);
29 } 29 }
30 }; 30 };
31 31