Commit 6345464d43452eef5bcc00927ae412bf837b2641
1 parent
2d655fbec9
Exists in
master
var redisClient
Showing 1 changed file with 1 additions and 0 deletions Inline Diff
partner-trustlink.js
1 | var winston = require('winston'); | 1 | var winston = require('winston'); |
2 | var request = require('request'); | 2 | var request = require('request'); |
3 | var strftime = require('strftime'); | 3 | var strftime = require('strftime'); |
4 | var url = require('url'); | 4 | var url = require('url'); |
5 | var xor = require('base64-xor'); | 5 | var xor = require('base64-xor'); |
6 | var http = require('http'); | 6 | var http = require('http'); |
7 | var xml = require('xml'); | 7 | var xml = require('xml'); |
8 | var xml2js = require('xml2js').parseString; | 8 | var xml2js = require('xml2js').parseString; |
9 | 9 | ||
10 | var max_retry = 3; | 10 | var max_retry = 3; |
11 | var sleep_before_retry = 2000; | 11 | var sleep_before_retry = 2000; |
12 | 12 | ||
13 | var config; | 13 | var config; |
14 | var callbackReport; | 14 | var callbackReport; |
15 | var aaa; | 15 | var aaa; |
16 | var logger; | 16 | var logger; |
17 | var options; | 17 | var options; |
18 | var redisClient; | ||
18 | 19 | ||
19 | function start(_config, _callbackReport, options) { | 20 | function start(_config, _callbackReport, options) { |
20 | config = _config; | 21 | config = _config; |
21 | callbackReport = _callbackReport | 22 | callbackReport = _callbackReport |
22 | 23 | ||
23 | if (options && options.aaa) { | 24 | if (options && options.aaa) { |
24 | aaa = options.aaa; | 25 | aaa = options.aaa; |
25 | } | 26 | } |
26 | 27 | ||
27 | if (options && options.logger) { | 28 | if (options && options.logger) { |
28 | logger = options.logger; | 29 | logger = options.logger; |
29 | } else { | 30 | } else { |
30 | logger = new winston.Logger({ | 31 | logger = new winston.Logger({ |
31 | transports: [ | 32 | transports: [ |
32 | new (winston.transports.Console)() | 33 | new (winston.transports.Console)() |
33 | ] | 34 | ] |
34 | }); | 35 | }); |
35 | } | 36 | } |
36 | 37 | ||
37 | createRedisClient(); | 38 | createRedisClient(); |
38 | createReverseReportServer(); | 39 | createReverseReportServer(); |
39 | } | 40 | } |
40 | 41 | ||
41 | function createReverseReportServer() { | 42 | function createReverseReportServer() { |
42 | var httpServer = http.createServer(onReverseReport).listen(config.h2h_out.listen_port, function() { | 43 | var httpServer = http.createServer(onReverseReport).listen(config.h2h_out.listen_port, function() { |
43 | logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); | 44 | logger.info('HTTP Reverse/Report server listen on port ' + config.h2h_out.listen_port); |
44 | }); | 45 | }); |
45 | } | 46 | } |
46 | 47 | ||
47 | function onReverseReport(req, res) { | 48 | function onReverseReport(req, res) { |
48 | res.end('OK'); | 49 | res.end('OK'); |
49 | 50 | ||
50 | var qs = url.parse(req.url, true).query; | 51 | var qs = url.parse(req.url, true).query; |
51 | logger.info('Reverse Report', {qs: qs}); | 52 | logger.info('Reverse Report', {qs: qs}); |
52 | } | 53 | } |
53 | 54 | ||
54 | function calculateSignature(ts, destination, password) { | 55 | function calculateSignature(ts, destination, password) { |
55 | var a = ts + destination.substr(destination.length - 4); | 56 | var a = ts + destination.substr(destination.length - 4); |
56 | var b = destination.substr(destination.length - 4).split('').reverse().join('') + password; | 57 | var b = destination.substr(destination.length - 4).split('').reverse().join('') + password; |
57 | 58 | ||
58 | return xor.encode(a,b); | 59 | return xor.encode(a,b); |
59 | } | 60 | } |
60 | 61 | ||
61 | function createXmlPayload(task, userid, password) { | 62 | function createXmlPayload(task, userid, password) { |
62 | var ts = strftime('%H%M%S', new Date()); | 63 | var ts = strftime('%H%M%S', new Date()); |
63 | 64 | ||
64 | var signature = calculateSignature(ts, task.destination, password); | 65 | var signature = calculateSignature(ts, task.destination, password); |
65 | 66 | ||
66 | var payload = { | 67 | var payload = { |
67 | evoucher: [ | 68 | evoucher: [ |
68 | {command: 'TOPUP'}, | 69 | {command: 'TOPUP'}, |
69 | {product: task.remoteProduct}, | 70 | {product: task.remoteProduct}, |
70 | {userid: userid}, | 71 | {userid: userid}, |
71 | {time: ts}, | 72 | {time: ts}, |
72 | {msisdn: task.destination}, | 73 | {msisdn: task.destination}, |
73 | {partner_trxid: task.requestId}, | 74 | {partner_trxid: task.requestId}, |
74 | {signature: signature}, | 75 | {signature: signature}, |
75 | {trxke: 1}, | 76 | {trxke: 1}, |
76 | ] | 77 | ] |
77 | }; | 78 | }; |
78 | 79 | ||
79 | if (logger) { | 80 | if (logger) { |
80 | logger.verbose('Generate xml payload', {payload: payload}); | 81 | logger.verbose('Generate xml payload', {payload: payload}); |
81 | } | 82 | } |
82 | 83 | ||
83 | return "<?xml version=\"1.0\" ?>\n" + xml(payload); | 84 | return "<?xml version=\"1.0\" ?>\n" + xml(payload); |
84 | } | 85 | } |
85 | 86 | ||
86 | function topupRequestHit(task, retry) { | 87 | function topupRequestHit(task, retry) { |
87 | if (retry === undefined) { | 88 | if (retry === undefined) { |
88 | retry = max_retry; | 89 | retry = max_retry; |
89 | } | 90 | } |
90 | 91 | ||
91 | var payload = createXmlPayload(task, config.h2h_out.userid, config.h2h_out.password); | 92 | var payload = createXmlPayload(task, config.h2h_out.userid, config.h2h_out.password); |
92 | 93 | ||
93 | var partner = url.parse(config.h2h_out.partner); | 94 | var partner = url.parse(config.h2h_out.partner); |
94 | 95 | ||
95 | var request_options = { | 96 | var request_options = { |
96 | host: partner.hostname, | 97 | host: partner.hostname, |
97 | path: partner.path, | 98 | path: partner.path, |
98 | port: partner.port, | 99 | port: partner.port, |
99 | method: "POST", | 100 | method: "POST", |
100 | headers: { | 101 | headers: { |
101 | 'Content-Type': 'text/xml', | 102 | 'Content-Type': 'text/xml', |
102 | 'Content-Length': Buffer.byteLength(payload) | 103 | 'Content-Length': Buffer.byteLength(payload) |
103 | } | 104 | } |
104 | }; | 105 | }; |
105 | 106 | ||
106 | var buffer = ""; | 107 | var buffer = ""; |
107 | 108 | ||
108 | logger.info('Requesting to partner', {request_options: request_options}); | 109 | logger.info('Requesting to partner', {request_options: request_options}); |
109 | 110 | ||
110 | var req = http.request(request_options, function( res ) { | 111 | var req = http.request(request_options, function( res ) { |
111 | 112 | ||
112 | logger.verbose('Status code: ' + res.statusCode ); | 113 | logger.verbose('Status code: ' + res.statusCode ); |
113 | var buffer = ""; | 114 | var buffer = ""; |
114 | res.on( "data", function( data ) { buffer = buffer + data; } ); | 115 | res.on( "data", function( data ) { buffer = buffer + data; } ); |
115 | res.on( "end", function( data ) { | 116 | res.on( "end", function( data ) { |
116 | logger.verbose('Got direct response from partner', {resp: buffer}); | 117 | logger.verbose('Got direct response from partner', {resp: buffer}); |
117 | directResponseHandler(buffer, task); | 118 | directResponseHandler(buffer, task); |
118 | }); | 119 | }); |
119 | 120 | ||
120 | }); | 121 | }); |
121 | 122 | ||
122 | req.on('error', function(e) { | 123 | req.on('error', function(e) { |
123 | logger.warn('problem with request: ' + e.message); | 124 | logger.warn('problem with request: ' + e.message); |
124 | callbackReport(task.requestId, '68', e.message); | 125 | callbackReport(task.requestId, '68', e.message); |
125 | return; | 126 | return; |
126 | }); | 127 | }); |
127 | 128 | ||
128 | logger.verbose('Sending payload to partner', {payload: payload}); | 129 | logger.verbose('Sending payload to partner', {payload: payload}); |
129 | req.write( payload ); | 130 | req.write( payload ); |
130 | req.end(); | 131 | req.end(); |
131 | } | 132 | } |
132 | 133 | ||
133 | function directResponseHandler(body, task) { | 134 | function directResponseHandler(body, task) { |
134 | 135 | ||
135 | logger.info('Got direct response'); | 136 | logger.info('Got direct response'); |
136 | 137 | ||
137 | xml2js(body, function (err, result) { | 138 | xml2js(body, function (err, result) { |
138 | if (err) { | 139 | if (err) { |
139 | logger.warn('Error parsing xml', {body: body}); | 140 | logger.warn('Error parsing xml', {body: body}); |
140 | callbackReport(task.requestId, '68', buffer); | 141 | callbackReport(task.requestId, '68', buffer); |
141 | return; | 142 | return; |
142 | } | 143 | } |
143 | 144 | ||
144 | logger.info('Direct response parsed', {result: result}); | 145 | logger.info('Direct response parsed', {result: result}); |
145 | 146 | ||
146 | var response_code = '68'; | 147 | var response_code = '68'; |
147 | 148 | ||
148 | var request_id = task.requestId; | 149 | var request_id = task.requestId; |
149 | var status = result.evoucher.result[0].trim(); | 150 | var status = result.evoucher.result[0].trim(); |
150 | var message = result.evoucher.value[0].string[0].trim(); | 151 | var message = result.evoucher.value[0].string[0].trim(); |
151 | 152 | ||
152 | if (message.indexOf('SUKSES') >= 0) { | 153 | if (message.indexOf('SUKSES') >= 0) { |
153 | /* | 154 | /* |
154 | var sn = getSNFromMessage(message); | 155 | var sn = getSNFromMessage(message); |
155 | message = 'SN=' + sn + '; ' + message; | 156 | message = 'SN=' + sn + '; ' + message; |
156 | */ | 157 | */ |
157 | 158 | ||
158 | response_code = '68'; | 159 | response_code = '68'; |
159 | } | 160 | } |
160 | else if (message.indexOf('GAGAL') >= 0) { | 161 | else if (message.indexOf('GAGAL') >= 0) { |
161 | response_code = '40'; | 162 | response_code = '40'; |
162 | } | 163 | } |
163 | else { | 164 | else { |
164 | response_code = '68'; | 165 | response_code = '68'; |
165 | } | 166 | } |
166 | 167 | ||
167 | callbackReport(request_id, response_code, message); | 168 | callbackReport(request_id, response_code, message); |
168 | }); | 169 | }); |
169 | } | 170 | } |
170 | 171 | ||
171 | function getSNFromMessage(message) { | 172 | function getSNFromMessage(message) { |
172 | try { | 173 | try { |
173 | var sn_match = message.match(/SN=(\w+)/); | 174 | var sn_match = message.match(/SN=(\w+)/); |
174 | return sn_match[1].trim(); | 175 | return sn_match[1].trim(); |
175 | } | 176 | } |
176 | catch(e) { | 177 | catch(e) { |
177 | return; | 178 | return; |
178 | } | 179 | } |
179 | } | 180 | } |
180 | 181 | ||
181 | function topupRequest(task, retry) { | 182 | function topupRequest(task, retry) { |
182 | var key = 'DUPCHECK.gw:' + config.globals.gateway_name + '.prod:' + task.remoteProduct + '.dest:' + task.destination + '.date:' + strftime('%Y%m%d', new Date); | 183 | var key = 'DUPCHECK.gw:' + config.globals.gateway_name + '.prod:' + task.remoteProduct + '.dest:' + task.destination + '.date:' + strftime('%Y%m%d', new Date); |
183 | redisClient.get(key, function(err, data) { | 184 | redisClient.get(key, function(err, data) { |
184 | if (err) { | 185 | if (err) { |
185 | callbackReport(task.requestId, '40', 'Gagal cek anti transaksi duplikat (redis error)'); | 186 | callbackReport(task.requestId, '40', 'Gagal cek anti transaksi duplikat (redis error)'); |
186 | return; | 187 | return; |
187 | } | 188 | } |
188 | 189 | ||
189 | if (!data) { | 190 | if (!data) { |
190 | 191 | ||
191 | redisClient.set(key, JSON.stringify(task)); | 192 | redisClient.set(key, JSON.stringify(task)); |
192 | redisClient.expire(key, 3600 * 24 * 2); | 193 | redisClient.expire(key, 3600 * 24 * 2); |
193 | 194 | ||
194 | } else { | 195 | } else { |
195 | 196 | ||
196 | try { | 197 | try { |
197 | var taskOnRedis = JSON.parse(data); | 198 | var taskOnRedis = JSON.parse(data); |
198 | if (task.requestId == taskOnRedis.requestId) { | 199 | if (task.requestId == taskOnRedis.requestId) { |
199 | topupRequestHit(task, retry); | 200 | topupRequestHit(task, retry); |
200 | } else { | 201 | } else { |
201 | callbackReport(task.requestId, '55', 'Transaksi duplikat') | 202 | callbackReport(task.requestId, '55', 'Transaksi duplikat') |
202 | } | 203 | } |
203 | } | 204 | } |
204 | catch(errJSONParse) { | 205 | catch(errJSONParse) { |
205 | callbackReport(task.requestId, '68', "error parsing json"); | 206 | callbackReport(task.requestId, '68', "error parsing json"); |
206 | } | 207 | } |
207 | } | 208 | } |
208 | 209 | ||
209 | }); | 210 | }); |
210 | } | 211 | } |
211 | 212 | ||
212 | function createRedisClient() { | 213 | function createRedisClient() { |
213 | try { | 214 | try { |
214 | redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host); | 215 | redisClient = redis.createClient(config.globals.redis_port, config.globals.redis_host); |
215 | } catch(err) { | 216 | } catch(err) { |
216 | logger.info("Error creating redis client"); | 217 | logger.info("Error creating redis client"); |
217 | } | 218 | } |
218 | } | 219 | } |
219 | 220 | ||
220 | exports.start = start; | 221 | exports.start = start; |
221 | exports.topupRequest = topupRequest; | 222 | exports.topupRequest = topupRequest; |
222 | exports.calculateSignature = calculateSignature; | 223 | exports.calculateSignature = calculateSignature; |
223 | 224 |