Commit 9e5ff94708752350082eaa68139aba98915147c3
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 |