Compare View

switch
from
...
to
 
Commits (2)

Changes

Showing 3 changed files Inline Diff

gateway/advice-push-server.js
File was created 1 "use strict";
2
3 const express = require('express');
4 const bodyParser = require('body-parser');
5
6 const pull = require('./pull');
7 const config = require('../config');
8 const logger = require('../logger');
9 const matrix = require('../matrix');
10
11 if (!config || !config.push_server || !!config.push_server.apikey || !config.push_server.advice_port) return;
12
13 const app = express();
14
15 let partner = null;
16
17 function setPartner(_partner) {
18 partner = _partner;
19
20 app.listen(config.push_server.advice_port, function () {
21 logger.info('Advice server listening', {port: config.push_server.advice_port});
22 });
23 }
24
25 function isValidApikey(req, res, next) {
26 if (req.params.apikey === config.push_server.apikey) {
27 next();
28 }
29 else {
30 res.end('INVALID_APIKEY');
31 }
32 }
33
34 function adviceHandler(req, res, next) {
35
36 if (!partner) {
37 logger.warn('PUSH-ADVICE: Undefined partner, skipped');
38 res.end('UNDEFINED_PARTNER');
39 return;
40 }
41
42 if (!partner.advice) {
43 logger.warn('PUSH-ADVICE: Partner does not have ADVICE capabilities');
44 res.end('UNSUPPORTED');
45 return;
46 }
47
48 let task = null;
49
50 try {
51 task = JSON.parse(coreMessage);
52 }
53 catch(e) {
54 logger.warn('PUSH-ADVICE: Exception on parsing task to advice', {err: e});
55 }
56
57 if (!task) {
58 res.end('INVALID_TASK');
59 return;
60 }
61
62 task.remote_product = pull.getRemoteProduct(task.product);
63 partner.advice(task);
64 }
65
66 app.use(bodyParser.json());
67 app.use('/apikey/:apikey', isValidApikey);
68 app.use('/apikey/:apikey/advice', adviceHandler);
69
70 exports.setPartner = setPartner;
1 "use strict"; 71
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 const taskArchive = require('./task-archive'); 11 const taskArchive = require('./task-archive');
12 12
13 const MAX_SLEEP_BEFORE_RESEND_MS = 500; 13 const MAX_SLEEP_BEFORE_RESEND_MS = 500;
14 14
15 if (config.handler_name) { 15 if (config.handler_name) {
16 process.title = "KOMODO-GW@" + config.handler_name; 16 process.title = "KOMODO-GW@" + config.handler_name;
17 } 17 }
18 18
19 heartbeat.setModuleType('gateway'); 19 heartbeat.setModuleType('gateway');
20 20
21 var partner; 21 var partner;
22 22
23 function setPartner(_partner) { 23 function setPartner(_partner) {
24 partner = _partner; 24 partner = _partner;
25 } 25 }
26 26
27 function pullTask() { 27 function pullTask() {
28 if (!partner) { 28 if (!partner) {
29 return; 29 return;
30 } 30 }
31 31
32 let core_pull_task_url; 32 let core_pull_task_url;
33 33
34 if (config.core_url) { 34 if (config.core_url) {
35 core_pull_task_url = config.core_url + '/pull/task'; 35 core_pull_task_url = config.core_url + '/pull/task';
36 } else if (config.pull_url.task) { 36 } else if (config.pull_url.task) {
37 core_pull_task_url = config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey); 37 core_pull_task_url = config.pull_url.task.replace('<CORE_APIKEY>', config.core_apikey);
38 } 38 }
39 39
40 if (!core_pull_task_url) { 40 if (!core_pull_task_url) {
41 logger.warn('Unknown CORE task url'); 41 logger.warn('Unknown CORE task url');
42 return; 42 return;
43 } 43 }
44 44
45 let options = { 45 let options = {
46 url: core_pull_task_url, 46 url: core_pull_task_url,
47 qs: { 47 qs: {
48 handler: config.handler_name, 48 handler: config.handler_name,
49 products: config.products.join(',') 49 products: config.products.join(',')
50 } 50 }
51 } 51 }
52 52
53 request(options, function(error, response, body) { 53 request(options, function(error, response, body) {
54 if (error) { 54 if (error) {
55 if (matrix.core_is_healthy) { 55 if (matrix.core_is_healthy) {
56 logger.warn('Error pulling task from CORE', {error: error}); 56 logger.warn('Error pulling task from CORE', {error: error});
57 } 57 }
58 matrix.core_is_healthy = false; 58 matrix.core_is_healthy = false;
59 return; 59 return;
60 } 60 }
61 61
62 if (response.statusCode != 200) { 62 if (response.statusCode != 200) {
63 if (matrix.core_is_healthy) { 63 if (matrix.core_is_healthy) {
64 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode}); 64 logger.warn('CORE http response status code for pull task is not 200', {http_response_status: response.statusCode});
65 } 65 }
66 matrix.core_is_healthy = false; 66 matrix.core_is_healthy = false;
67 return; 67 return;
68 } 68 }
69 69
70 if (!matrix.core_is_healthy) { 70 if (!matrix.core_is_healthy) {
71 logger.verbose('CORE is healthy'); 71 logger.verbose('CORE is healthy');
72 } 72 }
73 matrix.core_is_healthy = true; 73 matrix.core_is_healthy = true;
74 74
75 if (body == 'NONE') { 75 if (body == 'NONE') {
76 return; 76 return;
77 } 77 }
78 78
79 forwardCoreTaskToPartner(body); 79 forwardCoreTaskToPartner(body);
80 }); 80 });
81 } 81 }
82 82
83 function forwardCoreTaskToPartner(coreMessage) { 83 function forwardCoreTaskToPartner(coreMessage) {
84 let task; 84 let task;
85 85
86 try { 86 try {
87 task = JSON.parse(coreMessage); 87 task = JSON.parse(coreMessage);
88 } 88 }
89 catch(e) { 89 catch(e) {
90 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e}); 90 logger.warn('Exception on parsing CORE pull task response', {coreMessage: coreMessage, error: e});
91 } 91 }
92 92
93 incrementCounterTrx(); 93 incrementCounterTrx();
94 94
95 task.remote_product = getRemoteProduct(task.product); 95 task.remote_product = getRemoteProduct(task.product);
96 96
97 taskArchive.get(task, function(res) { 97 taskArchive.get(task, function(res) {
98 if (res && partner.advice) { 98 if (res && partner.advice) {
99 partner.advice(task); 99 partner.advice(task);
100 } 100 }
101 else { 101 else {
102 partner.buy(task); 102 partner.buy(task);
103 } 103 }
104 }); 104 });
105 105
106 106
107 } 107 }
108 108
109 function replaceRc(original_rc) { 109 function replaceRc(original_rc) {
110 if (!config || !config.replace_rc || !config.replace_rc.length) { 110 if (!config || !config.replace_rc || !config.replace_rc.length) {
111 return original_rc; 111 return original_rc;
112 } 112 }
113 113
114 return config.replace_rc[original_rc] || original_rc; 114 return config.replace_rc[original_rc] || original_rc;
115 } 115 }
116 116
117 function report(data) { 117 function report(data) {
118 118
119 let core_pull_report_url; 119 let core_pull_report_url;
120 120
121 if (config.core_url) { 121 if (config.core_url) {
122 core_pull_report_url = config.core_url + '/pull/report'; 122 core_pull_report_url = config.core_url + '/pull/report';
123 } else if (config.pull_url.report) { 123 } else if (config.pull_url.report) {
124 core_pull_report_url = config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey); 124 core_pull_report_url = config.pull_url.report.replace('<CORE_APIKEY>', config.core_apikey);
125 } 125 }
126 126
127 if (!core_pull_report_url) { 127 if (!core_pull_report_url) {
128 logger.warn('Unknown CORE report url'); 128 logger.warn('Unknown CORE report url');
129 return; 129 return;
130 } 130 }
131 131
132 let options = { 132 let options = {
133 url: core_pull_report_url, 133 url: core_pull_report_url,
134 form: { 134 form: {
135 trx_id: data.trx_id, 135 trx_id: data.trx_id,
136 rc: replaceRc(data.rc), 136 rc: replaceRc(data.rc),
137 message: data.message, 137 message: data.message,
138 handler: config.handler_name, 138 handler: config.handler_name,
139 sn: data.sn, 139 sn: data.sn,
140 amount: data.amount, 140 amount: data.amount,
141 raw: data.raw, 141 raw: data.raw,
142 misc: data.misc 142 misc: data.misc
143 } 143 }
144 } 144 }
145 145
146 if (!config.do_not_verbose_log_report) { 146 if (!config.do_not_verbose_log_report) {
147 logger.verbose('Report to CORE using HTTP POST'); 147 logger.verbose('Report to CORE using HTTP POST');
148 } 148 }
149 149
150 request.post(options, function(error, response, body) { 150 request.post(options, function(error, response, body) {
151 if (error) { 151 if (error) {
152 logger.warn('Error reporting to CORE', {error: error}); 152 logger.warn('Error reporting to CORE', {error: error});
153 resendReport(data); 153 resendReport(data);
154 } 154 }
155 else if (response.statusCode != 200) { 155 else if (response.statusCode != 200) {
156 logger.warn('Error reporting to CORE, http response status is not 200', {requestOptions: options, http_response_status: response.statusCode}); 156 logger.warn('Error reporting to CORE, http response status is not 200', {requestOptions: options, http_response_status: response.statusCode});
157 resendReport(data); 157 resendReport(data);
158 } 158 }
159 else if (!config.do_not_verbose_log_report) { 159 else if (!config.do_not_verbose_log_report) {
160 logger.verbose('Report has been sent to CORE', {requestOptions: options}); 160 logger.verbose('Report has been sent to CORE', {requestOptions: options});
161 } 161 }
162 }); 162 });
163 } 163 }
164 164
165 function resendReport(data) { 165 function resendReport(data) {
166 const sleepBeforeResend = Math.round(Math.random() * MAX_SLEEP_BEFORE_RESEND_MS) 166 const sleepBeforeResend = Math.round(Math.random() * MAX_SLEEP_BEFORE_RESEND_MS)
167 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms') 167 logger.verbose('Resend report to CORE in ' + sleepBeforeResend + 'ms')
168 168
169 setTimeout( 169 setTimeout(
170 function() { 170 function() {
171 report(data); 171 report(data);
172 }, 172 },
173 sleepBeforeResend 173 sleepBeforeResend
174 ) 174 )
175 } 175 }
176 176
177 function isPaused() { 177 function isPaused() {
178 return matrix.paused; 178 return matrix.paused;
179 } 179 }
180 180
181 function pause() { 181 function pause() {
182 matrix.paused = true; 182 matrix.paused = true;
183 } 183 }
184 184
185 function resume() { 185 function resume() {
186 matrix.pause = false; 186 matrix.pause = false;
187 } 187 }
188 188
189 function initMatrix() { 189 function initMatrix() {
190 if (!matrix) { 190 if (!matrix) {
191 matrix = {}; 191 matrix = {};
192 } 192 }
193 193
194 matrix.counter = { 194 matrix.counter = {
195 trx: 0 195 trx: 0
196 } 196 }
197 } 197 }
198 198
199 function incrementCounterTrx() { 199 function incrementCounterTrx() {
200 matrix.counter.trx++; 200 matrix.counter.trx++;
201 } 201 }
202 202
203 function getRemoteProduct(product) { 203 function getRemoteProduct(product) {
204 let remoteProduct = config.remote_products[product]; 204 let remoteProduct = config.remote_products[product];
205 return remoteProduct || product; 205 return remoteProduct || product;
206 } 206 }
207 207
208 initMatrix(); 208 initMatrix();
209 setInterval(pullTask, config.pull_interval_ms || 1000); 209 setInterval(pullTask, config.pull_interval_ms || 1000);
210 210
211 exports.setPartner = setPartner; 211 exports.setPartner = setPartner;
212 exports.isPaused = isPaused; 212 exports.isPaused = isPaused;
213 exports.pause = pause; 213 exports.pause = pause;
214 exports.resume = resume; 214 exports.resume = resume;
215 exports.report = report; 215 exports.report = report;
216 exports.getRemoteProduct = getRemoteProduct;
216 exports.getRemoteProduct = getRemoteProduct; 217
1 { 1 {
2 "name": "komodo-sdk", 2 "name": "komodo-sdk",
3 "version": "1.16.4", 3 "version": "1.17.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.3", 24 "express": "^4.16.3",
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 "macaddress": "^0.2.8", 27 "macaddress": "^0.2.8",
28 "moment": "^2.19.1", 28 "moment": "^2.19.1",
29 "node-machine-id": "^1.1.10", 29 "node-machine-id": "^1.1.10",
30 "node-natural-sort": "^0.8.6", 30 "node-natural-sort": "^0.8.6",
31 "numeral": "^2.0.6", 31 "numeral": "^2.0.6",
32 "nunjucks": "^3.0.1", 32 "nunjucks": "^3.0.1",
33 "redis": "^2.8.0", 33 "redis": "^2.8.0",
34 "request": "^2.81.0", 34 "request": "^2.81.0",
35 "sha1": "^1.1.1", 35 "sha1": "^1.1.1",
36 "simple-git": "^1.80.1", 36 "simple-git": "^1.80.1",
37 "strftime": "^0.10.0", 37 "strftime": "^0.10.0",
38 "uniqid": "^4.1.1", 38 "uniqid": "^4.1.1",
39 "uuid": "^3.1.0", 39 "uuid": "^3.1.0",
40 "winston": "^2.3.1", 40 "winston": "^2.3.1",
41 "winston-circular-buffer": "^1.0.0", 41 "winston-circular-buffer": "^1.0.0",
42 "winston-daily-rotate-file": "^1.4.6" 42 "winston-daily-rotate-file": "^1.4.6"
43 } 43 }
44 } 44 }
45 45