Commit b6d23624ab5093f53f9911c4f1317d77e6916635

Authored by Adhidarma Hadiwinoto
1 parent 6f29a7ff5b
Exists in master

ModemData.reportPathSms

Showing 3 changed files with 4 additions and 1 deletions Inline Diff

lib/apiserver/index.js
1 "use strict"; 1 "use strict";
2 2
3 /** 3 /**
4 * Modul untuk menerima callback dari modem handler jika ada SMS masuk. 4 * Modul untuk menerima callback dari modem handler jika ada SMS masuk.
5 */ 5 */
6 6
7 7
8 const express = require('express'); 8 const express = require('express');
9 const moment = require('moment'); 9 const moment = require('moment');
10 10
11 const messagingService = require('komodo-center-messaging-client-lib'); 11 const messagingService = require('komodo-center-messaging-client-lib');
12 12
13 const config = require('komodo-sdk/config'); 13 const config = require('komodo-sdk/config');
14 const logger = require('komodo-sdk/logger'); 14 const logger = require('komodo-sdk/logger');
15 15
16 const transport = require('../transport'); 16 const transport = require('../transport');
17 const partnerLastSeen = require('../partner-last-seen'); 17 const partnerLastSeen = require('../partner-last-seen');
18 const history = require('../history'); 18 const history = require('../history');
19 const modems = require('../modems2'); 19 const modems = require('../modems2');
20 20
21 const app = express(); 21 const app = express();
22 messagingService.setTransport(transport); 22 messagingService.setTransport(transport);
23 23
24 function apikeyChecker(req, res, next) { 24 function apikeyChecker(req, res, next) {
25 res.locals.has_valid_apikey = req.params.apikey === config.handler_callback_server.apikey; 25 res.locals.has_valid_apikey = req.params.apikey === config.handler_callback_server.apikey;
26 if (res.locals.has_valid_apikey) { 26 if (res.locals.has_valid_apikey) {
27 next(); 27 next();
28 } 28 }
29 else { 29 else {
30 res.end('APISERVER: Invalid apikey'); 30 res.end('APISERVER: Invalid apikey');
31 } 31 }
32 } 32 }
33 33
34 function onIncomingSms(req, res) { 34 function onIncomingSms(req, res) {
35 res.end('OK'); 35 res.end('OK');
36 36
37 if (!req.query.number) return; 37 if (!req.query.number) return;
38 if (req.query.number.indexOf('+') !== 0) return; 38 if (req.query.number.indexOf('+') !== 0) return;
39 39
40 const numberWithSuffix = req.query.number.replace(/^\+/, '') + (config.number_suffix || ''); 40 const numberWithSuffix = req.query.number.replace(/^\+/, '') + (config.number_suffix || '');
41 41
42 partnerLastSeen.set(req.query.number, req.query.modem); 42 partnerLastSeen.set(req.query.number, req.query.modem);
43 43
44 history.push({ 44 history.push({
45 ts: req.query.ts || moment().format('YYYY-MM-DD HH:mm:ss'), 45 ts: req.query.ts || moment().format('YYYY-MM-DD HH:mm:ss'),
46 modem: { 46 modem: {
47 name: req.query.modem, 47 name: req.query.modem,
48 imsi: req.query.modem_imsi, 48 imsi: req.query.modem_imsi,
49 msisdn: req.query.modem_msisdn, 49 msisdn: req.query.modem_msisdn,
50 }, 50 },
51 direction: 'INCOMING', 51 direction: 'INCOMING',
52 partner: req.query.number, 52 partner: req.query.number,
53 message: req.query.msg, 53 message: req.query.msg,
54 }); 54 });
55 55
56 modems.set({ 56 modems.set({
57 name: req.query.modem, 57 name: req.query.modem,
58 imsi: req.query.modem_imsi, 58 imsi: req.query.modem_imsi,
59 msisdn: req.query.modem_msisdn, 59 msisdn: req.query.modem_msisdn,
60 reportIp: req.query.report_ip || req.ip, 60 reportIp: req.query.report_ip || req.ip,
61 reportPort: req.query.report_port, 61 reportPort: req.query.report_port,
62 reportApikey: req.query.report_apikey, 62 reportApikey: req.query.report_apikey,
63 reportPathSms: req.query.report_path_sms || '/sms',
63 }); 64 });
64 65
65 logger.info('APISERVER: Incoming SMS', { modem: req.query.modem, from: req.query.number, from_with_suffix: numberWithSuffix, msg: req.query.msg }); 66 logger.info('APISERVER: Incoming SMS', { modem: req.query.modem, from: req.query.number, from_with_suffix: numberWithSuffix, msg: req.query.msg });
66 messagingService.onIncomingMessage({ 67 messagingService.onIncomingMessage({
67 me: req.query.modem, 68 me: req.query.modem,
68 partner: numberWithSuffix, 69 partner: numberWithSuffix,
69 msg: req.query.msg 70 msg: req.query.msg
70 }) 71 })
71 } 72 }
72 73
73 async function pageHistory(req, res) { 74 async function pageHistory(req, res) {
74 res.json(await history.dump()); 75 res.json(await history.dump());
75 } 76 }
76 77
77 app.use(function(req, res, next) { 78 app.use(function(req, res, next) {
78 logger.verbose('APISERVER: Incoming http request', { ip: req.ip, url: req.url }); 79 logger.verbose('APISERVER: Incoming http request', { ip: req.ip, url: req.url });
79 next(); 80 next();
80 }) 81 })
81 82
82 app.use('/apikey/:apikey', apikeyChecker); 83 app.use('/apikey/:apikey', apikeyChecker);
83 app.get('/apikey/:apikey/on-sms', onIncomingSms); 84 app.get('/apikey/:apikey/on-sms', onIncomingSms);
84 app.get('/apikey/:apikey/inbox', onIncomingSms); 85 app.get('/apikey/:apikey/inbox', onIncomingSms);
85 app.get('/apikey/:apikey/on-sms/inbox', onIncomingSms); 86 app.get('/apikey/:apikey/on-sms/inbox', onIncomingSms);
86 app.get('/apikey/:apikey/history', pageHistory); 87 app.get('/apikey/:apikey/history', pageHistory);
87 88
88 const listenPort = config && config.handler_callback_server ? config.handler_callback_server.listen_port : null; 89 const listenPort = config && config.handler_callback_server ? config.handler_callback_server.listen_port : null;
89 listenPort && app.listen(listenPort, () => { 90 listenPort && app.listen(listenPort, () => {
90 logger.info('HTTP Handler Callback server listening on port ' + listenPort); 91 logger.info('HTTP Handler Callback server listening on port ' + listenPort);
91 }) 92 })
1 'use strict'; 1 'use strict';
2 2
3 const modemList = { 3 const modemList = {
4 by_name: {}, 4 by_name: {},
5 by_imsi: {}, 5 by_imsi: {},
6 by_msisdn: {}, 6 by_msisdn: {},
7 }; 7 };
8 8
9 /** 9 /**
10 * Objek data sebuah modem. 10 * Objek data sebuah modem.
11 * 11 *
12 * @typedef {Object} ModemData 12 * @typedef {Object} ModemData
13 * @property {string} name - nama modem 13 * @property {string} name - nama modem
14 * @property {string} imsi - IMSI modem 14 * @property {string} imsi - IMSI modem
15 * @property {string} msisdn - MSISDN modem 15 * @property {string} msisdn - MSISDN modem
16 * @property {string} reportIp - IP modem 16 * @property {string} reportIp - IP modem
17 * @property {number} reportPort - TCP port modem 17 * @property {number} reportPort - TCP port modem
18 * @property {string} reportApikey - APIKEY modem 18 * @property {string} reportApikey - APIKEY modem
19 * @property {string} reportPathSms - url path untuk pengiriman SMS
19 */ 20 */
20 21
21 /** 22 /**
22 * Update data sebuah modem berdasarkan nama modem. 23 * Update data sebuah modem berdasarkan nama modem.
23 * 24 *
24 * @param {ModemData} val - objek data modem 25 * @param {ModemData} val - objek data modem
25 */ 26 */
26 function touchByName(val) { 27 function touchByName(val) {
27 if (!val || !val.name) return; 28 if (!val || !val.name) return;
28 if (typeof val.name !== 'string') return; 29 if (typeof val.name !== 'string') return;
29 if (!val.name.trim()) return; 30 if (!val.name.trim()) return;
30 31
31 modemList.by_name[val.name] = val; 32 modemList.by_name[val.name] = val;
32 } 33 }
33 /** 34 /**
34 * Update data sebuah modem berdasarkan IMSI. 35 * Update data sebuah modem berdasarkan IMSI.
35 * 36 *
36 * @param {ModemData} val - objek data modem 37 * @param {ModemData} val - objek data modem
37 */ 38 */
38 function touchByIMSI(val) { 39 function touchByIMSI(val) {
39 if (!val || !val.imsi) return; 40 if (!val || !val.imsi) return;
40 if (typeof val.imsi !== 'string') return; 41 if (typeof val.imsi !== 'string') return;
41 if (!val.imsi.trim()) return; 42 if (!val.imsi.trim()) return;
42 43
43 modemList.by_imsi[val.imsi] = val; 44 modemList.by_imsi[val.imsi] = val;
44 } 45 }
45 46
46 /** 47 /**
47 * Update data sebuah modem berdasarkan MSISDN. 48 * Update data sebuah modem berdasarkan MSISDN.
48 * 49 *
49 * @param {ModemData} val - objek data modem 50 * @param {ModemData} val - objek data modem
50 */ 51 */
51 function touchByMSISDN(val) { 52 function touchByMSISDN(val) {
52 if (!val || !val.msisdn) return; 53 if (!val || !val.msisdn) return;
53 if (typeof val.msisdn !== 'string') return; 54 if (typeof val.msisdn !== 'string') return;
54 if (!val.msisdn.trim()) return; 55 if (!val.msisdn.trim()) return;
55 56
56 modemList.by_msisdn[val.msisdn] = val; 57 modemList.by_msisdn[val.msisdn] = val;
57 } 58 }
58 59
59 /** 60 /**
60 * Update data sebuah modem. 61 * Update data sebuah modem.
61 * 62 *
62 * @param {ModemData} val - objek data modem 63 * @param {ModemData} val - objek data modem
63 * @see ModemData 64 * @see ModemData
64 */ 65 */
65 function touch(val) { 66 function touch(val) {
66 if (!val) return; 67 if (!val) return;
67 68
68 if (!val.reportIp) { 69 if (!val.reportIp) {
69 val.reportIp = '127.0.0.1'; 70 val.reportIp = '127.0.0.1';
70 } 71 }
71 72
72 touchByName(val); 73 touchByName(val);
73 touchByIMSI(val); 74 touchByIMSI(val);
74 touchByMSISDN(val); 75 touchByMSISDN(val);
75 } 76 }
76 /** 77 /**
77 * Ambil data sebuah modem. 78 * Ambil data sebuah modem.
78 * 79 *
79 * @param {string} selector - selector pencarian, valid jika bernilai salah satu dari: name, imsi, msisdn 80 * @param {string} selector - selector pencarian, valid jika bernilai salah satu dari: name, imsi, msisdn
80 * @param {string} keyword - kata kunci modem yang ingin diambil 81 * @param {string} keyword - kata kunci modem yang ingin diambil
81 * @returns {ModemData} data modem terkait 82 * @returns {ModemData} data modem terkait
82 */ 83 */
83 function get(selector, keyword) { 84 function get(selector, keyword) {
84 if (!selector || !keyword) return null; 85 if (!selector || !keyword) return null;
85 86
86 return modemList[`by_${selector}`] ? modemList[`by_${selector}`][keyword] : null; 87 return modemList[`by_${selector}`] ? modemList[`by_${selector}`][keyword] : null;
87 } 88 }
88 89
89 exports.touch = touch; 90 exports.touch = touch;
90 exports.set = touch; 91 exports.set = touch;
91 exports.get = get; 92 exports.get = get;
1 "use strict"; 1 "use strict";
2 2
3 const url = require('url'); 3 const url = require('url');
4 const request = require('request'); 4 const request = require('request');
5 const uuidv4 = require('uuid/v4'); 5 const uuidv4 = require('uuid/v4');
6 const moment = require('moment'); 6 const moment = require('moment');
7 7
8 const config = require('komodo-sdk/config'); 8 const config = require('komodo-sdk/config');
9 const logger = require('komodo-sdk/logger'); 9 const logger = require('komodo-sdk/logger');
10 10
11 const modemSelect = require('./modemSelect'); 11 const modemSelect = require('./modemSelect');
12 const modems = require('./modems2'); 12 const modems = require('./modems2');
13 const partnerLastSeen = require('./partner-last-seen'); 13 const partnerLastSeen = require('./partner-last-seen');
14 const history = require('./history'); 14 const history = require('./history');
15 15
16 function _send(destinationNumber, msg, handlerName) { 16 function _send(destinationNumber, msg, handlerName) {
17 17
18 if (msg.length > 160) { 18 if (msg.length > 160) {
19 const newMsg = msg.slice(0, 160); 19 const newMsg = msg.slice(0, 160);
20 const remainingMsg = msg.slice(160); 20 const remainingMsg = msg.slice(160);
21 21
22 _send(destinationNumber, newMsg, handlerName); 22 _send(destinationNumber, newMsg, handlerName);
23 setTimeout(() => { 23 setTimeout(() => {
24 _send(destinationNumber, remainingMsg, handlerName); 24 _send(destinationNumber, remainingMsg, handlerName);
25 }, 2000); 25 }, 2000);
26 26
27 return; 27 return;
28 } 28 }
29 29
30 const modem = modems.get('name', handlerName); 30 const modem = modems.get('name', handlerName);
31 if (!modem) { 31 if (!modem) {
32 logger.warn('Not knowing modem to use. Ignoring message', { destination_number: destinationNumber, msg: msg, handler_name: handlerName }); 32 logger.warn('Not knowing modem to use. Ignoring message', { destination_number: destinationNumber, msg: msg, handler_name: handlerName });
33 return; 33 return;
34 } 34 }
35 35
36 if (!modem.reportIp || !modem.reportPort || !modem.reportApikey) { 36 if (!modem.reportIp || !modem.reportPort || !modem.reportApikey) {
37 logger.warn('Invalid modem configuration', { modem }); 37 logger.warn('Invalid modem configuration', { modem });
38 return; 38 return;
39 } 39 }
40 40
41 const reqId = uuidv4(); 41 const reqId = uuidv4();
42 42
43 history.push({ 43 history.push({
44 ts: moment().format('YYYY-MM-DD HH:mm:ss'), 44 ts: moment().format('YYYY-MM-DD HH:mm:ss'),
45 modem: { 45 modem: {
46 name: handlerName, 46 name: handlerName,
47 }, 47 },
48 direction: 'OUTGOING', 48 direction: 'OUTGOING',
49 partner: destinationNumber, 49 partner: destinationNumber,
50 message: msg, 50 message: msg,
51 }); 51 });
52 52
53 const requestOptions = { 53 const requestOptions = {
54 url: url.format({ 54 url: url.format({
55 protocol: 'http', 55 protocol: 'http',
56 hostname: modem.reportIp, 56 hostname: modem.reportIp,
57 port: modem.reportPort, 57 port: modem.reportPort,
58 pathname: modem.reportPathSms,
58 }), 59 }),
59 qs: { 60 qs: {
60 msg: msg, 61 msg: msg,
61 number: destinationNumber, 62 number: destinationNumber,
62 reqid: reqId, 63 reqid: reqId,
63 apikey: modem.reportApikey 64 apikey: modem.reportApikey,
64 } 65 }
65 } 66 }
66 67
67 logger.info('Sending message to modem handler', { req_id: reqId, destination_number: destinationNumber, msg: msg, msg_length: msg.length, handler_name: handlerName }); 68 logger.info('Sending message to modem handler', { req_id: reqId, destination_number: destinationNumber, msg: msg, msg_length: msg.length, handler_name: handlerName });
68 request(requestOptions, function(err, res, body) { 69 request(requestOptions, function(err, res, body) {
69 if (err) { 70 if (err) {
70 logger.warn('Error requesting to modem handler. ' + err.toString(), { req_id: reqId, handler_name: handlerName }); 71 logger.warn('Error requesting to modem handler. ' + err.toString(), { req_id: reqId, handler_name: handlerName });
71 72
72 } 73 }
73 else if (res.statusCode != 200) { 74 else if (res.statusCode != 200) {
74 logger.warn('Modem handler not responding with HTTP status code 200.', { http_status_code: res.statusCode, req_id: reqId, handler_name: handlerName }); 75 logger.warn('Modem handler not responding with HTTP status code 200.', { http_status_code: res.statusCode, req_id: reqId, handler_name: handlerName });
75 } 76 }
76 else { 77 else {
77 logger.verbose('Message sent to handler', { req_id: reqId, handler_name: handlerName, response_body: body }); 78 logger.verbose('Message sent to handler', { req_id: reqId, handler_name: handlerName, response_body: body });
78 } 79 }
79 }) 80 })
80 81
81 } 82 }
82 83
83 async function send(partner, msg) { 84 async function send(partner, msg) {
84 if (!partner) return; 85 if (!partner) return;
85 86
86 if (typeof msg !== 'string') { 87 if (typeof msg !== 'string') {
87 logger.warn('Message to send is not a string, ignoring message'); 88 logger.warn('Message to send is not a string, ignoring message');
88 return; 89 return;
89 } 90 }
90 91
91 msg = msg.trim(); 92 msg = msg.trim();
92 if (!msg) return; 93 if (!msg) return;
93 94
94 const destinationNumber = modemSelect.removeSuffixFromNumber(partner, config); 95 const destinationNumber = modemSelect.removeSuffixFromNumber(partner, config);
95 96
96 // logger.verbose('Choosing handler name', { partner, destinationNumber, msg, origin }); 97 // logger.verbose('Choosing handler name', { partner, destinationNumber, msg, origin });
97 let handlerName = await partnerLastSeen.get(destinationNumber) ; 98 let handlerName = await partnerLastSeen.get(destinationNumber) ;
98 99
99 if (!handlerName) { 100 if (!handlerName) {
100 logger.warn(`Unknown handler for sending message to partner`, { partner, destinationNumber }); 101 logger.warn(`Unknown handler for sending message to partner`, { partner, destinationNumber });
101 return; 102 return;
102 } 103 }
103 104
104 _send(destinationNumber, msg, handlerName); 105 _send(destinationNumber, msg, handlerName);
105 } 106 }
106 107
107 exports.send = send; 108 exports.send = send;