Commit b6d23624ab5093f53f9911c4f1317d77e6916635
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 | }) |
lib/modems2.js
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; |
lib/transport.js
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; |