Compare View

switch
from
...
to
 
Commits (3)

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.indexOf(command) >= 0) {
29 if (config.commands && config.commands.balance.indexOf(command) >= 0) { 30 executeBalanceCheck(paramsFromTransport, cb);
30 executeBalanceCheck(paramsFromTransport, cb); 31 }
31 } 32 else if (config.commands && config.commands.price.indexOf(command) >= 0) {
32 else if (config.commands && config.commands.price.indexOf(command) >= 0) { 33 executePriceCheck(paramsFromTransport, cb);
33 executePriceCheck(paramsFromTransport, cb); 34 }
34 } 35 else {
35 else { 36 executePrepaidBuy(paramsFromTransport, cb);
36 executePrepaidBuy(paramsFromTransport, cb); 37 }
37 } 38 }
38 } 39
39 40 function executeBalanceCheck(paramsFromTransport) {
40 function executeBalanceCheck(paramsFromTransport) { 41 const terminal_name = paramsFromTransport.partner.toLowerCase();
41 const terminal_name = paramsFromTransport.partner.toLowerCase(); 42 const password = paramsFromTransport.msg.trim().split(/[\., ]+/)[1];
42 const password = paramsFromTransport.msg.trim().split(/[\., ]+/)[1]; 43
43 44 const requestOptions = {
44 const requestOptions = { 45 url: config.core_url + '/services/balance',
45 url: config.core_url + '/services/balance', 46 qs: {
46 qs: { 47 terminal_name: terminal_name,
47 terminal_name: terminal_name, 48 password: password
48 password: password 49 }
49 } 50 }
50 } 51
51 52 requestToCore(requestOptions);
52 requestToCore(requestOptions); 53 }
53 } 54
54 55 function executePriceCheck(paramsFromTransport) {
55 function executePriceCheck(paramsFromTransport) { 56 const requestOptions = {
56 const requestOptions = { 57 url: config.core_url + '/services/pricelist',
57 url: config.core_url + '/services/pricelist', 58 qs: {
58 qs: { 59 terminal_name: paramsFromTransport.partner.toLowerCase(),
59 terminal_name: paramsFromTransport.partner.toLowerCase(), 60 keyword: paramsFromTransport.msg.trim().split(/[\., ]+/)[1],
60 keyword: paramsFromTransport.msg.trim().split(/[\., ]+/)[1], 61 password: paramsFromTransport.msg.trim().split(/[\., ]+/)[2]
61 password: paramsFromTransport.msg.trim().split(/[\., ]+/)[2] 62 }
62 } 63 }
63 } 64
64 65 requestToCore(requestOptions);
65 requestToCore(requestOptions); 66 }
66 } 67
67 68 function parseCoreMessage(body) {
68 function parseCoreMessage(body) { 69 let coreRes;
69 let coreRes; 70
70 71 try {
71 try { 72 coreRes = JSON.parse(body)
72 coreRes = JSON.parse(body) 73 }
73 } 74 catch(err) {
74 catch(err) { 75 logger.warn('Exception on parsing CORE response as JSON', {body: body, err: err});
75 logger.warn('Exception on parsing CORE response as JSON', {body: body, err: err}); 76 coreRes = null;
76 coreRes = null; 77 }
77 } 78
78 79 return coreRes;
79 return coreRes; 80 }
80 } 81
81 82 function generateRequestId(req) {
82 function generateRequestId(req) { 83 return 'AUTO_' + req.product_name + '_' + req.destination + '_' + strftime('%Y%m%d');
83 return 'AUTO_' + req.product_name + '_' + req.destination + '_' + strftime('%Y%m%d'); 84 }
84 } 85
85 86 function executePrepaidBuy(paramsFromTransport, cb) {
86 function executePrepaidBuy(paramsFromTransport, cb) { 87 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/);
87 let tokens = paramsFromTransport.msg.trim().split(/[\., ]+/); 88
88 89 let qs = {
89 let qs = { 90 request_id: tokens[3],
90 request_id: tokens[3], 91 terminal_name: paramsFromTransport.partner.toLowerCase(),
91 terminal_name: paramsFromTransport.partner.toLowerCase(), 92 product_name: tokens[0].toUpperCase(),
92 product_name: tokens[0].toUpperCase(), 93 destination: tokens[1].toUpperCase(),
93 destination: tokens[1].toUpperCase(), 94 password: tokens[2],
94 password: tokens[2], 95 origin: config.origin || config.username,
95 origin: config.origin || config.username, 96 report_port: config.listen_port || '80',
96 report_port: config.listen_port || '80', 97 msg: paramsFromTransport.msg,
97 msg: paramsFromTransport.msg, 98 reverse_url: paramsFromTransport.reverse_url
98 reverse_url: paramsFromTransport.reverse_url 99 }
99 } 100
100 101 if (!config.do_not_prefix_request_id) {
101 if (!config.do_not_prefix_request_id) { 102 qs.request_id = generateRequestId(qs);
102 qs.request_id = generateRequestId(qs); 103 if (tokens[3]) {
103 if (tokens[3]) { 104 qs.request_id += '_' + tokens[3];
104 qs.request_id += '_' + tokens[3]; 105 }
105 } 106 }
106 } 107
107 108 let requestOptions = {
108 let requestOptions = { 109 url: config.core_url + '/prepaid/buy',
109 url: config.core_url + '/prepaid/buy', 110 qs: qs
110 qs: qs 111 }
111 } 112
112 113 requestToCore(requestOptions, cb);
113 requestToCore(requestOptions, cb); 114 }
114 } 115
115 116 function requestToCore(requestOptions, cb) {
116 function requestToCore(requestOptions, cb) { 117 logger.verbose('Requesting service to CORE', requestOptions);
117 logger.verbose('Requesting service to CORE', requestOptions); 118
118 119 request(requestOptions, function(err, res, body) {
119 request(requestOptions, function(err, res, body) { 120 if (err || res.statusCode != 200) {
120 if (err || res.statusCode != 200) { 121 logger.warn('Error requesting to CORE', {module_name: module_name, method_name: 'requestToCore', requestOptions: requestOptions, err: err});
121 logger.warn('Error requesting to CORE', {module_name: module_name, method_name: 'requestToCore', requestOptions: requestOptions, err: err}); 122 if (cb) {
122 if (cb) { 123 cb(null, {msg: 'INTERNAL ERROR'});
123 cb(null, {msg: 'INTERNAL ERROR'}); 124 }
124 } 125 else if (transport.send) {
125 else if (transport.send) { 126 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR');
126 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR'); 127 }
127 } 128 return;
128 return; 129 }
129 } 130
130 131 let result = parseCoreMessage(body);
131 let result = parseCoreMessage(body); 132 if (!result || !result.message) {
132 if (!result || !result.message) { 133 if (cb) {
133 if (cb) { 134 cb(null, {msg: 'INTERNAL ERROR'});
134 cb(null, {msg: 'INTERNAL ERROR'}); 135 }
135 } 136 else if (transport.send) {
136 else if (transport.send) { 137 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR');
137 transport.send(requestOptions.qs.terminal_name, 'INTERNAL ERROR'); 138 }
138 } 139 return;
139 return; 140 }
140 } 141
141 142 if (cb) {
142 if (cb) { 143 cb(null, result);
143 cb(null, result); 144 }
144 } 145 else if (transport.send) {
145 else if (transport.send) { 146 transport.send(requestOptions.qs.terminal_name, result.message);
146 transport.send(requestOptions.qs.terminal_name, result.message); 147
147 148 }
148 } 149 })
149 }) 150 }
150 } 151
151 152 function setTransport(_transport) {
152 function setTransport(_transport) { 153 transport = _transport;
153 transport = _transport; 154 httpResponseServer.setTransport(transport);
154 httpResponseServer.setTransport(transport); 155 }
155 } 156
156 157 const callback = {
157 const callback = { 158 onOnline: onOnline,
158 onOnline: onOnline, 159 onIncomingMessage: onIncomingMessage
159 onIncomingMessage: onIncomingMessage 160 }
160 } 161
161 162 exports.callback = callback;
162 exports.callback = callback; 163 exports.setTransport = setTransport;
163 exports.setTransport = setTransport; 164
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
9 10 var partner;
10 var partner; 11
11 12 function setPartner(_partner) {
12 function setPartner(_partner) { 13 partner = _partner;
13 partner = _partner; 14 }
14 } 15
15 16 function pullTask() {
16 function pullTask() { 17 if (!partner) {
17 if (!partner) { 18 return;
18 return; 19 }
19 } 20
20 21 let options = {
21 let options = { 22 url: config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey),
22 url: config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey), 23 qs: {
23 qs: { 24 handler: config.handler_name,
24 handler: config.handler_name, 25 products: config.products.join(',')
25 products: config.products.join(',') 26 }
26 } 27 }
27 } 28
28 29 request(options, function(error, response, body) {
29 request(options, function(error, response, body) { 30 if (error) {
30 if (error) { 31 if (matrix.core_is_healthy) {
31 if (matrix.core_is_healthy) { 32 logger.warn('Error pulling task from CORE', {error: error});
32 logger.warn('Error pulling task from CORE', {error: error}); 33 }
33 } 34 matrix.core_is_healthy = false;
34 matrix.core_is_healthy = false; 35 return;
35 return; 36 }
36 } 37
37 38 if (response.statusCode != 200) {
38 if (response.statusCode != 200) { 39 if (matrix.core_is_healthy) {
39 if (matrix.core_is_healthy) { 40 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode});
40 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode}); 41 }
41 } 42 matrix.core_is_healthy = false;
42 matrix.core_is_healthy = false; 43 return;
43 return; 44 }
44 } 45
45 46 if (!matrix.core_is_healthy) {
46 if (!matrix.core_is_healthy) { 47 logger.verbose('CORE is healthy');
47 logger.verbose('CORE is healthy'); 48 }
48 } 49 matrix.core_is_healthy = true;
49 matrix.core_is_healthy = true; 50
50 51 if (body == 'NONE') {
51 if (body == 'NONE') { 52 return;
52 return; 53 }
53 } 54
54 55 forwardCoreTaskToPartner(body);
55 forwardCoreTaskToPartner(body); 56 });
56 }); 57 }
57 } 58
58 59 function forwardCoreTaskToPartner(coreMessage) {
59 function forwardCoreTaskToPartner(coreMessage) { 60 let task;
60 let task; 61
61 62 try {
62 try { 63 task = JSON.parse(coreMessage);
63 task = JSON.parse(coreMessage); 64 }
64 } 65 catch(e) {
65 catch(e) { 66 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e});
66 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e}); 67 }
67 } 68
68 69 task.remote_product = getRemoteProduct(task.product);
69 task.remote_product = getRemoteProduct(task.product); 70
70 71 partner.buy(task);
71 partner.buy(task); 72 }
72 } 73
73 74 function report(data) {
74 function report(data) { 75 reportUsingHttpPost(data);
75 reportUsingHttpPost(data); 76 }
76 } 77
77 78 function reportUsingHttpPost(data) {
78 function reportUsingHttpPost(data) { 79 let options = {
79 let options = { 80 url: config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey),
80 url: config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey), 81 form: {
81 form: { 82 trx_id: data.trx_id,
82 trx_id: data.trx_id, 83 rc: data.rc,
83 rc: data.rc, 84 message: data.message,
84 message: data.message, 85 handler: config.handler_name,
85 handler: config.handler_name, 86 sn: data.sn,
86 sn: data.sn, 87 amount: data.amount,
87 amount: data.amount, 88 raw: data.raw
88 raw: data.raw 89 }
89 } 90 }
90 } 91
91 92 logger.verbose('Report to CORE using HTTP POST');
92 logger.verbose('Report to CORE using HTTP POST'); 93 request.post(options, function(error, response, body) {
93 request.post(options, function(error, response, body) { 94 if (error) {
94 if (error) { 95 logger.warn('Error reporting to CORE', {error: error});
95 logger.warn('Error reporting to CORE', {error: error}); 96 }
96 } 97 else if (response.statusCode != 200) {
97 else if (response.statusCode != 200) { 98 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode});
98 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode}); 99 }
99 } 100 else {
100 else { 101 logger.verbose('Report has been sent to CORE', {requestOptions: options});
101 logger.verbose('Report has been sent to CORE', {requestOptions: options}); 102 }
102 } 103 });
103 }); 104 }
104 } 105
105 106 function reportUsingHttpGet(data) {
106 function reportUsingHttpGet(data) { 107 let options = {
107 let options = { 108 url: config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey),
108 url: config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey), 109 qs: {
109 qs: { 110 trx_id: data.trx_id,
110 trx_id: data.trx_id, 111 rc: data.rc,
111 rc: data.rc, 112 message: data.message,
112 message: data.message, 113 handler: config.handler_name,
113 handler: config.handler_name, 114 sn: data.sn,
114 sn: data.sn, 115 amount: data.amount
115 amount: data.amount 116 }
116 } 117 }
117 } 118
118 119 logger.verbose('Report to CORE using HTTP GET');
119 logger.verbose('Report to CORE using HTTP GET'); 120 request(options, function(error, response, body) {
120 request(options, function(error, response, body) { 121 if (error) {
121 if (error) { 122 logger.warn('Error reporting to CORE', {error: error});
122 logger.warn('Error reporting to CORE', {error: error}); 123 }
123 } 124 else if (response.statusCode != 200) {
124 else if (response.statusCode != 200) { 125 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode});
125 logger.warn('CORE http response status is not 200', {requestOptions: options, http_response_status: response.statusCode}); 126 }
126 } 127 else {
127 else { 128 logger.verbose('Report has been sent to CORE', {requestOptions: options});
128 logger.verbose('Report has been sent to CORE', {requestOptions: options}); 129 }
129 } 130 });
130 }); 131 }
131 } 132
132 133 function resendReport(data) {
133 function resendReport(data) { 134 let sleepBeforeResend = 1000;
134 let sleepBeforeResend = 1000; 135 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms')
135 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms') 136
136 137 setTimeout(
137 setTimeout( 138 function() {
138 function() { 139 report(data);
139 report(data); 140 },
140 }, 141 sleepBeforeResend
141 sleepBeforeResend 142 )
142 ) 143 }
143 } 144
144 145 function isPaused() {
145 function isPaused() { 146 return matrix.paused;
146 return matrix.paused; 147 }
147 } 148
148 149 function pause() {
149 function pause() { 150 matrix.paused = true;
150 matrix.paused = true; 151 }
151 } 152
152 153 function resume() {
153 function resume() { 154 matrix.pause = false;
154 matrix.pause = false; 155 }
155 } 156
156 157 function initMatrix() {
157 function initMatrix() { 158 if (!matrix) {
158 if (!matrix) { 159 matrix = {};
159 matrix = {}; 160 }
160 } 161
161 162 matrix.counter = {
162 matrix.counter = { 163 trx: 0
163 trx: 0 164 }
164 } 165 }
165 } 166
166 167 function incrementCounterTrx() {
167 function incrementCounterTrx() { 168 matrix.counter.trx++;
168 matrix.counter.trx++; 169 }
169 } 170
170 171 function getRemoteProduct(product) {
171 function getRemoteProduct(product) { 172 let remoteProduct = config.remote_products[product];
172 let remoteProduct = config.remote_products[product]; 173 return remoteProduct || product;
173 return remoteProduct || product; 174 }
174 } 175
175 176 initMatrix();
176 initMatrix(); 177 setInterval(pullTask, config.pull_interval_ms || 1000);
177 setInterval(pullTask, config.pull_interval_ms || 1000); 178
178 179 exports.setPartner = setPartner;
179 exports.setPartner = setPartner; 180 exports.isPaused = isPaused;
180 exports.isPaused = isPaused; 181 exports.pause = pause;
181 exports.pause = pause; 182 exports.resume = resume;
182 exports.resume = resume; 183 exports.report = report;
183 exports.report = report; 184
1 { 1 {
2 "name": "komodo-sdk", 2 "name": "komodo-sdk",
3 "version": "1.10.1", 3 "version": "1.10.2",
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