Commit e7d6beeedb7474229261f8c67532547cc45cbb3e
1 parent
f855f4fdca
Exists in
master
message using stringify
Showing 2 changed files with 4 additions and 2 deletions Inline Diff
lib/partner.js
1 | "use strict"; | 1 | "use strict"; |
2 | 2 | ||
3 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; | 3 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; |
4 | 4 | ||
5 | const fs = require('fs'); | 5 | const fs = require('fs'); |
6 | const url = require('url'); | 6 | const url = require('url'); |
7 | const https = require('https'); | 7 | const https = require('https'); |
8 | const xmlrpc = require('xmlrpc'); | 8 | const xmlrpc = require('xmlrpc'); |
9 | const moment = require('moment'); | 9 | const moment = require('moment'); |
10 | const stringify = require("json-stringify-pretty-compact"); | ||
10 | 11 | ||
11 | const config = require('komodo-sdk/config'); | 12 | const config = require('komodo-sdk/config'); |
12 | const logger = require('komodo-sdk/logger'); | 13 | const logger = require('komodo-sdk/logger'); |
13 | const matrix = require('komodo-sdk/matrix'); | 14 | const matrix = require('komodo-sdk/matrix'); |
14 | const pull = require('komodo-sdk/gateway/pull'); | 15 | const pull = require('komodo-sdk/gateway/pull'); |
15 | const resendDelay = require('komodo-sdk/gateway/resend-delay'); | 16 | const resendDelay = require('komodo-sdk/gateway/resend-delay'); |
16 | 17 | ||
17 | const st24 = require('./st24'); | 18 | const st24 = require('./st24'); |
18 | 19 | ||
19 | const partnerRc = fs.existsSync(__dirname + '/../rc-local.json') ? require('../rc-local.json') : require('./partner-rc.json'); | 20 | const partnerRc = fs.existsSync(__dirname + '/../rc-local.json') ? require('../rc-local.json') : require('./partner-rc.json'); |
20 | 21 | ||
21 | if (config.partner.use_sslv3) { | 22 | if (config.partner.use_sslv3) { |
22 | https.globalAgent.options.secureProtocol = 'SSLv3_method'; | 23 | https.globalAgent.options.secureProtocol = 'SSLv3_method'; |
23 | } | 24 | } |
24 | 25 | ||
25 | function createXmlRpcClient(endpoint) { | 26 | function createXmlRpcClient(endpoint) { |
26 | const partnerUrl = url.parse(endpoint); | 27 | const partnerUrl = url.parse(endpoint); |
27 | const clientOptions = { | 28 | const clientOptions = { |
28 | host: partnerUrl.hostname, | 29 | host: partnerUrl.hostname, |
29 | port: partnerUrl.port, | 30 | port: partnerUrl.port, |
30 | path: partnerUrl.pathname | 31 | path: partnerUrl.pathname |
31 | }; | 32 | }; |
32 | 33 | ||
33 | logger.verbose('Creating XML-RPC client using ' + partnerUrl.protocol, clientOptions); | 34 | logger.verbose('Creating XML-RPC client using ' + partnerUrl.protocol, clientOptions); |
34 | 35 | ||
35 | return (partnerUrl.protocol === 'https:') ? xmlrpc.createSecureClient(clientOptions) : xmlrpc.createClient(clientOptions); | 36 | return (partnerUrl.protocol === 'https:') ? xmlrpc.createSecureClient(clientOptions) : xmlrpc.createClient(clientOptions); |
36 | } | 37 | } |
37 | 38 | ||
38 | function buy(task) { | 39 | function buy(task) { |
39 | _topUpRequest(task); | 40 | _topUpRequest(task); |
40 | } | 41 | } |
41 | 42 | ||
42 | function _topUpRequest(task, isAdvice) { | 43 | function _topUpRequest(task, isAdvice) { |
43 | const params = { | 44 | const params = { |
44 | MSISDN: config.partner.msisdn || config.partner.userid, | 45 | MSISDN: config.partner.msisdn || config.partner.userid, |
45 | REQUESTID: task.trx_id, | 46 | REQUESTID: task.trx_id, |
46 | PIN: config.partner.pin || config.partner.password, | 47 | PIN: config.partner.pin || config.partner.password, |
47 | NOHP: task.destination, | 48 | NOHP: task.destination, |
48 | NOM: task.remote_product | 49 | NOM: task.remote_product |
49 | }; | 50 | }; |
50 | 51 | ||
51 | const xmlrpcMethod = 'topUpRequest'; | 52 | const xmlrpcMethod = 'topUpRequest'; |
52 | logger.info('Preparing XMLRPC request', {method: xmlrpcMethod, params: params, partnerUrl: config.partner.url}); | 53 | logger.info('Preparing XMLRPC request', {method: xmlrpcMethod, params: params, partnerUrl: config.partner.url}); |
53 | 54 | ||
54 | const client = createXmlRpcClient(config.partner.url); | 55 | const client = createXmlRpcClient(config.partner.url); |
55 | client.methodCall(xmlrpcMethod, [ params ], function (err, value) { | 56 | client.methodCall(xmlrpcMethod, [ params ], function (err, value) { |
56 | 57 | ||
57 | if (err) { | 58 | if (err) { |
58 | 59 | ||
59 | let msg = 'XMLRPC Client Error: ' + err; | 60 | let msg = 'XMLRPC Client Error: ' + err; |
60 | let rc = '68'; | 61 | let rc = '68'; |
61 | 62 | ||
62 | if ( | 63 | if ( |
63 | !isAdvice && | 64 | !isAdvice && |
64 | ( | 65 | ( |
65 | err.code === 'ECONNREFUSED' | 66 | err.code === 'ECONNREFUSED' |
66 | || err.code === 'EHOSTUNREACH' | 67 | || err.code === 'EHOSTUNREACH' |
67 | || (err.code === 'ETIMEDOUT' && err.syscall === "connect") | 68 | || (err.code === 'ETIMEDOUT' && err.syscall === "connect") |
68 | || (err.code === 'EPROTO' && err.syscall === "write") | 69 | || (err.code === 'EPROTO' && err.syscall === "write") |
69 | ) | 70 | ) |
70 | ) { | 71 | ) { |
71 | rc = '91'; | 72 | rc = '91'; |
72 | } | 73 | } |
73 | 74 | ||
74 | logger.warn(msg, {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, err: err}); | 75 | logger.warn(msg, {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, err: err}); |
75 | report({ | 76 | report({ |
76 | trx_id: task.trx_id, | 77 | trx_id: task.trx_id, |
77 | rc: rc, | 78 | rc: rc, |
78 | message: 'INTERNAL: ' + msg, | 79 | message: 'INTERNAL: ' + msg, |
79 | misc: { | 80 | misc: { |
80 | task: task | 81 | task: task |
81 | } | 82 | } |
82 | }); | 83 | }); |
83 | 84 | ||
84 | return; | 85 | return; |
85 | } | 86 | } |
86 | 87 | ||
87 | logger.info('Got XMLRPC response from partner for', {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, response: value}); | 88 | logger.info('Got XMLRPC response from partner for', {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, response: value}); |
88 | matrix.last_topupRequest_ack = value; | 89 | matrix.last_topupRequest_ack = value; |
89 | 90 | ||
90 | report({ | 91 | report({ |
91 | trx_id: task.trx_id, | 92 | trx_id: task.trx_id, |
92 | rc: partnerRc[value.RESPONSECODE] || '40', | 93 | rc: partnerRc[value.RESPONSECODE] || '40', |
93 | message: value.MESSAGE, | 94 | message: stringify(value), |
94 | sn: (value.SN || '').replace(/;$/, '') || st24.extractSnFromMessage(value.MESSAGE), | 95 | sn: (value.SN || '').replace(/;$/, '') || st24.extractSnFromMessage(value.MESSAGE), |
95 | amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE), | 96 | amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE), |
96 | raw: value, | 97 | raw: value, |
97 | misc: { | 98 | misc: { |
98 | task: task | 99 | task: task |
99 | } | 100 | } |
100 | }); | 101 | }); |
101 | }); | 102 | }); |
102 | } | 103 | } |
103 | 104 | ||
104 | function _topUpInquiry(task) { | 105 | function _topUpInquiry(task) { |
105 | const params = { | 106 | const params = { |
106 | REQUESTID: task.trx_id, | 107 | REQUESTID: task.trx_id, |
107 | MSISDN: config.partner.msisdn || config.partner.userid, | 108 | MSISDN: config.partner.msisdn || config.partner.userid, |
108 | PIN: config.partner.pin || config.partner.password, | 109 | PIN: config.partner.pin || config.partner.password, |
109 | NOHP: task.destination | 110 | NOHP: task.destination |
110 | }; | 111 | }; |
111 | 112 | ||
112 | const xmlrpcMethod = 'topUpInquiry'; | 113 | const xmlrpcMethod = 'topUpInquiry'; |
113 | logger.info('Preparing XMLRPC request', {method: xmlrpcMethod, params: params, partnerUrl: config.partner.url}); | 114 | logger.info('Preparing XMLRPC request', {method: xmlrpcMethod, params: params, partnerUrl: config.partner.url}); |
114 | 115 | ||
115 | const client = createXmlRpcClient(config.partner.url); | 116 | const client = createXmlRpcClient(config.partner.url); |
116 | client.methodCall(xmlrpcMethod, [ params ], function (err, value) { | 117 | client.methodCall(xmlrpcMethod, [ params ], function (err, value) { |
117 | 118 | ||
118 | if (err) { | 119 | if (err) { |
119 | 120 | ||
120 | const msg = 'XMLRPC Client Error: ' + err; | 121 | const msg = 'XMLRPC Client Error: ' + err; |
121 | 122 | ||
122 | logger.warn(msg, {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, err: err}); | 123 | logger.warn(msg, {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, err: err}); |
123 | report({ | 124 | report({ |
124 | trx_id: task.trx_id, | 125 | trx_id: task.trx_id, |
125 | rc: '68', | 126 | rc: '68', |
126 | message: 'INTERNAL: ' + msg, | 127 | message: 'INTERNAL: ' + msg, |
127 | misc: { | 128 | misc: { |
128 | task: task | 129 | task: task |
129 | } | 130 | } |
130 | }); | 131 | }); |
131 | 132 | ||
132 | return; | 133 | return; |
133 | } | 134 | } |
134 | 135 | ||
135 | logger.info('Got XMLRPC response from partner for', {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, response: value}); | 136 | logger.info('Got XMLRPC response from partner for', {method: xmlrpcMethod, trx_id: task.trx_id, destination: task.destination, response: value}); |
136 | //matrix.last_topupRequest_ack = value; | 137 | //matrix.last_topupRequest_ack = value; |
137 | 138 | ||
138 | report({ | 139 | report({ |
139 | trx_id: task.trx_id, | 140 | trx_id: task.trx_id, |
140 | rc: partnerRc[value.RESPONSECODE] || '40', | 141 | rc: partnerRc[value.RESPONSECODE] || '40', |
141 | message: value.MESSAGE, | 142 | message: stringify(value), |
142 | sn: (value.SN || '').replace(/;$/, '') || st24.extractSnFromMessage(value.MESSAGE, config.sn_pattern), | 143 | sn: (value.SN || '').replace(/;$/, '') || st24.extractSnFromMessage(value.MESSAGE, config.sn_pattern), |
143 | amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE), | 144 | amount: value.PRICE || st24.extractPriceFromMsg(value.MESSAGE), |
144 | raw: value, | 145 | raw: value, |
145 | misc: { | 146 | misc: { |
146 | task: task | 147 | task: task |
147 | } | 148 | } |
148 | }); | 149 | }); |
149 | }); | 150 | }); |
150 | } | 151 | } |
151 | 152 | ||
152 | function advice(task) { | 153 | function advice(task) { |
153 | if (config && config.advice_is_not_allowed) { | 154 | if (config && config.advice_is_not_allowed) { |
154 | return; | 155 | return; |
155 | } | 156 | } |
156 | 157 | ||
157 | if (config && config.advice_max_age_ms) { | 158 | if (config && config.advice_max_age_ms) { |
158 | if (moment() - moment(task.created) > config.advice_max_age_ms) { | 159 | if (moment() - moment(task.created) > config.advice_max_age_ms) { |
159 | logger.verbose('Ignoring advice request because of expired task', {trx_id: task.trx_id, destination: task.destination, product: task.product, created: task.created, max_age: config.advice_max_age_ms}); | 160 | logger.verbose('Ignoring advice request because of expired task', {trx_id: task.trx_id, destination: task.destination, product: task.product, created: task.created, max_age: config.advice_max_age_ms}); |
160 | return; | 161 | return; |
161 | } | 162 | } |
162 | } | 163 | } |
163 | 164 | ||
164 | if (config && config.advice_is_topuprequest) { | 165 | if (config && config.advice_is_topuprequest) { |
165 | _topUpRequest(task, true); | 166 | _topUpRequest(task, true); |
166 | } | 167 | } |
167 | else { | 168 | else { |
168 | _topUpInquiry(task); | 169 | _topUpInquiry(task); |
169 | } | 170 | } |
170 | } | 171 | } |
171 | 172 | ||
172 | function report(data) { | 173 | function report(data) { |
173 | if (!data) { | 174 | if (!data) { |
174 | return; | 175 | return; |
175 | } | 176 | } |
176 | 177 | ||
177 | if (config && config.force_all_to_pending) { | 178 | if (config && config.force_all_to_pending) { |
178 | data.rc = '68'; | 179 | data.rc = '68'; |
179 | } | 180 | } |
180 | 181 | ||
181 | matrix.last_report_to_core = data; | 182 | matrix.last_report_to_core = data; |
182 | pull.report(data); | 183 | pull.report(data); |
183 | 184 | ||
184 | if (!resendDelay.isEnabled()) return; | 185 | if (!resendDelay.isEnabled()) return; |
185 | 186 | ||
186 | if (data.task && data.rc && data.rc === '68') { | 187 | if (data.task && data.rc && data.rc === '68') { |
187 | resendDelay.register(data.task, advice); | 188 | resendDelay.register(data.task, advice); |
188 | } | 189 | } |
189 | else { | 190 | else { |
190 | resendDelay.cancel(data.trx_id); | 191 | resendDelay.cancel(data.trx_id); |
191 | } | 192 | } |
192 | } | 193 | } |
193 | 194 | ||
194 | exports.buy = buy; | 195 | exports.buy = buy; |
195 | exports.advice = advice; | 196 | exports.advice = advice; |
196 | exports.report = report; | 197 | exports.report = report; |
197 | 198 |
package.json
1 | { | 1 | { |
2 | "name": "komodo-gw-st24", | 2 | "name": "komodo-gw-st24", |
3 | "version": "1.2.1", | 3 | "version": "1.2.1", |
4 | "description": "Komodo Gateway to ST24 XML-RPC", | 4 | "description": "Komodo Gateway to ST24 XML-RPC", |
5 | "main": "index.js", | 5 | "main": "index.js", |
6 | "scripts": { | 6 | "scripts": { |
7 | "test": "mocha", | 7 | "test": "mocha", |
8 | "postversion": "git push && git push --tags" | 8 | "postversion": "git push && git push --tags" |
9 | }, | 9 | }, |
10 | "repository": { | 10 | "repository": { |
11 | "type": "git", | 11 | "type": "git", |
12 | "url": "git@gitlab.kodesumber.com:komodo/komodo-gw-st24.git" | 12 | "url": "git@gitlab.kodesumber.com:komodo/komodo-gw-st24.git" |
13 | }, | 13 | }, |
14 | "keywords": [ | 14 | "keywords": [ |
15 | "komodo", | 15 | "komodo", |
16 | "tektrans", | 16 | "tektrans", |
17 | "ppob", | 17 | "ppob", |
18 | "st24", | 18 | "st24", |
19 | "xmlrpc", | 19 | "xmlrpc", |
20 | "xml-rpc" | 20 | "xml-rpc" |
21 | ], | 21 | ], |
22 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", | 22 | "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", |
23 | "license": "ISC", | 23 | "license": "ISC", |
24 | "dependencies": { | 24 | "dependencies": { |
25 | "json-stringify-pretty-compact": "^1.1.0", | ||
25 | "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", | 26 | "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", |
26 | "moment": "^2.22.1", | 27 | "moment": "^2.22.1", |
27 | "xmlrpc": "^1.3.2" | 28 | "xmlrpc": "^1.3.2" |
28 | }, | 29 | }, |
29 | "devDependencies": { | 30 | "devDependencies": { |
30 | "should": "^13.2.1" | 31 | "should": "^13.2.1" |
31 | } | 32 | } |
32 | } | 33 | } |
33 | 34 |