Commit 4cc1669e7107b7a0803f090c409f57a57b0e991a
1 parent
3bef0d5aa2
Exists in
master
Ready to running test
Showing 9 changed files with 622 additions and 0 deletions Side-by-side Diff
config.sample.json
... | ... | @@ -0,0 +1,14 @@ |
1 | +{ | |
2 | + "server_options": { | |
3 | + "port": 6789 | |
4 | + }, | |
5 | + "smscid": "XML1234", | |
6 | + "immediate_reply": 1, | |
7 | + "master_url": "http://127.0.0.1:4100/", | |
8 | + "res_port": 25300, | |
9 | + "oracle": { | |
10 | + "user": "user", | |
11 | + "password": "password", | |
12 | + "connectString": "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=172.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ST24)))" | |
13 | + } | |
14 | +} |
index.js
... | ... | @@ -0,0 +1,11 @@ |
1 | +var neoxmlinutil = require('./neoxmlinutil'); | |
2 | +var xmlrpcServer = require('./xmlrpc-server'); | |
3 | +var logger = require('./logger.js').start(); | |
4 | + | |
5 | +var options = { | |
6 | + logger: logger | |
7 | +}; | |
8 | + | |
9 | +neoxmlinutil.init(options); | |
10 | +neoxmlinutil.connectToOracle(); | |
11 | +xmlrpcServer.start(options); |
logger.js
... | ... | @@ -0,0 +1,48 @@ |
1 | +var strftime = require('strftime'); | |
2 | +var winston = require('winston'); | |
3 | +var fs = require('fs'); | |
4 | + | |
5 | +var loggerTimestamp = function() { | |
6 | + return strftime('%F %T', new Date()); | |
7 | +} | |
8 | + | |
9 | +function start(options) { | |
10 | + var logDir = __dirname + '/logs' | |
11 | + | |
12 | + var logLevel = 'debug'; | |
13 | + if (options && options.logLevel) { | |
14 | + logLevel = options.logLevel; | |
15 | + } | |
16 | + | |
17 | + if (!fs.existsSync(logDir)) { | |
18 | + fs.mkdirSync(logDir); | |
19 | + } | |
20 | + | |
21 | + var logger = new winston.Logger({ | |
22 | + transports: [ | |
23 | + new (winston.transports.Console)({ | |
24 | + timestamp: function() { | |
25 | + return strftime('%F %T', new Date()); | |
26 | + }, | |
27 | + level: 'verbose', | |
28 | + }), | |
29 | + | |
30 | + new(require('winston-daily-rotate-file')) ({ | |
31 | + name: './log-file-txt', | |
32 | + filename: logDir + '/log.txt', | |
33 | + timestamp: loggerTimestamp, | |
34 | + formatter: function(options) { | |
35 | + return options.timestamp() | |
36 | + +' ' + options.level.toUpperCase() | |
37 | + +' ' + (undefined !== options.message ? options.message : '') | |
38 | + + (options.meta && Object.keys(options.meta).length ? '\n\t' + JSON.stringify(options.meta) : '' ); | |
39 | + }, | |
40 | + level: logLevel, | |
41 | + }), | |
42 | + ] | |
43 | + }); | |
44 | + | |
45 | + return logger; | |
46 | +} | |
47 | + | |
48 | +exports.start = start; |
neoxmlinutil.js
... | ... | @@ -0,0 +1,78 @@ |
1 | +var oracledb = require('oracledb'); | |
2 | + | |
3 | +var config = require("./config.json"); | |
4 | +var logger = console; | |
5 | + | |
6 | +var oraCon; | |
7 | + | |
8 | +function init(options) { | |
9 | + if (options && options.logger) { | |
10 | + logger = options.logger; | |
11 | + } | |
12 | +} | |
13 | + | |
14 | +function connectToOracle(callback) { | |
15 | + oracledb.getConnection(config.oracle, function(err, connection) { | |
16 | + if (err) { | |
17 | + logger.warn('Can not connect to oracle db: ' + err); | |
18 | + process.exit(1); | |
19 | + } | |
20 | + | |
21 | + oraCon = connection; | |
22 | + logger.info("Oracle db connected") | |
23 | + | |
24 | + if (callback) { | |
25 | + callback(null, oraCon); | |
26 | + } | |
27 | + }) | |
28 | +} | |
29 | + | |
30 | +function getTransactionIdFromMessage(message) { | |
31 | + try { | |
32 | + var matches = message.match(/ID=(\d+)/); | |
33 | + return matches[1]; | |
34 | + } | |
35 | + catch(err) { | |
36 | + return '0'; | |
37 | + } | |
38 | +} | |
39 | + | |
40 | +function getReverseUrl(msisdn, callback) { | |
41 | + oraCon.execute( | |
42 | + "SELECT trim(A.MSISDN) MSISDN, trim(B.REVERSE_URL) REVERSE_URL FROM T_STORE_USER_MSISDN A, T_STORE_USER B WHERE A.STORE_ID = B.STORE_ID AND A.USER_NAME = B.USER_NAME AND B.REVERSE_URL IS NOT NULL AND A.MSISDN = :msisdn", | |
43 | + [msisdn], | |
44 | + function(err, result) { | |
45 | + if (err) { | |
46 | + logger.warn('Error retrieving reverse url from oracle: ' + err); | |
47 | + callback(err); | |
48 | + return; | |
49 | + } | |
50 | + | |
51 | + var rowCount = result.rows.length; | |
52 | + | |
53 | + var retval = []; | |
54 | + for (var i = 0; i < rowCount; i++) { | |
55 | + retval.push(result.rows[i][1]); | |
56 | + } | |
57 | + | |
58 | + callback(null, retval); | |
59 | + } | |
60 | + ); | |
61 | +} | |
62 | + | |
63 | +function getRequestIdFromResponseMessage(message) { | |
64 | + try { | |
65 | + var tokens = message.split('.'); | |
66 | + return tokens[4]; | |
67 | + } | |
68 | + catch(err) { | |
69 | + return; | |
70 | + } | |
71 | + | |
72 | +} | |
73 | + | |
74 | +exports.init = init; | |
75 | +exports.connectToOracle = connectToOracle; | |
76 | +exports.getReverseUrl = getReverseUrl; | |
77 | +exports.getTransactionIdFromMessage = getTransactionIdFromMessage; | |
78 | +exports.getRequestIdFromResponseMessage = getRequestIdFromResponseMessage; |
package.json
... | ... | @@ -0,0 +1,35 @@ |
1 | +{ | |
2 | + "name": "sate24-neoxmlin", | |
3 | + "version": "1.0.0", | |
4 | + "description": "Drop-in replacement for ST24 XML-RPC in", | |
5 | + "main": "index.js", | |
6 | + "scripts": { | |
7 | + "test": "mocha" | |
8 | + }, | |
9 | + "repository": { | |
10 | + "type": "git", | |
11 | + "url": "git@gitlab.kodesumber.com:reload97/sate24-neoxmlin.git" | |
12 | + }, | |
13 | + "keywords": [ | |
14 | + "r97", | |
15 | + "reload97", | |
16 | + "st24", | |
17 | + "ppob", | |
18 | + "xmlrpc", | |
19 | + "xmlin" | |
20 | + ], | |
21 | + "author": "Adhidarma Hadiwinoto <me@adhisimon.org>", | |
22 | + "license": "ISC", | |
23 | + "dependencies": { | |
24 | + "oracledb": "^1.9.3", | |
25 | + "request": "^2.72.0", | |
26 | + "strftime": "^0.9.2", | |
27 | + "winston": "^2.2.0", | |
28 | + "winston-daily-rotate-file": "^1.1.1", | |
29 | + "xml2js": "^0.4.16", | |
30 | + "xmlrpc": "^1.3.1" | |
31 | + }, | |
32 | + "devDependencies": { | |
33 | + "should": "^9.0.0" | |
34 | + } | |
35 | +} |
server.crt
... | ... | @@ -0,0 +1,24 @@ |
1 | +-----BEGIN CERTIFICATE----- | |
2 | +MIID8zCCAtugAwIBAgIJAN0ti6ihYyvqMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD | |
3 | +VQQGEwJJRDEUMBIGA1UECAwLREtJIEpha2FydGExFjAUBgNVBAcMDUpha2FydGEg | |
4 | +UHVzYXQxETAPBgNVBAoMCFJlbG9hZDk3MRswGQYDVQQDDBJ4bWxpbi5yZWxvYWQ5 | |
5 | +Ny5jb20xIjAgBgkqhkiG9w0BCQEWE2FkaGlzaW1vbkBnbWFpbC5jb20wHhcNMTYw | |
6 | +NjAxMTMyMDUzWhcNMjYwNTMwMTMyMDUzWjCBjzELMAkGA1UEBhMCSUQxFDASBgNV | |
7 | +BAgMC0RLSSBKYWthcnRhMRYwFAYDVQQHDA1KYWthcnRhIFB1c2F0MREwDwYDVQQK | |
8 | +DAhSZWxvYWQ5NzEbMBkGA1UEAwwSeG1saW4ucmVsb2FkOTcuY29tMSIwIAYJKoZI | |
9 | +hvcNAQkBFhNhZGhpc2ltb25AZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOC | |
10 | +AQ8AMIIBCgKCAQEA3kmctiCOWifW4FAJlvvK888LaZ7k5kTsBma+5D8THIhQiW2c | |
11 | +TNZhSiOFalgTFv2ICTpq/SJ81+v3Im8Lv+Y3MCWLvu5MkLYyrX/AJYq55dmn64WI | |
12 | +Mx+dHUJSuZ/IxOUVIVGwJ9RW8FpkwnUvEPg5hZG+B0sVJhbxKTuiTSqWRuT7DWGe | |
13 | +dG1ejnGYpQOM9H6+eF1sHAAGYQ7mqhD/kaDtPilpGNWe/ugfzoqok/L3D1uExMzA | |
14 | +ovoG0XgIN0f/JvSkhGV+4TblvPQ6HN+VWlkMJ9jLGXEGX/dqKk0wT9hgUPm4Erpj | |
15 | +Oeul3Gk5/bs50nMJotIQ2hxEsIY0IYD0yyY2HwIDAQABo1AwTjAdBgNVHQ4EFgQU | |
16 | +po0uWeWkrCwFIZE7KKUSZRUFKF4wHwYDVR0jBBgwFoAUpo0uWeWkrCwFIZE7KKUS | |
17 | +ZRUFKF4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAITnQYHKxZ+ZI | |
18 | +Ug3npsC+E6hsEXi8SuV9gO/PBpEITR+oJd6vNTmdiFtEqWPGZm0+Jbdi7/UsIIg1 | |
19 | +b5kYLuCFpf+h6ulv94Na8aIOPdpoH0V7vrWZ6zSw7jUDZcFwiSEfsmozpXaspE3p | |
20 | +mESbXndBuP8lweUg4dBS4/+Dlqm0GLtacoLBuKlPqraOVAlVTy4JqxvOy0RlX/47 | |
21 | +FldEIc8bhNIgYiJjnYnsQstNLtk9mvJ3eg0qy174JbE8Ls6hiitx1fI8gUq1wbmM | |
22 | +AtMt2xZic/U4xZuTf6SXF3ogBg5C9xkHn2gb7NCuMEAyCU+NYAR7NtNwRuqXWeHI | |
23 | +r8U0aGtxeg== | |
24 | +-----END CERTIFICATE----- |
server.key
... | ... | @@ -0,0 +1,28 @@ |
1 | +-----BEGIN PRIVATE KEY----- | |
2 | +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDeSZy2II5aJ9bg | |
3 | +UAmW+8rzzwtpnuTmROwGZr7kPxMciFCJbZxM1mFKI4VqWBMW/YgJOmr9InzX6/ci | |
4 | +bwu/5jcwJYu+7kyQtjKtf8Alirnl2afrhYgzH50dQlK5n8jE5RUhUbAn1FbwWmTC | |
5 | +dS8Q+DmFkb4HSxUmFvEpO6JNKpZG5PsNYZ50bV6OcZilA4z0fr54XWwcAAZhDuaq | |
6 | +EP+RoO0+KWkY1Z7+6B/OiqiT8vcPW4TEzMCi+gbReAg3R/8m9KSEZX7hNuW89Doc | |
7 | +35VaWQwn2MsZcQZf92oqTTBP2GBQ+bgSumM566XcaTn9uznScwmi0hDaHESwhjQh | |
8 | +gPTLJjYfAgMBAAECggEAA+85nt+kpWPfIclI4itCxF39zbjKRGkj5FkdN90F8ZNY | |
9 | +GZafFZ0Vy8IlMmSssdN6/O7Txfc+TnQWw71Db/obL/b6Kj79i/Ito3SHaiKyd6cK | |
10 | +mdibOIxus33hCPgTDakgXp6bh5jykP6ImgiI9LvwCLUzr91cWng9fIVZshP25PpQ | |
11 | +I/dI+2fhL+f+QB3QJEMDyz2b7KR3i4IbX8gHUUcT83JPnqZ07lED1gqAUIuSwbDz | |
12 | +kskxVPm8AGOiQ/f1sCbrAyetGy3nZ0N51RvRgFOREyb+SnmKI86GtgwEo5kCAzip | |
13 | +D4Xy+GCHMUennnHOzcLwthEn1FFk3Xww2CbjmQPKQQKBgQD3c8dgY13gjaUVREru | |
14 | +aSoUv6sZWRbXYK/MhBrUyt0VgpISEgG2zXTgwPuYVJofJVUZB6QVAgiGKiKySHwN | |
15 | +zYd8sQAtiKjUQIEUr2uVO/l+uSwSnBCdI85+Rxt1a9PxM4JDs6e7HYn4N7UowBoJ | |
16 | +PofnE8X2mptZTRmNX3EDJC5lEwKBgQDl9007tRA+fePfKRfmePqb+3oC0PLaQxi6 | |
17 | +ZMTudefDwUVzEBRw2aCsuS5Sqi+CAeyKsYORjNiR1xUw8dYrljP17wz7+I1/ksQe | |
18 | +PIl+Ujhm36cbCOPOdIJoOt4ocAMyJ3hGbWph3A0HSSagqsbfdYUScmMTvlnRJynu | |
19 | +L5VLtv4oRQKBgFdwbAVdV3Df3HO1XBz+wEXwrI8acf3NRpGoJKsIvDK7ns4P2tcz | |
20 | +ppc82iqryoIy+O0NTCe4PjbacMQ65Msj0zp2eS+d2LqXyIT8r7FeLf1fhXlV+HDu | |
21 | +lCr/CW7mmU/j+aXet+hgub4iQTuTFiAqHm/DBvLrEvXtTpgsH40SnepNAoGActV5 | |
22 | +NbWGtQ38OjW0/5ut2TJMjRd2DdOvh3RGeqVZ5ICgg4KmEmw6NcYLAbCGJK99RQy7 | |
23 | +nHTuuHTk2hoJTp6kt8x1eWV2kxvg3xBvwCqii4xnT7Kyvyei7xVmVl8I2YSoJNMC | |
24 | +aneN8fNvXI+q22890iZYn0VQaIbcA1qzfKmWZNkCgYEA0PYfpPUoEdkqzW+SqKb/ | |
25 | +8ky8qkuYMYC0toHI2lGQZIomZ6RWXd8OVn9UeM5CTtP+n4IzZHQBAu5Qxvss/S2T | |
26 | +TAdpb/ILx3dK8Px1lUc5a0cf7mDL39nSWp9rmD1qoRVM1Wr0jeQ80jQXMZluAIjt | |
27 | +KbMtcoO4E/22+apAg33FRmE= | |
28 | +-----END PRIVATE KEY----- |
test.js
... | ... | @@ -0,0 +1,24 @@ |
1 | +var should = require('should'); | |
2 | +var neoxmlinutil = require('./neoxmlinutil'); | |
3 | + | |
4 | +describe('#neoxmlinutil', function() { | |
5 | + | |
6 | + before(function(ready) { | |
7 | + neoxmlinutil.connectToOracle(ready); | |
8 | + }) | |
9 | + | |
10 | + | |
11 | + it ('#should return correct transaction id', function() { | |
12 | + var message = 'SN=4786-4311-9060-7286-2722/RAJUDIN/R1/1300VA/13.7;31/05/16 12:10 ISI PLN20 KE 45008590213, BERHASIL.SAL=54.283.173,HRG=19.950,ID=2565605,SN=4786-4311-9060-7286-2722/RAJUDIN/R1/1300VA/13.7; -- Telkomsel Nasional kode S denom 5000 harga 5300 silahkan'; | |
13 | + neoxmlinutil.getTransactionIdFromMessage(message).should.equal('2565605'); | |
14 | + }) | |
15 | + | |
16 | + it ('#should return correct reverse url', function(done) { | |
17 | + | |
18 | + neoxmlinutil.getReverseUrl('R97DEV', function(err, result) { | |
19 | + result.should.not.be.empty(); | |
20 | + done(); | |
21 | + }) | |
22 | + | |
23 | + }) | |
24 | +}) |
xmlrpc-server.js
... | ... | @@ -0,0 +1,360 @@ |
1 | +var xmlrpc = require('xmlrpc'); | |
2 | +var request = require('request'); | |
3 | +var neoxmlinutil = require('./neoxmlinutil'); | |
4 | +var http = require('http'); | |
5 | +var https = require('https'); | |
6 | +var fs = require('fs'); | |
7 | +var xml2js = new require('xml2js'); | |
8 | +var xml2jsParser = require('xml2js').parseString; | |
9 | +var xml2jsBuilder = new xml2js.Builder(); | |
10 | +var url = require("url"); | |
11 | +var strftime = require('strftime'); | |
12 | + | |
13 | +var options; | |
14 | +var config; | |
15 | +var logger; | |
16 | + | |
17 | +var server; | |
18 | + | |
19 | +function start(_options) { | |
20 | + options = _options; | |
21 | + | |
22 | + if (options.config) { | |
23 | + config = options.config; | |
24 | + } | |
25 | + else { | |
26 | + config = require("./config.json"); | |
27 | + } | |
28 | + | |
29 | + if (options.logger) { | |
30 | + logger = options.logger; | |
31 | + } | |
32 | + else { | |
33 | + logger = console; | |
34 | + } | |
35 | + | |
36 | + createResponseServer(); | |
37 | + | |
38 | + createDiyHttpXmlRpcServer(); | |
39 | + //createXmlRpcServer() | |
40 | + //createExpressXmlRpcServer(); | |
41 | +} | |
42 | + | |
43 | +function createXmlRpcServer() { | |
44 | + var server = xmlrpc.createServer(config.server_options); | |
45 | + logger.info("Server listening on port " + config.server_options.port); | |
46 | + | |
47 | + server.on('NotFound', function(method, params) { | |
48 | + logger.warn('Method ' + method + ' does not exist'); | |
49 | + }); | |
50 | + | |
51 | + server.on('topUpRequest', onTopUpRequest); | |
52 | + //server.on('topUpInquiry', onTopUpInquiry); | |
53 | +} | |
54 | + | |
55 | +function getXmlRpcParam(values) { | |
56 | + try { | |
57 | + | |
58 | + var count = values.length | |
59 | + var result = {}; | |
60 | + for (var i = 0; i < count; i++) { | |
61 | + var value = values[i]; | |
62 | + | |
63 | + var keys = Object.keys(value.value[0]); | |
64 | + var firstKey = keys[0]; | |
65 | + result[value.name[0]] = value.value[0][firstKey][0]; | |
66 | + } | |
67 | + | |
68 | + return result; | |
69 | + | |
70 | + } | |
71 | + catch(err) { | |
72 | + return null; | |
73 | + } | |
74 | +} | |
75 | + | |
76 | +function createDiyHttpXmlRpcServer() { | |
77 | + var serverOptions = { | |
78 | + key: fs.readFileSync('./server.key'), | |
79 | + cert: fs.readFileSync('./server.crt') | |
80 | + } | |
81 | + | |
82 | + var httpServer = https.createServer(serverOptions, function(req, res) { | |
83 | + | |
84 | + var body = ""; | |
85 | + req.on('data', function (chunk) { | |
86 | + body += chunk; | |
87 | + }); | |
88 | + | |
89 | + req.on('end', function () { | |
90 | + | |
91 | + xml2jsParser(body, function(err, message) { | |
92 | + | |
93 | + if (err) { | |
94 | + res.end('Unknown xml'); | |
95 | + return; | |
96 | + } | |
97 | + | |
98 | + var method; | |
99 | + var _params; | |
100 | + | |
101 | + try { | |
102 | + method = message.methodCall.methodName[0]; | |
103 | + _params = message.methodCall.params[0].param[0].value[0].struct[0].member; | |
104 | + } | |
105 | + catch(errSelectMethod) { | |
106 | + logger.warn('Failed to get method and _params'); | |
107 | + res.end('Invalid') | |
108 | + return; | |
109 | + } | |
110 | + | |
111 | + params = getXmlRpcParam(_params); | |
112 | + | |
113 | + immediateReply(params, function(errReply, data) { | |
114 | + var responseBody = composeXmlRpcResponse(data) | |
115 | + logger.info(responseBody); | |
116 | + | |
117 | + res.writeHead(200, {'Content-Type': 'text/xml'}); | |
118 | + res.end(responseBody); | |
119 | + }); | |
120 | + | |
121 | + sendToMaster(params, req.connection.remoteAddress); | |
122 | + | |
123 | + }) | |
124 | + }); | |
125 | + | |
126 | + }); | |
127 | + | |
128 | + httpServer.listen(config.server_options.port, function() { | |
129 | + logger.info('HTTP XMLRPC listen on port ' + config.server_options.port); | |
130 | + }); | |
131 | +} | |
132 | + | |
133 | +function composeXmlRpcResponse(param) { | |
134 | + | |
135 | + var values = []; | |
136 | + var keys = Object.keys(param); | |
137 | + var keysCount = keys.length; | |
138 | + | |
139 | + for (var i = 0; i < keysCount; i++) { | |
140 | + var key = keys[i]; | |
141 | + var value = { | |
142 | + name: key, | |
143 | + value: { | |
144 | + string: param[key] | |
145 | + } | |
146 | + } | |
147 | + values.push(value); | |
148 | + } | |
149 | + | |
150 | + var data = { | |
151 | + methodResponse: { | |
152 | + params: { | |
153 | + param: { | |
154 | + value: { | |
155 | + struct: { | |
156 | + member: values | |
157 | + } | |
158 | + } | |
159 | + } | |
160 | + } | |
161 | + } | |
162 | + } | |
163 | + | |
164 | + logger.info(JSON.stringify(data)); | |
165 | + | |
166 | + return xml2jsBuilder.buildObject(data); | |
167 | +} | |
168 | + | |
169 | +function immediateReply(param, callback) { | |
170 | + var message = 'ISI ' | |
171 | + + param.NOM | |
172 | + + ' KE ' | |
173 | + + param.NOHP | |
174 | + + ', Transaksi anda sedang diproses' | |
175 | + | |
176 | + var trxId = neoxmlinutil.getTransactionIdFromMessage(message); | |
177 | + | |
178 | + var response = { | |
179 | + 'RESPONSECODE': '68', | |
180 | + 'REQUESTID': param.REQUESTID, | |
181 | + 'MESSAGE': message, | |
182 | + 'TRANSACTIONID': trxId, | |
183 | + } | |
184 | + | |
185 | + //logger.info(response); | |
186 | + callback(null, response); | |
187 | +} | |
188 | + | |
189 | +function onTopUpRequest(err, params, callback) { | |
190 | + logger.info('METHOD: topUpRequest'); | |
191 | + logger.info(JSON.stringify(params)); | |
192 | + | |
193 | + if (config.immediate_reply) { | |
194 | + immediateReply(params[0], callback); | |
195 | + } | |
196 | + else { | |
197 | + callback(); | |
198 | + } | |
199 | +} | |
200 | + | |
201 | +function onTopUpInquiry(err, params, callback) { | |
202 | + callback(); | |
203 | +} | |
204 | + | |
205 | +function composeMessage(params, remoteAddress) { | |
206 | + try { | |
207 | + var nom = params.NOM.replace(/\./g, '').trim(); | |
208 | + var destination = params.NOHP.replace(/\./g, '').trim(); | |
209 | + var pin = params.PIN.replace(/\./g, '').trim(); | |
210 | + var requestId = params.REQUESTID.replace(/\./g, '').trim(); | |
211 | + | |
212 | + return 'MI.' + nom + '."' + destination + '".' + pin + '.' + requestId + '.NOTRUST."' + remoteAddress + '"'; | |
213 | + } | |
214 | + catch(err) { | |
215 | + return; | |
216 | + } | |
217 | + | |
218 | + | |
219 | +} | |
220 | + | |
221 | +function sendToMaster(param, remoteAddress) { | |
222 | + | |
223 | + /* | |
224 | + var smscidSuffix = '99999999999999' + String(Math.round(Math.random() * 99999999999999)); | |
225 | + var smscid = 'XML1' + smscidSuffix.slice(-13); | |
226 | + */ | |
227 | + | |
228 | + //var smscid = 'XML' + '12345' + strftime('%H%M%S%L'); | |
229 | + var smscid = config.smscid;// + Math.round(Math.random() * 9999999999999); | |
230 | + | |
231 | + var message = composeMessage(param, remoteAddress); | |
232 | + if (!message) { | |
233 | + logger.warn('Invalid parameter'); | |
234 | + return; | |
235 | + } | |
236 | + | |
237 | + var requestOpts = { | |
238 | + url: config.master_url, | |
239 | + qs: { | |
240 | + PhoneNumber: param.MSISDN, | |
241 | + 'Text': message, | |
242 | + Res_Port: config.res_port, | |
243 | + Smscid: smscid | |
244 | + } | |
245 | + }; | |
246 | + | |
247 | + logger.info(requestOpts); | |
248 | + request(requestOpts, function(err, response, body) { | |
249 | + if (err) { | |
250 | + logger.warn('Failed to contact master: ' + err); | |
251 | + setTimeout(sendToMaster, 2000, param, remoteAddress); | |
252 | + return; | |
253 | + } | |
254 | + | |
255 | + logger.info(body); | |
256 | + }) | |
257 | + | |
258 | +} | |
259 | + | |
260 | +function sendReply(response) { | |
261 | + var requestId = neoxmlinutil.getRequestIdFromResponseMessage(response.text); | |
262 | + | |
263 | + if (!requestId) { | |
264 | + logger.warn('No request id found, skipping'); | |
265 | + return; | |
266 | + } | |
267 | + | |
268 | + var params = { | |
269 | + REQUESTID: requestId, | |
270 | + RESPONSECODE: response.resp_code, | |
271 | + MESSAGE: response.text, | |
272 | + } | |
273 | + | |
274 | + logger.info('PARAMS:'); | |
275 | + logger.info(params); | |
276 | + | |
277 | + neoxmlinutil.getReverseUrl(response.PhoneNumber, function(err, reverseUrls) { | |
278 | + if (err) { | |
279 | + logger.warn('Fail to get reverse urls, skipping'); | |
280 | + return; | |
281 | + } | |
282 | + | |
283 | + if (reverseUrls.length <= 0) { | |
284 | + logger.warn('No reverse urls found, skipping'); | |
285 | + return; | |
286 | + } | |
287 | + | |
288 | + sendTopUpReport(reverseUrls, params, 0, 4); | |
289 | + }); | |
290 | +} | |
291 | + | |
292 | +function sendTopUpReport(reverseUrls, params, urlIdx, retry) { | |
293 | + if (retry === null || retry === undefined) { | |
294 | + retry = 4; | |
295 | + } | |
296 | + | |
297 | + if (urlIdx === null || urlIdx === undefined) { | |
298 | + urlIdx = 0; | |
299 | + } | |
300 | + | |
301 | + if (urlIdx >= reverseUrls.length) { | |
302 | + if (retry) { | |
303 | + logger.info('Retrying to send topUpReport to partner'); | |
304 | + setTimeout( | |
305 | + sendTopUpReport, | |
306 | + 10000, | |
307 | + reverseUrls, 0, --retry | |
308 | + ) | |
309 | + return; | |
310 | + } | |
311 | + else { | |
312 | + logger.warn('topUpReport retry exceed'); | |
313 | + } | |
314 | + } | |
315 | + | |
316 | + var partnerUrl = url.parse(reverseUrls[urlIdx]); | |
317 | + | |
318 | + var clientOptions = { | |
319 | + host: partnerUrl.hostname | |
320 | + , port: partnerUrl.port | |
321 | + , path: partnerUrl.pathname | |
322 | + }; | |
323 | + logger.info(clientOptions); | |
324 | + | |
325 | + var client; | |
326 | + if (partnerUrl.protocol == 'https:') { | |
327 | + client = xmlrpc.createSecureClient(clientOptions); | |
328 | + } else { | |
329 | + client = xmlrpc.createClient(clientOptions); | |
330 | + } | |
331 | + | |
332 | + var methodName = 'topUpReport'; | |
333 | + logger.info(params); | |
334 | + client.methodCall(methodName, [ params ], function (error, value) { | |
335 | + if (!error) { | |
336 | + return; | |
337 | + } | |
338 | + | |
339 | + sendTopUpReport(reverseUrls, ++urlIdx, retry) | |
340 | + }); | |
341 | +} | |
342 | + | |
343 | +function createResponseServer() { | |
344 | + var httpServer = http.createServer(function(req, res) { | |
345 | + | |
346 | + res.end(); | |
347 | + | |
348 | + var parsed_url = url.parse(req.url, true, true); | |
349 | + logger.info(parsed_url.query); | |
350 | + | |
351 | + sendReply(parsed_url.query); | |
352 | + | |
353 | + }); | |
354 | + | |
355 | + httpServer.listen(config.res_port, function() { | |
356 | + logger.info('HTTP Response server listen on port ' + config.res_port); | |
357 | + }); | |
358 | +} | |
359 | + | |
360 | +exports.start = start; |