From f43dbc16a329b2ffedd2103dc9ddbcb1343ef668 Mon Sep 17 00:00:00 2001 From: Adhidarma Hadiwinoto <me@adhisimon.org> Date: Wed, 31 Jul 2019 16:14:26 +0700 Subject: [PATCH] New modem selector --- lib/apiserver/index.js | 10 ++++++ lib/modemSelect.js | 34 ++++++++++++++++++ lib/modems.js | 34 ------------------ lib/modems2.js | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/partner-last-seen.js | 2 +- lib/transport.js | 78 +++++++++++------------------------------ test/modems.js | 22 ++++++------ 7 files changed, 167 insertions(+), 104 deletions(-) create mode 100644 lib/modemSelect.js delete mode 100644 lib/modems.js create mode 100644 lib/modems2.js diff --git a/lib/apiserver/index.js b/lib/apiserver/index.js index 098da61..e18e4fb 100644 --- a/lib/apiserver/index.js +++ b/lib/apiserver/index.js @@ -16,6 +16,7 @@ const logger = require('komodo-sdk/logger'); const transport = require('../transport'); const partnerLastSeen = require('../partner-last-seen'); const history = require('../history'); +const modems = require('../modems2'); const app = express(); messagingService.setTransport(transport); @@ -52,6 +53,15 @@ function onIncomingSms(req, res) { message: req.query.msg, }); + modems.set({ + name: req.query.modem, + imsi: req.query.modem_imsi, + msisdn: req.query.modem_msisdn, + reportIp: req.query.report_ip || req.ip, + reportPort: req.query.report_port, + reportApikey: req.query.report_apikey, + }); + logger.info('APISERVER: Incoming SMS', { modem: req.query.modem, from: req.query.number, from_with_suffix: numberWithSuffix, msg: req.query.msg }); messagingService.onIncomingMessage({ me: req.query.modem, diff --git a/lib/modemSelect.js b/lib/modemSelect.js new file mode 100644 index 0000000..4f441ad --- /dev/null +++ b/lib/modemSelect.js @@ -0,0 +1,34 @@ +"use strict"; + +function getModemConfig(modemName, modemsConfig) { + if (!modemsConfig) return; + if (!modemName) return; + if (typeof modemName === 'string' && !modemName.trim()) return; + + return modemsConfig[modemName.trim()]; +} + +function getModemUrl(modemName, modemsConfig) { + const modemConfig = getModemConfig(modemName, modemsConfig); + return modemConfig ? modemConfig.url : null; +} + +function getModemApikey(modemName, modemsConfig) { + const modemConfig = getModemConfig(modemName, modemsConfig); + return modemConfig ? modemConfig.apikey : null; +} + +function removeSuffixFromNumber(number, config) { + if (!config) { + config = {}; + } + + const suffix = config && config.number_suffix ? config.number_suffix : '@.*'; + const re = new RegExp(suffix + '$'); + return number.replace(re, ''); +} + +exports.getModemConfig = getModemConfig; +exports.getModemUrl = getModemUrl; +exports.getModemApikey = getModemApikey; +exports.removeSuffixFromNumber = removeSuffixFromNumber; \ No newline at end of file diff --git a/lib/modems.js b/lib/modems.js deleted file mode 100644 index 4f441ad..0000000 --- a/lib/modems.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; - -function getModemConfig(modemName, modemsConfig) { - if (!modemsConfig) return; - if (!modemName) return; - if (typeof modemName === 'string' && !modemName.trim()) return; - - return modemsConfig[modemName.trim()]; -} - -function getModemUrl(modemName, modemsConfig) { - const modemConfig = getModemConfig(modemName, modemsConfig); - return modemConfig ? modemConfig.url : null; -} - -function getModemApikey(modemName, modemsConfig) { - const modemConfig = getModemConfig(modemName, modemsConfig); - return modemConfig ? modemConfig.apikey : null; -} - -function removeSuffixFromNumber(number, config) { - if (!config) { - config = {}; - } - - const suffix = config && config.number_suffix ? config.number_suffix : '@.*'; - const re = new RegExp(suffix + '$'); - return number.replace(re, ''); -} - -exports.getModemConfig = getModemConfig; -exports.getModemUrl = getModemUrl; -exports.getModemApikey = getModemApikey; -exports.removeSuffixFromNumber = removeSuffixFromNumber; \ No newline at end of file diff --git a/lib/modems2.js b/lib/modems2.js new file mode 100644 index 0000000..e863b2d --- /dev/null +++ b/lib/modems2.js @@ -0,0 +1,91 @@ +'use strict'; + +const modemList = { + by_name: {}, + by_imsi: {}, + by_msisdn: {}, +}; + +/** + * Objek data sebuah modem. + * + * @typedef {Object} ModemData + * @property {string} name - nama modem + * @property {string} imsi - IMSI modem + * @property {string} msisdn - MSISDN modem + * @property {string} reportIp - IP modem + * @property {number} reportPort - TCP port modem + * @property {string} reportApikey - APIKEY modem + */ + +/** + * Update data sebuah modem berdasarkan nama modem. + * + * @param {ModemData} val - objek data modem + */ +function touchByName(val) { + if (!val || !val.name) return; + if (typeof val.name !== 'string') return; + if (!val.name.trim()) return; + + modemList.by_name[val.name] = val; +} +/** + * Update data sebuah modem berdasarkan IMSI. + * + * @param {ModemData} val - objek data modem + */ +function touchByIMSI(val) { + if (!val || !val.imsi) return; + if (typeof val.imsi !== 'string') return; + if (!val.imsi.trim()) return; + + modemList.by_imsi[val.imsi] = val; +} + +/** + * Update data sebuah modem berdasarkan MSISDN. + * + * @param {ModemData} val - objek data modem + */ +function touchByMSISDN(val) { + if (!val || !val.msisdn) return; + if (typeof val.msisdn !== 'string') return; + if (!val.msisdn.trim()) return; + + modemList.by_msisdn[val.msisdn] = val; +} + +/** + * Update data sebuah modem. + * + * @param {ModemData} val - objek data modem + * @see ModemData + */ +function touch(val) { + if (!val) return; + + if (!val.reportIp) { + val.reportIp = '127.0.0.1'; + } + + touchByName(val); + touchByIMSI(val); + touchByMSISDN(val); +} +/** + * Ambil data sebuah modem. + * + * @param {string} selector - selector pencarian, valid jika bernilai salah satu dari: name, imsi, msisdn + * @param {string} keyword - kata kunci modem yang ingin diambil + * @returns {ModemData} data modem terkait + */ +function get(selector, keyword) { + if (!selector || !keyword) return null; + + return modemList[`by_${selector}`] ? modemList[`by_${selector}`][keyword] : null; +} + +exports.touch = touch; +exports.set = touch; +exports.get = get; \ No newline at end of file diff --git a/lib/partner-last-seen.js b/lib/partner-last-seen.js index 63b626b..1fe3347 100644 --- a/lib/partner-last-seen.js +++ b/lib/partner-last-seen.js @@ -1,6 +1,6 @@ "use strict"; -const REDIS_TTL_SECS = 3600 * 24 * 7; +const REDIS_TTL_SECS = 3600 * 24 * 31; const config = require('komodo-sdk/config'); // const logger = require('komodo-sdk/logger'); diff --git a/lib/transport.js b/lib/transport.js index f368247..a411f2f 100644 --- a/lib/transport.js +++ b/lib/transport.js @@ -1,5 +1,6 @@ "use strict"; +const url = require('url'); const request = require('request'); const uuidv4 = require('uuid/v4'); const moment = require('moment'); @@ -7,60 +8,13 @@ const moment = require('moment'); const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); -const modems = require('./modems'); +const modemSelect = require('./modemSelect'); +const modems = require('./modems2'); const partnerLastSeen = require('./partner-last-seen'); const history = require('./history'); -async function _getApproriateHandlerByLastSeen(partnerNumber) { - logger.verbose('Looking for last seen on for partner number ' + partnerNumber); - const lastSeenFrom = await partnerLastSeen.get(partnerNumber); - return lastSeenFrom; -} - -function _getApproriateHandlerByForced() { - if (!config.sending_handler || !config.sending_handler.length) return; - - const sendingHandlerCount = config.sending_handler.length; - const idx = Math.floor(Math.random() * sendingHandlerCount); - return config.sending_handler[idx]; -} - -async function _getApproriateHandler(partnerNumber, origin) { - let handlerToUse; - - if (config.handler_chooser_algorithm === 'FORCED') { - handlerToUse = _getApproriateHandlerByForced(); - logger.verbose('Config file mentioned to using FORCED handler chooser algorithm', { handler_to_use: handlerToUse}); - } - else { - handlerToUse = await _getApproriateHandlerByLastSeen(partnerNumber); - logger.verbose('Config file mentioned to using LAST-SEEN handler chooser algorithm', { handler_to_use: handlerToUse}); - } - - if (!modems.getModemConfig(handlerToUse, config.modems)) { - const handlerWithSameOrigin = modems.getModemConfig(origin, config.modems); - if (handlerWithSameOrigin) { - logger.verbose('Invalid approriate handler, using handler from the same ORIGIN request by CORE to send sms') - handlerToUse = origin; - } - else { - logger.verbose('Invalid approriate handler, using default handler to send sms') - handlerToUse = config.default_modem; - } - } - - return handlerToUse; -} - function _send(destinationNumber, msg, handlerName) { - /* - if (msg.length > 160 && !config.do_not_trim_long_sms) { - logger.verbose('Message trim to 160 chars'); - msg = msg.slice(0, 156) + ' ...'; - } - */ - if (msg.length > 160) { const newMsg = msg.slice(0, 160); const remainingMsg = msg.slice(160); @@ -73,14 +27,14 @@ function _send(destinationNumber, msg, handlerName) { return; } - const modem = modems.getModemConfig(handlerName, config.modems); + const modem = modems.get('name', handlerName); if (!modem) { logger.warn('Not knowing modem to use. Ignoring message', { destination_number: destinationNumber, msg: msg, handler_name: handlerName }); return; } - if (!modem.url || !modem.apikey) { - logger.warn('Invalid modem configuration', { config: modem, handler_name: handlerName }); + if (!modem.reportIp || !modem.reportPort || !modem.reportApikey) { + logger.warn('Invalid modem configuration', { modem }); return; } @@ -96,14 +50,17 @@ function _send(destinationNumber, msg, handlerName) { message: msg, }); - const requestOptions = { - url: modem.url, + url: url.format({ + protocol: 'http', + hostname: modem.reportIp, + port: modem.reportPort, + }), qs: { msg: msg, number: destinationNumber, reqid: reqId, - apikey: modem.apikey + apikey: modem.reportApikey } } @@ -134,10 +91,15 @@ async function send(partner, msg, origin) { msg = msg.trim(); if (!msg) return; - const destinationNumber = modems.removeSuffixFromNumber(partner, config); + const destinationNumber = modemSelect.removeSuffixFromNumber(partner, config); + + // logger.verbose('Choosing handler name', { partner, destinationNumber, msg, origin }); + let handlerName = await partnerLastSeen.get(destinationNumber) ; - logger.verbose('Choosing handler name', { partner, destinationNumber, msg, origin }); - let handlerName = ( await _getApproriateHandler(destinationNumber) ); + if (!handlerName) { + logger.warn(`Unknown handler for sending message to partner`, { partner, destinationNumber }); + return; + } _send(destinationNumber, msg, handlerName); } diff --git a/test/modems.js b/test/modems.js index 1e3a5d2..d116897 100644 --- a/test/modems.js +++ b/test/modems.js @@ -4,9 +4,9 @@ const should = require('should'); -const modems = require('../lib/modems'); +const modemSelect = require('../lib/modemSelect'); -describe('#modems', function() { +describe('#modemSelect', function() { describe('#getModemUrl', function() { @@ -17,13 +17,13 @@ describe('#modems', function() { } it('should return correct url', function() { - modems.getModemUrl('SMS0', modemsConfig).should.equal('http://localhost:8888/'); + modemSelect.getModemUrl('SMS0', modemsConfig).should.equal('http://localhost:8888/'); }) it ('should handle missing modems', function() { - should.not.exists(modems.getModemUrl('SMS0', null)); - should.not.exists(modems.getModemUrl('SMS0', {})); - should.not.exists(modems.getModemUrl('SMS1', modemsConfig)); + should.not.exists(modemSelect.getModemUrl('SMS0', null)); + should.not.exists(modemSelect.getModemUrl('SMS0', {})); + should.not.exists(modemSelect.getModemUrl('SMS1', modemsConfig)); }) }) @@ -33,17 +33,17 @@ describe('#modems', function() { } it('should return correct number', function() { - modems.removeSuffixFromNumber('08181234@phonenumber', config).should.equal('08181234'); + modemSelect.removeSuffixFromNumber('08181234@phonenumber', config).should.equal('08181234'); }) it ('should return correct number without suffix in the number', function() { - modems.removeSuffixFromNumber('08181234', config).should.equal('08181234'); + modemSelect.removeSuffixFromNumber('08181234', config).should.equal('08181234'); }) it ('should return correct number without suffix in config', function() { - modems.removeSuffixFromNumber('08181234', null).should.equal('08181234'); - modems.removeSuffixFromNumber('08181234', {}).should.equal('08181234'); - modems.removeSuffixFromNumber('08181234@phonenumber', {}).should.equal('08181234'); + modemSelect.removeSuffixFromNumber('08181234', null).should.equal('08181234'); + modemSelect.removeSuffixFromNumber('08181234', {}).should.equal('08181234'); + modemSelect.removeSuffixFromNumber('08181234@phonenumber', {}).should.equal('08181234'); }) }) -- 1.9.0