Commit 9e5ff94708752350082eaa68139aba98915147c3

Authored by Adhidarma Hadiwinoto
1 parent a99d67bf64
Exists in master

Experimental POST-JSON

Showing 2 changed files with 19 additions and 5 deletions Inline Diff

lib/hit/dump-req-res.js
1 const MODULE_NAME = 'DUMP-REQ-RES'; 1 const MODULE_NAME = 'DUMP-REQ-RES';
2 2
3 const querystring = require('querystring'); 3 const querystring = require('querystring');
4 const fs = require('fs'); 4 const fs = require('fs');
5 const path = require('path'); 5 const path = require('path');
6 const fsPromise = require('fs').promises; 6 const fsPromise = require('fs').promises;
7 const moment = require('moment'); 7 const moment = require('moment');
8 8
9 const config = require('komodo-sdk/config'); 9 const config = require('komodo-sdk/config');
10 const logger = require('tektrans-logger'); 10 const logger = require('tektrans-logger');
11 11
12 const baseDumpDir = 'dump'; 12 const baseDumpDir = 'dump';
13 const requestDumpDir = path.join(baseDumpDir, 'request'); 13 const requestDumpDir = path.join(baseDumpDir, 'request');
14 14
15 if (!fs.existsSync(baseDumpDir)) { 15 if (!fs.existsSync(baseDumpDir)) {
16 logger.verbose(`${MODULE_NAME} 51105314: Creating base dump dir`); 16 logger.verbose(`${MODULE_NAME} 51105314: Creating base dump dir`);
17 fs.mkdirSync(baseDumpDir); 17 fs.mkdirSync(baseDumpDir);
18 } 18 }
19 19
20 if (!fs.existsSync(requestDumpDir)) { 20 if (!fs.existsSync(requestDumpDir)) {
21 logger.verbose(`${MODULE_NAME} 8A52891B: Creating request dump dir`); 21 logger.verbose(`${MODULE_NAME} 8A52891B: Creating request dump dir`);
22 fs.mkdirSync(requestDumpDir); 22 fs.mkdirSync(requestDumpDir);
23 } 23 }
24 24
25 module.exports = async ( 25 module.exports = async (
26 xid, task, httpMethod, endpointUrl, params, responseBody, responseStatus, isAdvice, 26 xid, task, httpMethod, endpointUrl, params, responseBody, responseStatus, isAdvice,
27 ) => { 27 ) => {
28 if ( 28 if (
29 !config 29 !config
30 || !config.partner 30 || !config.partner
31 || !config.partner.dump_request 31 || !config.partner.dump_request
32 ) { 32 ) {
33 return; 33 return;
34 } 34 }
35 35
36 const data = `-------- 36 const data = `--------
37 XID: ${xid} 37 XID: ${xid}
38 PID: ${process.pid} 38 PID: ${process.pid}
39 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')} 39 DATE: ${moment().format('YYYY-MM-DD HH:mm:ss.SSS')}
40 40
41 TASK: 41 TASK:
42 ${JSON.stringify(task, null, 2)} 42 ${JSON.stringify(task, null, 2)}
43 43
44 IS-ADVICE: ${!!isAdvice} 44 IS-ADVICE: ${!!isAdvice}
45 45
46 HTTP-METHOD: ${httpMethod} 46 HTTP-METHOD: ${httpMethod}
47 URL: ${endpointUrl} 47 URL: ${endpointUrl}
48 PARAMS: 48 PARAMS:
49 ${ 49 ${
50 params && ( 50 params && (
51 (typeof params === 'string' && params) 51 (typeof params === 'string' && params)
52 || JSON.stringify(params, null, 2) 52 || JSON.stringify(params, null, 2)
53 ) 53 )
54 } 54 }
55 55
56 ${httpMethod === 'GET' ? `FULL URL: ${endpointUrl}?${querystring.stringify(params)}` : `FORM DATA: ${new URLSearchParams(params).toString()}`} 56 ${
57 (httpMethod === 'GET' && `FULL URL: ${endpointUrl}?${querystring.stringify(params)}`)
58 || (httpMethod === 'POST' && `FORM DATA: ${new URLSearchParams(params).toString()}`)
59 || ''
60 }
57 61
58 RESPONSE-STATUS: ${responseStatus} 62 RESPONSE-STATUS: ${responseStatus}
59 RESPONSE-BODY: 63 RESPONSE-BODY:
60 ${ 64 ${
61 responseBody && ( 65 responseBody && (
62 (typeof responseBody === 'string' && responseBody) 66 (typeof responseBody === 'string' && responseBody)
63 || JSON.stringify(responseBody, null, 2) 67 || JSON.stringify(responseBody, null, 2)
64 ) 68 )
65 } 69 }
66 70
67 `; 71 `;
68 72
69 const dumpDir = path.join( 73 const dumpDir = path.join(
70 requestDumpDir, 74 requestDumpDir,
71 moment().format('YYYY-MM-DD'), 75 moment().format('YYYY-MM-DD'),
72 ); 76 );
73 77
74 try { 78 try {
75 await fsPromise.stat(dumpDir); 79 await fsPromise.stat(dumpDir);
76 } catch { 80 } catch {
77 await fsPromise.mkdir(dumpDir, { recursive: true }); 81 await fsPromise.mkdir(dumpDir, { recursive: true });
78 } 82 }
79 83
80 await fsPromise.appendFile( 84 await fsPromise.appendFile(
81 path.join( 85 path.join(
82 dumpDir, 86 dumpDir,
83 `trx_${task.trx_id}`, 87 `trx_${task.trx_id}`,
84 ), 88 ),
85 data, 89 data,
86 ); 90 );
87 91
88 await fsPromise.writeFile( 92 await fsPromise.writeFile(
89 path.join(requestDumpDir, 'last'), 93 path.join(requestDumpDir, 'last'),
90 data, 94 data,
91 ); 95 );
92 }; 96 };
93 97
lib/hit/prepaid-topup.js
1 const MODULE_NAME = 'HIT.PREPAID-TOPUP'; 1 const MODULE_NAME = 'HIT.PREPAID-TOPUP';
2 2
3 const axios = require('axios'); 3 const axios = require('axios');
4 const urljoin = require('url-join'); 4 const urljoin = require('url-join');
5 const querystring = require('querystring'); 5 const querystring = require('querystring');
6 6
7 const config = require('komodo-sdk/config'); 7 const config = require('komodo-sdk/config');
8 const logger = require('tektrans-logger'); 8 const logger = require('tektrans-logger');
9 9
10 const report = require('../report/prepaid'); 10 const report = require('../report/prepaid');
11 const translateRc = require('../translate-rc'); 11 const translateRc = require('../translate-rc');
12 const composeCallbackUrl = require('./compose-callback-url'); 12 const composeCallbackUrl = require('./compose-callback-url');
13 const dumpReqRes = require('./dump-req-res'); 13 const dumpReqRes = require('./dump-req-res');
14 const axiosErrorIsSafe = require('./axios-error-is-safe'); 14 const axiosErrorIsSafe = require('./axios-error-is-safe');
15 15
16 module.exports = async (xid, task) => { 16 module.exports = async (xid, task) => {
17 logger.verbose(`${MODULE_NAME} 2272F01F: Processing task`, { 17 logger.verbose(`${MODULE_NAME} 2272F01F: Processing task`, {
18 xid, 18 xid,
19 task, 19 task,
20 }); 20 });
21 21
22 const params = { 22 const params = {
23 request_id: task.trx_id, 23 request_id: task.trx_id,
24 terminal_name: config.partner.terminal_name, 24 terminal_name: config.partner.terminal_name,
25 password: config.partner.password, 25 password: config.partner.password,
26 destination: task.destination, 26 destination: task.destination,
27 product_name: task.remote_product, 27 product_name: task.remote_product,
28 reverse_url: composeCallbackUrl(xid, task, false), 28 reverse_url: composeCallbackUrl(xid, task, false),
29 }; 29 };
30 30
31 const endpointUrl = urljoin(config.partner.url, '/topup'); 31 const endpointUrl = urljoin(config.partner.url, '/topup');
32 const fullEndpointUrl = urljoin( 32 const fullEndpointUrl = urljoin(
33 endpointUrl, 33 endpointUrl,
34 [ 34 [
35 '?', 35 '?',
36 querystring.stringify(params), 36 querystring.stringify(params),
37 ].join(''), 37 ].join(''),
38 ); 38 );
39 let lastResponse = null; 39 let lastResponse = null;
40 40
41 try { 41 try {
42 logger.verbose(`${MODULE_NAME} 4AAD4F99: Going to HIT prepaid endpoint`, { 42 logger.verbose(`${MODULE_NAME} 4AAD4F99: Going to HIT prepaid endpoint`, {
43 xid, 43 xid,
44 endpointUrl, 44 endpointUrl,
45 params, 45 params,
46 fullEndpointUrl: (!config.partner.method || config.partner.method === 'GET') 46 fullEndpointUrl: (!config.partner.method || config.partner.method === 'GET')
47 ? fullEndpointUrl 47 ? fullEndpointUrl
48 : endpointUrl, 48 : endpointUrl,
49 }); 49 });
50 50
51 report(xid, { 51 report(xid, {
52 trx_id: task.trx_id, 52 trx_id: task.trx_id,
53 rc: '68', 53 rc: '68',
54 message: { 54 message: {
55 xid, 55 xid,
56 msg: 'Sending request to partner', 56 msg: 'Sending request to partner',
57 method: config.partner.method || 'GET', 57 method: config.partner.method || 'GET',
58 endpointUrl, 58 endpointUrl,
59 }, 59 },
60 }); 60 });
61 61
62 const response = config.partner.method === 'POST' 62 let response;
63 ? await axios.post(endpointUrl, new URLSearchParams(params), { 63 if (config.partner.method === 'POST') {
64 response = await axios.post(endpointUrl, new URLSearchParams(params), {
64 headers: { 65 headers: {
65 'User-Agent': 'KOMODO-GW-HTTPGETX', 66 'User-Agent': 'KOMODO-GW-HTTPGETX',
66 }, 67 },
67 timeout: config.partner.hit_timeout_ms || 60 * 1000, 68 timeout: config.partner.hit_timeout_ms || 60 * 1000,
68 }) 69 });
69 : await axios.get(endpointUrl, { 70 } else if (config.partner.method === 'POST-JSON') {
71 response = await axios.post(endpointUrl, params, {
72 headers: {
73 'User-Agent': 'KOMODO-GW-HTTPGETX',
74 },
75 timeout: config.partner.hit_timeout_ms || 60 * 1000,
76 });
77 } else {
78 response = await axios.get(endpointUrl, {
70 headers: { 79 headers: {
71 'User-Agent': 'KOMODO-GW-HTTPGETX', 80 'User-Agent': 'KOMODO-GW-HTTPGETX',
72 }, 81 },
73 timeout: config.partner.hit_timeout_ms || 60 * 1000, 82 timeout: config.partner.hit_timeout_ms || 60 * 1000,
74 params, 83 params,
75 }); 84 });
85 }
76 86
77 if (!response) { 87 if (!response) {
78 const e = new Error(`${MODULE_NAME} 8CF4E04D: Empty response`); 88 const e = new Error(`${MODULE_NAME} 8CF4E04D: Empty response`);
79 e.rc = '68'; 89 e.rc = '68';
80 e.response = response; 90 e.response = response;
81 throw e; 91 throw e;
82 } 92 }
83 93
84 if (!response.data) { 94 if (!response.data) {
85 const e = new Error(`${MODULE_NAME} E72B5A53: Empty response data`); 95 const e = new Error(`${MODULE_NAME} E72B5A53: Empty response data`);
86 e.rc = '68'; 96 e.rc = '68';
87 e.response = response; 97 e.response = response;
88 throw e; 98 throw e;
89 } 99 }
90 100
91 if (typeof response.data !== 'object') { 101 if (typeof response.data !== 'object') {
92 const e = new Error(`${MODULE_NAME} 507680AB: Response data is not a JSON`); 102 const e = new Error(`${MODULE_NAME} 507680AB: Response data is not a JSON`);
93 e.rc = '68'; 103 e.rc = '68';
94 e.response = response; 104 e.response = response;
95 throw e; 105 throw e;
96 } 106 }
97 107
98 lastResponse = response; 108 lastResponse = response;
99 109
100 logger.verbose(`${MODULE_NAME} E51AFBBA: Got a direct response`, { 110 logger.verbose(`${MODULE_NAME} E51AFBBA: Got a direct response`, {
101 xid, 111 xid,
102 responseBody: response.data, 112 responseBody: response.data,
103 }); 113 });
104 114
105 report(xid, { 115 report(xid, {
106 trx_id: task.trx_id, 116 trx_id: task.trx_id,
107 rc: response.data.rc ? translateRc[response.data.rc] || response.data.rc 117 rc: response.data.rc ? translateRc[response.data.rc] || response.data.rc
108 : '68', 118 : '68',
109 sn: response.data.sn || null, 119 sn: response.data.sn || null,
110 amount: Number(response.data.amount) || undefined, 120 amount: Number(response.data.amount) || undefined,
111 balance: Number(response.data.ending_balance) || undefined, 121 balance: Number(response.data.ending_balance) || undefined,
112 message: { 122 message: {
113 xid, 123 xid,
114 'DIRECT-RESPONSE': response.data, 124 'DIRECT-RESPONSE': response.data,
115 }, 125 },
116 }); 126 });
117 } catch (e) { 127 } catch (e) {
118 const rc = e.rc 128 const rc = e.rc
119 || (axiosErrorIsSafe(e) && '91') 129 || (axiosErrorIsSafe(e) && '91')
120 || '68'; 130 || '68';
121 131
122 logger.warn(`${MODULE_NAME} 8E8E49F5: Exception`, { 132 logger.warn(`${MODULE_NAME} 8E8E49F5: Exception`, {
123 xid, 133 xid,
124 eCode: e.code, 134 eCode: e.code,
125 eMessage: e.message, 135 eMessage: e.message,
126 eRc: e.rc, 136 eRc: e.rc,
127 rc, 137 rc,
128 responseHttpStatus: e.response && e.response.status, 138 responseHttpStatus: e.response && e.response.status,
129 responseBody: e.response && e.response.data, 139 responseBody: e.response && e.response.data,
130 }); 140 });
131 141
132 lastResponse = e.response; 142 lastResponse = e.response;
133 143
134 report(xid, { 144 report(xid, {
135 trx_id: task.trx_id, 145 trx_id: task.trx_id,
136 rc, 146 rc,
137 message: { 147 message: {
138 xid, 148 xid,
139 'KOMODO-GW-ERROR': { 149 'KOMODO-GW-ERROR': {
140 eCode: e.code, 150 eCode: e.code,
141 eMessage: e.message, 151 eMessage: e.message,
142 responseHttpStatus: e.response && e.response.status, 152 responseHttpStatus: e.response && e.response.status,
143 responseBody: e.response && e.response.data, 153 responseBody: e.response && e.response.data,
144 }, 154 },
145 }, 155 },
146 }); 156 });
147 } finally { 157 } finally {
148 dumpReqRes( 158 dumpReqRes(
149 xid, 159 xid,
150 task, 160 task,
151 config.partner.method || 'GET', 161 config.partner.method || 'GET',
152 endpointUrl, 162 endpointUrl,
153 params, 163 params,
154 lastResponse && lastResponse.data, 164 lastResponse && lastResponse.data,
155 lastResponse && lastResponse.status, 165 lastResponse && lastResponse.status,
156 lastResponse, 166 lastResponse,
157 false, 167 false,
158 ); 168 );
159 } 169 }
160 }; 170 };
161 171