diff --git a/config.sample.json b/config.sample.json new file mode 100644 index 0000000..3848abb --- /dev/null +++ b/config.sample.json @@ -0,0 +1,28 @@ +{ + "handler_name": "KOMODO", + "products": [ + ], + "core_url": "http://127.0.0.1:32972/apikey/PLEASE_CHANGE_ME", + "pull_interval_ms": 1000, + "partner": { + "url": "http://PLEASE_CHANGE_ME:25614/", + "terminal_name": "PLEASE_CHANGE_ME", + "password": "PLEASE_CHANGE_ME" + }, + "remote_products": { + "XL5": "XJ5", + "XL10": "XJ10", + "XL15": "XJ15", + "XL25": "XJ25", + "XL30": "XJ30", + "XL50": "XJ50", + "XL100": "XJ100", + "XL200": "XJ200" + }, + "reverse_report_url": "http://PLEASE_CHANGE_ME:24867/", + "reverse_report_port": 24867, + "control_panel": { + "listen_port": 24868 + }, + "do_not_verbose_log_report": false +} diff --git a/index.js b/index.js new file mode 100644 index 0000000..01d94b7 --- /dev/null +++ b/index.js @@ -0,0 +1,13 @@ +"use strict"; +process.chdir(__dirname); + +/* +const config = require('komodo-sdk/config'); +const logger = require('komodo-sdk/logger'); +const matrix = require('komodo-sdk/matrix'); +*/ + +const pullgw = require('komodo-sdk/gateway/pull'); +const partner = require('./lib/partner'); + +pullgw.setPartner(partner); diff --git a/lib/komodo-client.js b/lib/komodo-client.js new file mode 100644 index 0000000..0e4d873 --- /dev/null +++ b/lib/komodo-client.js @@ -0,0 +1,15 @@ +"use strict"; + +function parseResponse(body) { + let result; + try { + result = JSON.parse(body); + } + catch(e) { + result = null; + } + + return result; +} + +exports.parseResponse = parseResponse; diff --git a/lib/komodo-rc.js b/lib/komodo-rc.js new file mode 100644 index 0000000..68e4a22 --- /dev/null +++ b/lib/komodo-rc.js @@ -0,0 +1,14 @@ +"use strict"; + +module.exports = { + '00': '00', + '13': '90', + '14': '14', + '68': '68', + '88': '88', + '89': '89', + '90': '90', + '91': '90', + '93': '94', + '96': '68' +} diff --git a/lib/partner.js b/lib/partner.js new file mode 100644 index 0000000..a4ecbcf --- /dev/null +++ b/lib/partner.js @@ -0,0 +1,171 @@ +"use strict"; + +const HTTP = require('http'); +const URL = require('url'); +const request = require('request'); +const uuidv4 = require('uuid/v4'); + +const config = require('komodo-sdk/config'); +const logger = require('komodo-sdk/logger'); +const matrix = require('komodo-sdk/matrix'); +const pull = require('komodo-sdk/gateway/pull'); + +const komodoClient = require('./komodo-client'); +const partnerRc = require('./komodo-rc'); + +if (!matrix.pending_tasks) { + matrix.pending_tasks = {}; +} + +function deleteFromPendingTasks(trx_id) { + if (matrix.pending_tasks && matrix.pending_tasks[trx_id]) { + delete matrix.pending_tasks[trx_id]; + } +} + +function report(data) { + pull.report(data); + + if (data.rc !== '68' && data.rc !== '96') { + deleteFromPendingTasks(data.trx_id); + } +} + +function _hit(task, is_advice) { + + if (matrix.pending_tasks && !matrix.pending_tasks[task.trx_id]) { + matrix.pending_tasks[task.trx_id] = task; + } + + const request_options = { + url: config.partner.url, + qs: { + request_id: task.trx_id, + terminal_name: config.partner.terminal_name || config.partner.username, + password: config.partner.password, + reverse_url: config.reverse_report_url, + product_name: task.remote_product, + destination: task.destination + } + } + + if (!request_options.qs.request_id || !request_options.qs.terminal_name || !request_options.qs.password || !request_options.qs.reverse_url || !request_options.qs.product_name || !request_options.qs.destination) { + logger.verbose('Missing parameter on request', request_options.qs); + return; + } + + logger.info('Requesting to partner', {is_advice: is_advice, trx_id: task.trx_id, destination: task.destination, product: task.product, remote_product: task.remote_product}); + request(request_options, function(err, res, body) { + if (err) { + logger.warn('Error requesting to partner', {err: err, trx_id: task.trx_id, destination: task.destination, is_advice: is_advice}); + report({ + trx_id: task.trx_id, + rc: (!is_advice && (err.syscall === 'connect')) ? '91' : '68', + message: 'INTERNAL: REQUEST ERROR: ' + err.toString(), + misc: { + task: task + } + }); + return; + } + + if (res.statusCode != 200) { + logger.warn('Partner returning non 200 HTTP status code', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, http_status_code: res.statusCode, response_body: body}); + report({ + trx_id: task.trx_id, + rc: '68', + message: ('INTERNAL: Got non 200 HTTP status code: ' + res.statusCode + '\n\n' + body).trim(), + raw: body, + misc: { + task: task + } + }); + return; + } + + logger.verbose('Got response from partner', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, response_body: body}); + + const result = komodoClient.parseResponse(body); + if (!result) { + logger.warn('Partner returning invalid JSON', {trx_id: task.trx_id, destination: task.destination, is_advice: is_advice, response_body: body}); + report({ + trx_id: task.trx_id, + rc: is_advice ? '68' : '90', + message: 'INTERNAL: Partner return invalid JSON:\n' + body, + raw: body, + misc: { + task: task + } + }); + return; + } + + report({ + trx_id: task.trx_id, + rc: partnerRc[result.rc] || '40', + message: result.message, + sn: result.sn, + amount: Number(result.amount) || null, + raw: body, + misc: { + task: task + } + }); + }) +} + +function buy(task) { + _hit(task, false); +} + +function advice(task) { + _hit(task, true); +} + +function reverseReportHandler(req, res) { + const report_id = uuidv4(); + + logger.verbose('Incoming reverse report', {report_id: report_id, url: req.url}); + const qs = URL.parse(req.url, true).query; + + if (!qs.request_id || !qs.rc) { + logger.verbose('No request_id and rc on reverse report message', {report_id: report_id, url: req.url, qs: qs}); + return; + } + + const task = { + trx_id: qs.request_id, + destination: qs.destination, + remote_product: qs.product_name + } + + report({ + trx_id: qs.request_id, + rc: partnerRc[qs.rc] || '40', + message: qs.message, + sn: qs.sn, + amount: qs.amount || null, + raw: req.url, + misc: { + task: task + } + }); +} + +function createReverseReportHttpServer() { + const http_server = HTTP.createServer(reverseReportHandler); + http_server.listen(config.reverse_report_port, function(err) { + if (err) { + logger.warn('Error creating reverse report HTTP server: ' + err.toString()); + process.exit(1); + return; + } + + logger.info('Reverse report HTTP server listening on port ' + config.reverse_report_port); + }) +} + +createReverseReportHttpServer(); + +exports.buy = buy; +exports.advice = advice; diff --git a/package.json b/package.json index c7faa58..6ba9d4f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "json-stringify-pretty-compact": "^1.1.0", "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", - "request": "^2.85.0" + "request": "^2.85.0", + "uuid": "^3.2.1" } }