Compare View

switch
from
...
to
 
Commits (4)

Changes

Showing 3 changed files Inline Diff

center/messaging/trx-center.js
1 "use strict"; 1 "use strict";
2 2
3 /** 3 /**
4 * Trx Handler untuk center messaging 4 * Trx Handler untuk center messaging
5 */ 5 */
6 6
7 const path = require('path'); 7 const path = require('path');
8 const request = require('request'); 8 const request = require('request');
9 const strftime = require('strftime'); 9 const strftime = require('strftime');
10 const config = require('../../config'); 10 const config = require('../../config');
11 const logger = require('../../logger'); 11 const logger = require('../../logger');
12 const httpResponseServer = require('../http-response-server'); 12 const httpResponseServer = require('../http-response-server');
13 const controlPanel = require('../../control-panel'); 13 const controlPanel = require('../../control-panel');
14 14
15 const module_name = path.basename(__filename); 15 const module_name = path.basename(__filename);
16 16
17 let transport; 17 let transport;
18 18
19 function onOnline(params) { 19 function onOnline(params) {
20 logger.info('CENTER is ONLINE, ready to communicate'); 20 logger.info('CENTER is ONLINE, ready to communicate');
21 21
22 } 22 }
23 23
24 function onIncomingMessage(paramsFromTransport, cb) { 24 function onIncomingMessage(paramsFromTransport, cb) {
25 logger.verbose('Reporting message to CORE') 25 logger.verbose('Reporting message to CORE')
26 26
27 const command = paramsFromTransport.msg.split(/[\., ]+/)[0].toUpperCase(); 27 const command = paramsFromTransport.msg.split(/[\., ]+/)[0].toUpperCase();
28 28
29 if (config.commands && config.commands.balance && config.commands.balance.indexOf(command) >= 0) { 29 if (config.commands && config.commands.balance && config.commands.balance.indexOf(command) >= 0) {
30 executeBalanceCheck(paramsFromTransport, cb); 30 executeBalanceCheck(paramsFromTransport, cb);
31 } 31 }
32 else if (config.commands && config.commands.price && config.commands.price.indexOf(command) >= 0) { 32 else if (config.commands && config.commands.price && config.commands.price.indexOf(command) >= 0) {
33 executePriceCheck(paramsFromTransport, cb); 33 executePriceCheck(paramsFromTransport, cb);
34 } 34 }
35 else if (config.commands && config.commands.postpaid_inquiry && config.commands.postpaid_inquiry.indexOf(command) >= 0) {
36
37 }
38 else if (config.commands && config.commands.postpaid_pay && config.commands.postpaid_pay.indexOf(command) >= 0) {
39
40 }
35 else if (config.commands && config.commands.postpaid_inquiry && config.commands.postpaid_inquiry.indexOf(command) >= 0) { 41 else {
36 42 executePrepaidBuy(paramsFromTransport, cb);
37 } 43 }
38 else if (config.commands && config.commands.postpaid_pay && config.commands.postpaid_pay.indexOf(command) >= 0) { 44 }
39 45
40 } 46 function executeBalanceCheck(paramsFromTransport) {
41 else { 47 const terminal_name = paramsFromTransport.partner.toLowerCase();
42 executePrepaidBuy(paramsFromTransport, cb); 48 const password = paramsFromTransport.msg.trim().split(/[\., ]+/)[1];
43 } 49
44 } 50 const requestOptions = {
45 51 url: config.core_url + '/services/balance',
46 function executeBalanceCheck(paramsFromTransport) { 52 qs: {
47 const terminal_name = paramsFromTransport.partner.toLowerCase(); 53 terminal_name: terminal_name,
48 const password = paramsFromTransport.msg.trim().split(/[\., ]+/)[1]; 54 password: password
49 55 }
50 const requestOptions = { 56 }
51 url: config.core_url + '/services/balance', 57
52 qs: { 58 requestToCore(requestOptions);
53 terminal_name: terminal_name, 59 }
54 password: password 60
55 } 61 function executePriceCheck(paramsFromTransport) {
56 } 62 const requestOptions = {
57 63 url: config.core_url + '/services/pricelist',
58 requestToCore(requestOptions); 64 qs: {
59 } 65 terminal_name: paramsFromTransport.partner.toLowerCase(),
60 66 keyword: paramsFromTransport.msg.trim().split(/[\., ]+/)[1],
61 function executePriceCheck(paramsFromTransport) { 67 password: paramsFromTransport.msg.trim().split(/[\., ]+/)[2],
62 const requestOptions = { 68 postpaid: 0,
63 url: config.core_url + '/services/pricelist', 69 }
64 qs: { 70 }
65 terminal_name: paramsFromTransport.partner.toLowerCase(), 71
66 keyword: paramsFromTransport.msg.trim().split(/[\., ]+/)[1], 72 requestToCore(requestOptions);
67 password: paramsFromTransport.msg.trim().split(/[\., ]+/)[2], 73 }
68 postpaid: 0, 74
69 } 75 function parseCoreMessage(body) {
70 } 76 let coreRes;
71 77
72 requestToCore(requestOptions); 78 try {
73 } 79 coreRes = JSON.parse(body)
74 80 }
75 function parseCoreMessage(body) { 81 catch(err) {
76 let coreRes; 82 logger.warn('Exception on parsing CORE response as JSON', {body: body, err: err});
77 83 coreRes = null;
78 try { 84 }
79 coreRes = JSON.parse(body) 85
80 } 86 return coreRes;
81 catch(err) { 87 }
82 logger.warn('Exception on parsing CORE response as JSON', {body: body, err: err}); 88
83 coreRes = null; 89 function generateRequestId(req) {
84 } 90 return 'AUTO_' + req.product_name + '_' + req.destination + '_' + strftime('%Y%m%d');
85 91 }
86 return coreRes; 92
87 } 93 function executePrepaidBuy(paramsFromTransport, cb) {
88 94 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/);
89 function generateRequestId(req) { 95
90 return 'AUTO_' + req.product_name + '_' + req.destination + '_' + strftime('%Y%m%d'); 96 let qs = {
91 } 97 request_id: tokens[3],
92 98 terminal_name: paramsFromTransport.partner.toLowerCase(),
93 function executePrepaidBuy(paramsFromTransport, cb) { 99 product_name: tokens[0].toUpperCase(),
94 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/); 100 destination: tokens[1].toUpperCase(),
95 101 password: tokens[2],
96 let qs = { 102 origin: config.origin || config.username,
97 request_id: tokens[3], 103 report_port: config.listen_port || '80',
98 terminal_name: paramsFromTransport.partner.toLowerCase(), 104 msg: paramsFromTransport.msg,
99 product_name: tokens[0].toUpperCase(), 105 reverse_url: paramsFromTransport.reverse_url
100 destination: tokens[1].toUpperCase(), 106 }
101 password: tokens[2], 107
102 origin: config.origin || config.username, 108 if (!config.do_not_prefix_request_id) {
103 report_port: config.listen_port || '80', 109 qs.request_id = generateRequestId(qs);
104 msg: paramsFromTransport.msg, 110 if (tokens[3]) {
105 reverse_url: paramsFromTransport.reverse_url 111 qs.request_id += '_' + tokens[3];
106 } 112 }
107 113 }
108 if (!config.do_not_prefix_request_id) { 114
109 qs.request_id = generateRequestId(qs); 115 let requestOptions = {
110 if (tokens[3]) { 116 url: config.core_url + '/prepaid/buy',
111 qs.request_id += '_' + tokens[3]; 117 qs: qs
112 } 118 }
113 } 119
114 120 requestToCore(requestOptions, cb);
115 let requestOptions = { 121 }
116 url: config.core_url + '/prepaid/buy', 122
123 function executePostpaidInquiry(paramsFromTransport, cb) {
124 // PAY.PLN.1234567890.PIN
125
126 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/);
127
128 let qs = {
129 request_id: tokens[4],
130 terminal_name: paramsFromTransport.partner.toLowerCase(),
131 product_name: tokens[1].toUpperCase(),
132 destination: tokens[2].toUpperCase(),
133 password: tokens[3],
134 origin: config.origin || config.username,
135 report_port: config.listen_port || '80',
136 msg: paramsFromTransport.msg,
137 reverse_url: paramsFromTransport.reverse_url
138 }
139
140 if (!config.do_not_prefix_request_id) {
141 qs.request_id = generateRequestId(qs);
142 if (tokens[3]) {
143 qs.request_id += '_' + tokens[3];
144 }
145 }
146
147 let requestOptions = {
148 url: config.core_url + '/postpaid/pay',
149 qs: qs
150 }
151
152 requestToCore(requestOptions, cb);
153 }
154
155 function executePostpaidPay(paramsFromTransport, cb) {
156 // INQUIRY.PLN.1234567890.PIN
157
158 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/);
159
160 let qs = {
161 request_id: tokens[4],
162 terminal_name: paramsFromTransport.partner.toLowerCase(),
163 product_name: tokens[1].toUpperCase(),
164 destination: tokens[2].toUpperCase(),
165 password: tokens[3],
166 origin: config.origin || config.username,
167 report_port: config.listen_port || '80',
168 msg: paramsFromTransport.msg,
169 reverse_url: paramsFromTransport.reverse_url
170 }
171
172 if (!config.do_not_prefix_request_id) {
173 qs.request_id = generateRequestId(qs);
174 if (tokens[3]) {
175 qs.request_id += '_' + tokens[3];
176 }
177 }
178
179 let requestOptions = {
180 url: config.core_url + '/postpaid/inquiry',
181 qs: qs
182 }
183
184 requestToCore(requestOptions, cb);
185 }
186
117 qs: qs 187 function requestToCore(requestOptions, cb) {
118 } 188 logger.verbose('Requesting service to CORE', requestOptions);
119 189
120 requestToCore(requestOptions, cb); 190 request(requestOptions, function(err, res, body) {
121 } 191 if (err || res.statusCode != 200) {
122 192 logger.warn('Error requesting to CORE', {module_name: module_name, method_name: 'requestToCore', requestOptions: requestOptions, err: err});
123 function executePostpaidInquiry(paramsFromTransport, cb) { 193 if (cb) {
124 // PAY.PLN.1234567890.PIN 194 cb(null, {msg: 'INTERNAL ERROR'});
125 195 }
126 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/); 196 else if (transport.send) {
127 197 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR');
128 let qs = { 198 }
129 request_id: tokens[4], 199 return;
130 terminal_name: paramsFromTransport.partner.toLowerCase(), 200 }
131 product_name: tokens[1].toUpperCase(), 201
132 destination: tokens[2].toUpperCase(), 202 let result = parseCoreMessage(body);
133 password: tokens[3], 203 if (!result || !result.message) {
134 origin: config.origin || config.username, 204 if (cb) {
135 report_port: config.listen_port || '80', 205 cb(null, {msg: 'INTERNAL ERROR'});
136 msg: paramsFromTransport.msg, 206 }
137 reverse_url: paramsFromTransport.reverse_url 207 else if (transport.send) {
138 } 208 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR');
139 209 }
140 if (!config.do_not_prefix_request_id) { 210 return;
141 qs.request_id = generateRequestId(qs); 211 }
142 if (tokens[3]) { 212
143 qs.request_id += '_' + tokens[3]; 213 if (cb) {
144 } 214 cb(null, result);
145 } 215 }
146 216 else if (transport.send) {
147 let requestOptions = { 217 transport.send(requestOptions.qs.terminal_name, result.message);
148 url: config.core_url + '/postpaid/pay', 218
149 qs: qs 219 }
150 } 220 })
151 221 }
152 requestToCore(requestOptions, cb); 222
153 } 223 function setTransport(_transport) {
154 224 transport = _transport;
155 function executePostpaidPay(paramsFromTransport, cb) { 225 httpResponseServer.setTransport(transport);
156 // INQUIRY.PLN.1234567890.PIN 226 }
157 227
158 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/); 228 const callback = {
159 229 onOnline: onOnline,
160 let qs = { 230 onIncomingMessage: onIncomingMessage
161 request_id: tokens[4], 231 }
162 terminal_name: paramsFromTransport.partner.toLowerCase(), 232
163 product_name: tokens[1].toUpperCase(), 233 exports.callback = callback;
164 destination: tokens[2].toUpperCase(), 234 exports.setTransport = setTransport;
165 password: tokens[3], 235
1 "use strict"; 1 "use strict";
2 2
3 const request = require('request'); 3 const request = require('request');
4 4
5 const config = require('../config'); 5 const config = require('../config');
6 const logger = require('../logger'); 6 const logger = require('../logger');
7 const matrix = require('../matrix'); 7 const matrix = require('../matrix');
8 const controlPanel = require('../control-panel'); 8 const controlPanel = require('../control-panel');
9 const heartbeat = require('../heartbeat'); 9 const heartbeat = require('../heartbeat');
10 10
11 heartbeat.setModuleType('gateway'); 11 heartbeat.setModuleType('gateway');
12 12
13 var partner; 13 var partner;
14 14
15 function setPartner(_partner) { 15 function setPartner(_partner) {
16 partner = _partner; 16 partner = _partner;
17 } 17 }
18 18
19 function pullTask() { 19 function pullTask() {
20 if (!partner) { 20 if (!partner) {
21 return; 21 return;
22 } 22 }
23 23
24 let core_pull_task_url; 24 let core_pull_task_url;
25 25
26 if (config.core_url) { 26 if (config.core_url) {
27 core_pull_task_url = config.core_url + '/pull/task'; 27 core_pull_task_url = config.core_url + '/pull/task';
28 } else if (config.pull_url.task) { 28 } else if (config.pull_url.task) {
29 core_pull_task_url = config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey); 29 core_pull_task_url = config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey);
30 } 30 }
31 31
32 if (!core_pull_task_url) { 32 if (!core_pull_task_url) {
33 logger.warn('Unknown CORE task url'); 33 logger.warn('Unknown CORE task url');
34 return; 34 return;
35 } 35 }
36 36
37 let options = { 37 let options = {
38 url: core_pull_task_url, 38 url: core_pull_task_url,
39 qs: { 39 qs: {
40 handler: config.handler_name, 40 handler: config.handler_name,
41 products: config.products.join(',') 41 products: config.products.join(',')
42 } 42 }
43 } 43 }
44 44
45 request(options, function(error, response, body) { 45 request(options, function(error, response, body) {
46 if (error) { 46 if (error) {
47 if (matrix.core_is_healthy) { 47 if (matrix.core_is_healthy) {
48 logger.warn('Error pulling task from CORE', {error: error}); 48 logger.warn('Error pulling task from CORE', {error: error});
49 } 49 }
50 matrix.core_is_healthy = false; 50 matrix.core_is_healthy = false;
51 return; 51 return;
52 } 52 }
53 53
54 if (response.statusCode != 200) { 54 if (response.statusCode != 200) {
55 if (matrix.core_is_healthy) { 55 if (matrix.core_is_healthy) {
56 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode}); 56 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode});
57 } 57 }
58 matrix.core_is_healthy = false; 58 matrix.core_is_healthy = false;
59 return; 59 return;
60 } 60 }
61 61
62 if (!matrix.core_is_healthy) { 62 if (!matrix.core_is_healthy) {
63 logger.verbose('CORE is healthy'); 63 logger.verbose('CORE is healthy');
64 } 64 }
65 matrix.core_is_healthy = true; 65 matrix.core_is_healthy = true;
66 66
67 if (body == 'NONE') { 67 if (body == 'NONE') {
68 return; 68 return;
69 } 69 }
70 70
71 forwardCoreTaskToPartner(body); 71 forwardCoreTaskToPartner(body);
72 }); 72 });
73 } 73 }
74 74
75 function forwardCoreTaskToPartner(coreMessage) { 75 function forwardCoreTaskToPartner(coreMessage) {
76 let task; 76 let task;
77 77
78 try { 78 try {
79 task = JSON.parse(coreMessage); 79 task = JSON.parse(coreMessage);
80 } 80 }
81 catch(e) { 81 catch(e) {
82 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e}); 82 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e});
83 } 83 }
84 84
85 task.remote_product = getRemoteProduct(task.product); 85 task.remote_product = getRemoteProduct(task.product);
86 86
87 partner.buy(task); 87 partner.buy(task);
88 } 88 }
89 89
90 function report(data) { 90 function report(data) {
91
92 let core_pull_report_url;
93
94 if (config.core_url) {
95 core_pull_report_url = config.core_url + '/pull/report'; 91
96 } else if (config.pull_url.report) { 92 let core_pull_report_url;
97 core_pull_report_url = config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey); 93
98 } 94 if (config.core_url) {
99 95 core_pull_report_url = config.core_url + '/pull/report';
100 if (!core_pull_report_url) { 96 } else if (config.pull_url.report) {
101 logger.warn('Unknown CORE report url'); 97 core_pull_report_url = config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey);
102 return; 98 }
103 } 99
104 100 if (!core_pull_report_url) {
105 let options = { 101 logger.warn('Unknown CORE report url');
106 url: core_pull_report_url, 102 return;
107 form: { 103 }
108 trx_id: data.trx_id, 104
109 rc: data.rc, 105 let options = {
110 message: data.message, 106 url: core_pull_report_url,
111 handler: config.handler_name, 107 form: {
112 sn: data.sn, 108 trx_id: data.trx_id,
113 amount: data.amount, 109 rc: data.rc,
114 raw: data.raw, 110 message: data.message,
115 misc: data.misc 111 handler: config.handler_name,
116 } 112 sn: data.sn,
117 } 113 amount: data.amount,
118 114 raw: data.raw,
119 logger.verbose('Report to CORE using HTTP POST'); 115 misc: data.misc
120 request.post(options, function(error, response, body) {
121 if (error) {
122 logger.warn('Error reporting to CORE', {error: error}); 116 }
123 } 117 }
124 else if (response.statusCode != 200) { 118
125 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode}); 119 logger.verbose('Report to CORE using HTTP POST');
126 } 120 request.post(options, function(error, response, body) {
127 else { 121 if (error) {
128 logger.verbose('Report has been sent to CORE', {requestOptions: options}); 122 logger.warn('Error reporting to CORE', {error: error});
129 } 123 }
130 }); 124 else if (response.statusCode != 200) {
131 } 125 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode});
132 126 }
133 function resendReport(data) { 127 else {
134 let sleepBeforeResend = 1000; 128 logger.verbose('Report has been sent to CORE', {requestOptions: options});
135 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms') 129 }
136 130 });
137 setTimeout( 131 }
138 function() { 132
139 report(data);
140 },
141 sleepBeforeResend
142 )
143 }
144
145 function isPaused() {
146 return matrix.paused;
147 }
148
149 function pause() {
150 matrix.paused = true;
151 }
152
153 function resume() {
154 matrix.pause = false;
155 }
156
157 function initMatrix() {
158 if (!matrix) {
159 matrix = {};
160 }
161
162 matrix.counter = {
163 trx: 0
164 }
165 }
166
167 function incrementCounterTrx() {
168 matrix.counter.trx++;
169 }
170
171 function getRemoteProduct(product) {
172 let remoteProduct = config.remote_products[product];
173 return remoteProduct || product;
174 }
175
176 initMatrix();
177 setInterval(pullTask, config.pull_interval_ms || 1000);
178
179 exports.setPartner = setPartner; 133 function resendReport(data) {
180 exports.isPaused = isPaused; 134 let sleepBeforeResend = 1000;
181 exports.pause = pause; 135 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms')
182 exports.resume = resume; 136
183 exports.report = report; 137 setTimeout(
184 138 function() {
1 { 1 {
2 "name": "komodo-sdk", 2 "name": "komodo-sdk",
3 "version": "1.12.2", 3 "version": "1.13.0",
4 "description": "SDK for Komodo", 4 "description": "SDK for Komodo",
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-sdk.git" 12 "url": "git@gitlab.kodesumber.com:komodo/komodo-sdk.git"
13 }, 13 },
14 "keywords": [ 14 "keywords": [
15 "ppob", 15 "ppob",
16 "payment", 16 "payment",
17 "komodo" 17 "komodo"
18 ], 18 ],
19 "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>", 19 "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>",
20 "license": "ISC", 20 "license": "ISC",
21 "dependencies": { 21 "dependencies": {
22 "basic-auth": "^2.0.0", 22 "basic-auth": "^2.0.0",
23 "body-parser": "^1.18.2", 23 "body-parser": "^1.18.2",
24 "express": "^4.16.2", 24 "express": "^4.16.2",
25 "express-session": "^1.15.6", 25 "express-session": "^1.15.6",
26 "lru-cache": "^4.1.1", 26 "lru-cache": "^4.1.1",
27 "moment": "^2.19.1", 27 "moment": "^2.19.1",
28 "numeral": "^2.0.6", 28 "numeral": "^2.0.6",
29 "nunjucks": "^3.0.1", 29 "nunjucks": "^3.0.1",
30 "request": "^2.81.0", 30 "request": "^2.81.0",
31 "simple-git": "^1.80.1", 31 "simple-git": "^1.80.1",
32 "strftime": "^0.10.0", 32 "strftime": "^0.10.0",
33 "uniqid": "^4.1.1", 33 "uniqid": "^4.1.1",
34 "uuid": "^3.1.0", 34 "uuid": "^3.1.0",
35 "winston": "^2.3.1", 35 "winston": "^2.3.1",
36 "winston-circular-buffer": "^1.0.0", 36 "winston-circular-buffer": "^1.0.0",
37 "winston-daily-rotate-file": "^1.4.6" 37 "winston-daily-rotate-file": "^1.4.6"
38 } 38 }
39 } 39 }
40 40