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