Commit f53fe083fc8cd09e46ceb45818a36e177c3027d0

Authored by Adhidarma Hadiwinoto
1 parent 30ac636c83
Exists in master

Sender chooser algo

Showing 5 changed files with 125 additions and 7 deletions Side-by-side Diff

... ... @@ -22,5 +22,18 @@
22 22  
23 23 "do_not_trim_long_sms": false,
24 24  
25   - "default_modem": "SMS0"
  25 + "default_modem": "SMS0",
  26 +
  27 + "# handler_chooser_algorithm": "algoritma untuk memilih modem dalam mengirim SMS. Pilihan: LAST-SEEN, FORCED. Default: LAST-SEEN",
  28 + "handler_chooser_algorithm": "LAST-SEEN",
  29 +
  30 + "# sending handler": "list modem yang dipakai untuk mengirim jika handler_chooser_algorithm === 'FORCED'",
  31 + "sending_handler": [
  32 + "SMS0",
  33 + "SMS1"
  34 + ],
  35 +
  36 + "redis": {
  37 + "host": "127.0.0.1"
  38 + }
26 39 }
27 40 \ No newline at end of file
lib/handler-callback-server.js
... ... @@ -13,6 +13,7 @@ const config = require('komodo-sdk/config');
13 13 const logger = require('komodo-sdk/logger');
14 14  
15 15 const transport = require('./transport');
  16 +const partnerLastSeen = require('./partner-last-seen');
16 17  
17 18 const app = express();
18 19 messagingService.setTransport(transport);
... ... @@ -31,6 +32,8 @@ function onIncomingSms(req, res) {
31 32 res.end('OK');
32 33 const numberWithSuffix = req.query.number + (config.number_suffix || '');
33 34  
  35 + partnerLastSeen.set(req.query.number, req.query.modem);
  36 +
34 37 logger.info('HANDLER-CALLBACK-SERVER: Incoming SMS', { modem: req.query.modem, from: req.query.number, from_with_suffix: numberWithSuffix, msg: req.query.msg });
35 38 messagingService.onIncomingMessage({
36 39 me: req.query.modem,
lib/partner-last-seen.js
... ... @@ -0,0 +1,57 @@
  1 +"use strict";
  2 +
  3 +const REDIS_TTL_SECS = 3600 * 24 * 7;
  4 +
  5 +const config = require('komodo-sdk/config');
  6 +
  7 +const redis = require('redis');
  8 +const redisClient = redis.createClient(config.redis || { host: '127.0.0.1' });
  9 +
  10 +const _caches = {};
  11 +
  12 +
  13 +function _composeKeyword(partner) {
  14 + return `POCHINKI_PARTNER_LAST_SEEN_${ partner }`;
  15 +}
  16 +
  17 +function get(partnerNumber) {
  18 + return new Promise(function(resolve) {
  19 +
  20 + if (!partnerNumber) {
  21 + resolve(null);
  22 + }
  23 + else if (_caches[partnerNumber]) {
  24 + resolve(_caches[partnerNumber]);
  25 + }
  26 + else {
  27 + const keyword = _composeKeyword(partnerNumber);
  28 +
  29 + redisClient.get(keyword, function(err, reply) {
  30 + if (err) {
  31 + resolve(null);
  32 + }
  33 + else if (reply) {
  34 + resolve(Number(reply));
  35 + _caches[partnerNumber] = Number(reply);
  36 + }
  37 + else {
  38 + resolve(null);
  39 + }
  40 + })
  41 + }
  42 + })
  43 +}
  44 +
  45 +function set(partnerNumber, modemName) {
  46 + if (!partnerNumber || !modemName) {
  47 + return;
  48 + }
  49 +
  50 + _caches[partnerNumber] = modemName;
  51 +
  52 + const keyword = _composeKeyword(partnerNumber);
  53 + redisClient.set(keyword, modemName, 'EX', REDIS_TTL_SECS);
  54 +}
  55 +
  56 +exports.get = get;
  57 +exports.set = set;
... ... @@ -7,8 +7,50 @@ const config = require('komodo-sdk/config');
7 7 const logger = require('komodo-sdk/logger');
8 8  
9 9 const modems = require('./modems');
  10 +const partnerLastSeen = require('./partner-last-seen');
10 11  
11   -function send(partner, msg, origin) {
  12 +async function _getApproriateHandlerByLastSeen(partnerNumber) {
  13 + logger.verbose('Looking for last seen on for partner number ' + partnerNumber);
  14 + const lastSeenFrom = await partnerLastSeen.get(partnerNumber);
  15 + return lastSeenFrom;
  16 +}
  17 +
  18 +function _getApproriateHandlerByForced() {
  19 + if (!config.sending_handler || !config.sending_handler.length) return;
  20 +
  21 + const sendingHandlerCount = config.sending_handler.length;
  22 + const idx = Math.floor(Math.random() * sendingHandlerCount);
  23 + return config.sending_handler[idx];
  24 +}
  25 +
  26 +async function _getApproriateHandler(partnerNumber, origin) {
  27 + let handlerToUse;
  28 +
  29 + if (config.handler_chooser_algorithm === 'FORCED') {
  30 + handlerToUse = _getApproriateHandlerByForced();
  31 + logger.verbose('Config file mentioned to using FORCED handler chooser algorithm', { handler_to_use: handlerToUse});
  32 + }
  33 + else {
  34 + handlerToUse = await _getApproriateHandlerByLastSeen(partnerNumber);
  35 + logger.verbose('Config file mentioned to using LAST-SEEN handler chooser algorithm', { handler_to_use: handlerToUse});
  36 + }
  37 +
  38 + if (!modems.getModemConfig(handlerToUse, config.modems)) {
  39 + const handlerWithSameOrigin = modems.getModemConfig(origin, config.modems);
  40 + if (handlerWithSameOrigin) {
  41 + logger.verbose('Invalid approriate handler, using handler from the same ORIGIN request by CORE to send sms')
  42 + handlerToUse = origin;
  43 + }
  44 + else {
  45 + logger.verbose('Invalid approriate handler, using default handler to send sms')
  46 + handlerToUse = config.default_modem;
  47 + }
  48 + }
  49 +
  50 + return handlerToUse;
  51 +}
  52 +
  53 +async function send(partner, msg, origin) {
12 54 if (!partner) return;
13 55  
14 56 if (typeof msg !== 'string') {
... ... @@ -19,12 +61,17 @@ function send(partner, msg, origin) {
19 61 msg = msg.trim();
20 62 if (!msg) return;
21 63  
  64 + const reqId = uuidv4();
  65 +
22 66 if (msg.length > 160 && !config.do_not_trim_long_sms) {
23 67 logger.verbose('Message trim to 160 chars');
24 68 msg = msg.slice(0, 156) + ' ...';
25 69 }
26 70  
27   - const handlerName = origin || config.default_modem;
  71 + const destinationNumber = modems.removeSuffixFromNumber(partner, config);
  72 +
  73 + logger.verbose('Choosing handler name', { req_id: reqId, partner: partner, msg: msg, origin: origin });
  74 + let handlerName = ( await _getApproriateHandler(destinationNumber) );
28 75  
29 76 const modem = modems.getModemConfig(handlerName, config.modems);
30 77 if (!modem) {
... ... @@ -37,9 +84,6 @@ function send(partner, msg, origin) {
37 84 return;
38 85 }
39 86  
40   - const reqId = uuidv4();
41   - const destinationNumber = modems.removeSuffixFromNumber(partner, config);
42   -
43 87 const requestOptions = {
44 88 url: modem.url,
45 89 qs: {
... ... @@ -50,7 +94,7 @@ function send(partner, msg, origin) {
50 94 }
51 95 }
52 96  
53   - logger.info('Sending message to modem handler', { req_id: reqId, partner: partner, destination_number: destinationNumber, msg: msg, handler_name: handlerName });
  97 + logger.info('Sending message to modem handler', { req_id: reqId, partner: partner, destination_number: destinationNumber, msg: msg, msg_length: msg.length, handler_name: handlerName });
54 98 request(requestOptions, function(err, res, body) {
55 99 if (err) {
56 100 logger.warn('Error requesting to modem handler. ' + err.toString(), { req_id: reqId, handler_name: handlerName });
... ... @@ -22,6 +22,7 @@
22 22 "express": "^4.17.1",
23 23 "komodo-center-messaging-client-lib": "git+http://gitlab.kodesumber.com/komodo/komodo-center-messaging-client-lib.git",
24 24 "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git",
  25 + "redis": "^2.8.0",
25 26 "request": "^2.88.0",
26 27 "uuid": "^3.3.2"
27 28 },