diff --git a/config.sample.json b/config.sample.json index a0b3b3c..fc4e151 100644 --- a/config.sample.json +++ b/config.sample.json @@ -22,5 +22,18 @@ "do_not_trim_long_sms": false, - "default_modem": "SMS0" + "default_modem": "SMS0", + + "# handler_chooser_algorithm": "algoritma untuk memilih modem dalam mengirim SMS. Pilihan: LAST-SEEN, FORCED. Default: LAST-SEEN", + "handler_chooser_algorithm": "LAST-SEEN", + + "# sending handler": "list modem yang dipakai untuk mengirim jika handler_chooser_algorithm === 'FORCED'", + "sending_handler": [ + "SMS0", + "SMS1" + ], + + "redis": { + "host": "127.0.0.1" + } } \ No newline at end of file diff --git a/lib/handler-callback-server.js b/lib/handler-callback-server.js index 20d3b01..a04312b 100644 --- a/lib/handler-callback-server.js +++ b/lib/handler-callback-server.js @@ -13,6 +13,7 @@ const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); const transport = require('./transport'); +const partnerLastSeen = require('./partner-last-seen'); const app = express(); messagingService.setTransport(transport); @@ -31,6 +32,8 @@ function onIncomingSms(req, res) { res.end('OK'); const numberWithSuffix = req.query.number + (config.number_suffix || ''); + partnerLastSeen.set(req.query.number, req.query.modem); + logger.info('HANDLER-CALLBACK-SERVER: 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/partner-last-seen.js b/lib/partner-last-seen.js new file mode 100644 index 0000000..b228372 --- /dev/null +++ b/lib/partner-last-seen.js @@ -0,0 +1,57 @@ +"use strict"; + +const REDIS_TTL_SECS = 3600 * 24 * 7; + +const config = require('komodo-sdk/config'); + +const redis = require('redis'); +const redisClient = redis.createClient(config.redis || { host: '127.0.0.1' }); + +const _caches = {}; + + +function _composeKeyword(partner) { + return `POCHINKI_PARTNER_LAST_SEEN_${ partner }`; +} + +function get(partnerNumber) { + return new Promise(function(resolve) { + + if (!partnerNumber) { + resolve(null); + } + else if (_caches[partnerNumber]) { + resolve(_caches[partnerNumber]); + } + else { + const keyword = _composeKeyword(partnerNumber); + + redisClient.get(keyword, function(err, reply) { + if (err) { + resolve(null); + } + else if (reply) { + resolve(Number(reply)); + _caches[partnerNumber] = Number(reply); + } + else { + resolve(null); + } + }) + } + }) +} + +function set(partnerNumber, modemName) { + if (!partnerNumber || !modemName) { + return; + } + + _caches[partnerNumber] = modemName; + + const keyword = _composeKeyword(partnerNumber); + redisClient.set(keyword, modemName, 'EX', REDIS_TTL_SECS); +} + +exports.get = get; +exports.set = set; diff --git a/lib/transport.js b/lib/transport.js index 9e2e96c..c6c9932 100644 --- a/lib/transport.js +++ b/lib/transport.js @@ -7,8 +7,50 @@ const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); const modems = require('./modems'); +const partnerLastSeen = require('./partner-last-seen'); -function send(partner, msg, origin) { +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; +} + +async function send(partner, msg, origin) { if (!partner) return; if (typeof msg !== 'string') { @@ -19,12 +61,17 @@ function send(partner, msg, origin) { msg = msg.trim(); if (!msg) return; + const reqId = uuidv4(); + if (msg.length > 160 && !config.do_not_trim_long_sms) { logger.verbose('Message trim to 160 chars'); msg = msg.slice(0, 156) + ' ...'; } - const handlerName = origin || config.default_modem; + const destinationNumber = modems.removeSuffixFromNumber(partner, config); + + logger.verbose('Choosing handler name', { req_id: reqId, partner: partner, msg: msg, origin: origin }); + let handlerName = ( await _getApproriateHandler(destinationNumber) ); const modem = modems.getModemConfig(handlerName, config.modems); if (!modem) { @@ -37,9 +84,6 @@ function send(partner, msg, origin) { return; } - const reqId = uuidv4(); - const destinationNumber = modems.removeSuffixFromNumber(partner, config); - const requestOptions = { url: modem.url, qs: { @@ -50,7 +94,7 @@ function send(partner, msg, origin) { } } - logger.info('Sending message to modem handler', { req_id: reqId, partner: partner, destination_number: destinationNumber, msg: msg, handler_name: handlerName }); + logger.info('Sending message to modem handler', { req_id: reqId, partner: partner, destination_number: destinationNumber, msg: msg, msg_length: msg.length, handler_name: handlerName }); request(requestOptions, function(err, res, body) { if (err) { logger.warn('Error requesting to modem handler. ' + err.toString(), { req_id: reqId, handler_name: handlerName }); diff --git a/package.json b/package.json index dd104a6..e3cb49e 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "express": "^4.17.1", "komodo-center-messaging-client-lib": "git+http://gitlab.kodesumber.com/komodo/komodo-center-messaging-client-lib.git", "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", + "redis": "^2.8.0", "request": "^2.88.0", "uuid": "^3.3.2" },