mirror of
https://github.com/jambonz/sbc-inbound.git
synced 2026-10-04 02:04:22 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
563ea405e9 | ||
|
|
8cd91c19c9 | ||
|
|
994904e8e7 | ||
|
|
874d1804e1 | ||
|
|
9475b776be | ||
|
|
a3799576a2 | ||
|
|
63e72fbfce | ||
|
|
e5dce35bab | ||
|
|
b6675de2bd | ||
|
|
66e73d8353 | ||
|
|
a25aa08e17 | ||
|
|
b1296c8e89 | ||
|
|
17df3a4ca8 | ||
|
|
f2e820915d |
@@ -33,7 +33,10 @@ const JAMBONES_REDIS_SENTINELS = process.env.JAMBONES_REDIS_SENTINELS ? {
|
||||
}),
|
||||
...(process.env.JAMBONES_REDIS_SENTINEL_USERNAME && {
|
||||
username: process.env.JAMBONES_REDIS_SENTINEL_USERNAME
|
||||
})
|
||||
}),
|
||||
...(process.env.JAMBONES_REDIS_SENTINEL_SENTINAL_PASSWORD && {
|
||||
sentinelPassword: process.env.JAMBONES_REDIS_SENTINEL_SENTINAL_PASSWORD
|
||||
}),
|
||||
} : null;
|
||||
|
||||
const Srf = require('drachtio-srf');
|
||||
@@ -64,6 +67,7 @@ const {LifeCycleEvents} = require('./lib/constants');
|
||||
const setNameRtp = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-rtp`;
|
||||
const rtpServers = [];
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-sip`;
|
||||
const Registrar = require('@jambonz/mw-registrar');
|
||||
|
||||
const {
|
||||
pool,
|
||||
@@ -77,7 +81,8 @@ const {
|
||||
lookupAccountBySid,
|
||||
lookupAccountCapacitiesBySid,
|
||||
queryCallLimits,
|
||||
lookupClientByAccountAndUsername
|
||||
lookupClientByAccountAndUsername,
|
||||
lookupAppBySid
|
||||
} = require('@jambonz/db-helpers')({
|
||||
host: process.env.JAMBONES_MYSQL_HOST,
|
||||
port: process.env.JAMBONES_MYSQL_PORT || 3306,
|
||||
@@ -97,6 +102,7 @@ const {
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
const registrar = new Registrar(logger, redisClient);
|
||||
|
||||
const ngProtocol = process.env.JAMBONES_NG_PROTOCOL || 'udp';
|
||||
const ngPort = process.env.RTPENGINE_PORT || ('udp' === ngProtocol ? 22222 : 8080);
|
||||
@@ -117,6 +123,7 @@ srf.locals = {...srf.locals,
|
||||
activeCallIds: new Map(),
|
||||
getRtpEngine,
|
||||
dbHelpers: {
|
||||
registrar,
|
||||
pool,
|
||||
ping,
|
||||
lookupAuthHook,
|
||||
@@ -127,7 +134,8 @@ srf.locals = {...srf.locals,
|
||||
lookupAccountBySipRealm,
|
||||
lookupAccountCapacitiesBySid,
|
||||
queryCallLimits,
|
||||
lookupClientByAccountAndUsername
|
||||
lookupClientByAccountAndUsername,
|
||||
lookupAppBySid
|
||||
},
|
||||
realtimeDbHelpers: {
|
||||
createSet,
|
||||
|
||||
+54
-31
@@ -64,6 +64,7 @@ class CallSession extends Emitter {
|
||||
this.application_sid = req.locals.application_sid;
|
||||
this.account_sid = req.locals.account_sid;
|
||||
this.service_provider_sid = req.locals.service_provider_sid;
|
||||
this.srsClients = [];
|
||||
}
|
||||
|
||||
get isFromMSTeams() {
|
||||
@@ -223,6 +224,12 @@ class CallSession extends Emitter {
|
||||
if (this.req.locals.application_sid) {
|
||||
Object.assign(headers, {'X-Application-Sid': this.req.locals.application_sid});
|
||||
}
|
||||
if (this.req.locals.queue_name) {
|
||||
Object.assign(headers, {'X-Queue-Name': this.req.locals.queue_name});
|
||||
}
|
||||
if (this.req.locals.called_user) {
|
||||
Object.assign(headers, {'X-Called-User': this.req.locals.called_user});
|
||||
}
|
||||
if (this.req.authorization) {
|
||||
if (this.req.authorization.grant && this.req.authorization.grant.application_sid) {
|
||||
Object.assign(headers, {'X-Application-Sid': this.req.authorization.grant.application_sid});
|
||||
@@ -247,7 +254,7 @@ class CallSession extends Emitter {
|
||||
'-Max-Forwards',
|
||||
'-Record-Route',
|
||||
'-Session-Expires',
|
||||
'-X-Subspace-Forwarded-For'
|
||||
'-X-Subspace-Forwarded-For',
|
||||
],
|
||||
proxyResponseHeaders: ['all', '-X-Trace-ID'],
|
||||
localSdpB: spdOfferB,
|
||||
@@ -317,10 +324,7 @@ class CallSession extends Emitter {
|
||||
this.activeCallIds.delete(callId);
|
||||
if (dlg.other && dlg.other.connected) dlg.other.destroy().catch((e) => {});
|
||||
|
||||
if (this.srsClient) {
|
||||
this.srsClient.stop();
|
||||
this.srsClient = null;
|
||||
}
|
||||
this._stopRecording();
|
||||
|
||||
this.srf.endSession(this.req);
|
||||
});
|
||||
@@ -329,6 +333,13 @@ class CallSession extends Emitter {
|
||||
dlg.on('modify', this._onReinvite.bind(this, dlg));
|
||||
}
|
||||
|
||||
_stopRecording() {
|
||||
if (this.srsClients.length) {
|
||||
this.srsClients.forEach((c) => c.stop());
|
||||
this.srsClients = [];
|
||||
}
|
||||
}
|
||||
|
||||
_setHandlers({uas, uac}) {
|
||||
this.emit('connected');
|
||||
const callStart = Date.now();
|
||||
@@ -412,10 +423,7 @@ class CallSession extends Emitter {
|
||||
dlg.other = null;
|
||||
other.other = null;
|
||||
|
||||
if (this.srsClient) {
|
||||
this.srsClient.stop();
|
||||
this.srsClient = null;
|
||||
}
|
||||
this._stopRecording();
|
||||
|
||||
this.logger.info(`call ended with normal termination, there are ${this.activeCallIds.size} active`);
|
||||
this.srf.endSession(this.req);
|
||||
@@ -689,6 +697,7 @@ Duration=${payload.duration} `
|
||||
const to = this.req.getParsedHeader('To');
|
||||
const aorFrom = from.uri;
|
||||
const aorTo = to.uri;
|
||||
const headers = contentType === 'application/json' && req.body ? JSON.parse(req.body) : {};
|
||||
this.logger.info({to, from}, 'startCallRecording request for a call');
|
||||
|
||||
const srsUrl = req.get('X-Srs-Url');
|
||||
@@ -696,7 +705,7 @@ Duration=${payload.duration} `
|
||||
const callSid = req.get('X-Call-Sid');
|
||||
const accountSid = req.get('X-Account-Sid');
|
||||
const applicationSid = req.get('X-Application-Sid');
|
||||
if (this.srsClient) {
|
||||
if (this.srsClients.length) {
|
||||
res.send(400);
|
||||
this.logger.info('discarding duplicate startCallRecording request for a call');
|
||||
return;
|
||||
@@ -706,13 +715,14 @@ Duration=${payload.duration} `
|
||||
res.send(400);
|
||||
return;
|
||||
}
|
||||
this.srsClient = new SrsClient(this.logger, {
|
||||
const arr = srsUrl.split(',');
|
||||
this.srsClients = arr.map((url) => new SrsClient(this.logger, {
|
||||
srf: dlg.srf,
|
||||
direction: 'inbound',
|
||||
originalInvite: this.req,
|
||||
callingNumber: this.req.callingNumber,
|
||||
calledNumber: this.req.calledNumber,
|
||||
srsUrl,
|
||||
srsUrl: url,
|
||||
srsRecordingId,
|
||||
callSid,
|
||||
accountSid,
|
||||
@@ -727,42 +737,51 @@ Duration=${payload.duration} `
|
||||
del: this.del,
|
||||
blockMedia: this.blockMedia,
|
||||
unblockMedia: this.unblockMedia,
|
||||
unsubscribe: this.unsubscribe
|
||||
});
|
||||
unsubscribe: this.unsubscribe,
|
||||
headers
|
||||
}));
|
||||
try {
|
||||
succeeded = await this.srsClient.start();
|
||||
succeeded = (await Promise.all(
|
||||
this.srsClients.map((c) => c.start())
|
||||
)).every((r) => r);
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error starting SipRec call recording');
|
||||
}
|
||||
}
|
||||
else if (reason === 'stopCallRecording') {
|
||||
if (!this.srsClient) {
|
||||
if (!this.srsClients.length) {
|
||||
res.send(400);
|
||||
this.logger.info('discarding stopCallRecording request because we are not recording');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
succeeded = await this.srsClient.stop();
|
||||
succeeded = (await Promise.all(
|
||||
this.srsClients.map((c) => c.stop())
|
||||
)).every((r) => r);
|
||||
} catch (err) {
|
||||
this.logger.error({err}, 'Error stopping SipRec call recording');
|
||||
}
|
||||
this.srsClient = null;
|
||||
this.srsClients = [];
|
||||
}
|
||||
else if (reason === 'pauseCallRecording') {
|
||||
if (!this.srsClient || this.srsClient.paused) {
|
||||
if (!this.srsClients.length || this.srsClients.every((c) => c.paused)) {
|
||||
this.logger.info('discarding invalid pauseCallRecording request');
|
||||
res.send(400);
|
||||
return;
|
||||
}
|
||||
succeeded = await this.srsClient.pause();
|
||||
succeeded = (await Promise.all(
|
||||
this.srsClients.map((c) => c.pause())
|
||||
)).every((r) => r);
|
||||
}
|
||||
else if (reason === 'resumeCallRecording') {
|
||||
if (!this.srsClient || !this.srsClient.paused) {
|
||||
if (!this.srsClients.length || !this.srsClients.every((c) => c.paused)) {
|
||||
res.send(400);
|
||||
this.logger.info('discarding invalid resumeCallRecording request');
|
||||
return;
|
||||
}
|
||||
succeeded = await this.srsClient.resume();
|
||||
succeeded = (await Promise.all(
|
||||
this.srsClients.map((c) => c.resume())
|
||||
)).every((r) => r);
|
||||
}
|
||||
res.send(succeeded ? 200 : 503);
|
||||
}
|
||||
@@ -815,8 +834,8 @@ Duration=${payload.duration} `
|
||||
res.send(response.status, {headers: responseHeaders, body: response.body});
|
||||
}
|
||||
} catch (err) {
|
||||
if (this.srsClient) {
|
||||
this.srsClient = null;
|
||||
if (this.srsClients.length) {
|
||||
this.srsClients = [];
|
||||
}
|
||||
res.send(500);
|
||||
this.logger.info({err}, `Error handing INFO request on ${dlg.type} leg`);
|
||||
@@ -891,6 +910,7 @@ Duration=${payload.duration} `
|
||||
this.uac = uac;
|
||||
uac.other = this.uas;
|
||||
this.uas.other = uac;
|
||||
uac.on('info', this._onInfo.bind(this, uac));
|
||||
uac.on('modify', this._onReinvite.bind(this, uac));
|
||||
uac.on('refer', this._onFeatureServerTransfer.bind(this, uac));
|
||||
uac.on('destroy', () => {
|
||||
@@ -900,19 +920,22 @@ Duration=${payload.duration} `
|
||||
uac.other.destroy();
|
||||
this.srf.endSession(this.req);
|
||||
});
|
||||
// now we can destroy the old dialog
|
||||
dlg.destroy().catch(() => {});
|
||||
|
||||
// modify rtpengine to stream to new feature server
|
||||
const opts = Object.assign({sdp: uac.remote.sdp, 'to-tag': res.getParsedHeader('To').params.tag},
|
||||
this.rtpEngineOpts.answer);
|
||||
const opts = {
|
||||
...this.rtpEngineOpts.common,
|
||||
'from-tag': this.rtpEngineOpts.uas.tag,
|
||||
'to-tag': this.rtpEngineOpts.uac.tag,
|
||||
sdp: uac.remote.sdp,
|
||||
flags: ['port latching']
|
||||
};
|
||||
const response = await this.answer(opts);
|
||||
if ('ok' !== response.result) {
|
||||
res.send(488);
|
||||
throw new Error(`_onFeatureServerTransfer: rtpengine failed: ${JSON.stringify(response)}`);
|
||||
throw new Error(`_onFeatureServerTransfer: rtpengine answer failed: ${JSON.stringify(response)}`);
|
||||
}
|
||||
dlg.destroy().catch(() => {});
|
||||
this.logger.info('successfully moved call to new feature server');
|
||||
} catch (err) {
|
||||
res.send(488);
|
||||
this.logger.error(err, 'Error handling refer from feature server');
|
||||
}
|
||||
}
|
||||
|
||||
+38
-18
@@ -45,7 +45,7 @@ AND vc.is_active = 1
|
||||
AND sg.inbound = 1
|
||||
AND sg.voip_carrier_sid = vc.voip_carrier_sid`;
|
||||
|
||||
const sqlAccountByRealm = 'SELECT * from accounts WHERE sip_realm = ?';
|
||||
const sqlAccountByRealm = 'SELECT * from accounts WHERE sip_realm = ? AND is_active = 1';
|
||||
const sqlAccountBySid = 'SELECT * from accounts WHERE account_sid = ?';
|
||||
const sqlApplicationBySid = 'SELECT * from applications WHERE application_sid = ?';
|
||||
|
||||
@@ -153,24 +153,41 @@ module.exports = (srf, logger) => {
|
||||
* Let's look for case #1 first...
|
||||
*/
|
||||
|
||||
/* get all the carriers and gateways for the account owning this sip realm */
|
||||
const [gwAcc] = await pp.query(sqlSelectAllCarriersForAccountByRealm, [uri.host]);
|
||||
const [gwSP] = gwAcc.length ? [[]] : await pp.query(sqlSelectAllCarriersForSPByRealm, uri.host);
|
||||
const gw = gwAcc.concat(gwSP);
|
||||
const selected = gw.find(gatewayMatchesSourceAddress.bind(null, logger, req.source_address));
|
||||
if (selected) {
|
||||
const [a] = await pp.query(sqlAccountByRealm, [uri.host]);
|
||||
if (0 === a.length) return failure;
|
||||
return {
|
||||
fromCarrier: true,
|
||||
gateway: selected,
|
||||
service_provider_sid: a[0].service_provider_sid,
|
||||
account_sid: a[0].account_sid,
|
||||
application_sid: selected.application_sid,
|
||||
account: a[0]
|
||||
};
|
||||
/* does anyone own this sip realm? */
|
||||
const [a] = await pp.query(sqlAccountByRealm, [uri.host]);
|
||||
if (a.length) {
|
||||
assert(a.length === 1);
|
||||
|
||||
/* yes they do */
|
||||
logger.debug(`sip realm is associated with account_sid: ${a[0].account_sid}`);
|
||||
|
||||
/**
|
||||
* We have one of two cases:
|
||||
* (1a). The user configured his or her carrier to send to their sip realm, or
|
||||
* (1b). The user is making a call from a sip device.
|
||||
*/
|
||||
|
||||
/* get all the carriers and gateways for the account owning this sip realm */
|
||||
const [gwAcc] = await pp.query(sqlSelectAllCarriersForAccountByRealm, [uri.host]);
|
||||
const [gwSP] = gwAcc.length ? [[]] : await pp.query(sqlSelectAllCarriersForSPByRealm, uri.host);
|
||||
const gw = gwAcc
|
||||
.concat(gwSP)
|
||||
.sort((a, b) => b.netmask - a.netmask);
|
||||
const selected = gw.find(gatewayMatchesSourceAddress.bind(null, logger, req.source_address));
|
||||
if (selected) {
|
||||
return {
|
||||
fromCarrier: true,
|
||||
gateway: selected,
|
||||
service_provider_sid: a[0].service_provider_sid,
|
||||
account_sid: a[0].account_sid,
|
||||
application_sid: selected.application_sid,
|
||||
account: a[0]
|
||||
};
|
||||
}
|
||||
return failure;
|
||||
}
|
||||
|
||||
|
||||
/* no match, so let's look for case #2 */
|
||||
try {
|
||||
logger.info({
|
||||
@@ -178,7 +195,9 @@ module.exports = (srf, logger) => {
|
||||
user: uri.user
|
||||
}, 'sip realm is not associated with an account, checking carriers');
|
||||
const [gw] = await pp.query(sqlSelectCarrierRequiringRegistration, [uri.host, uri.user]);
|
||||
const matches = gw.filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address));
|
||||
const matches = gw
|
||||
.sort((a, b) => b.netmask - a.netmask)
|
||||
.filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address));
|
||||
if (1 === matches.length) {
|
||||
// bingo
|
||||
//TODO: this assumes the carrier is associate to an account, not an SP
|
||||
@@ -229,6 +248,7 @@ module.exports = (srf, logger) => {
|
||||
/* find all carrier entries that have an inbound gateway matching the source IP */
|
||||
const [gw] = await pp.query(sqlSelectAllGatewaysForSP);
|
||||
let matches = gw
|
||||
.sort((a, b) => b.netmask - a.netmask)
|
||||
.filter(gatewayMatchesSourceAddress.bind(null, logger, req.source_address))
|
||||
.map((gw) => {
|
||||
return {
|
||||
|
||||
+30
-7
@@ -1,7 +1,7 @@
|
||||
const debug = require('debug')('jambonz:sbc-inbound');
|
||||
const assert = require('assert');
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const {nudgeCallCounts, roundTripTime} = require('./utils');
|
||||
const {nudgeCallCounts, roundTripTime, isMSTeamsCIDR} = require('./utils');
|
||||
const digestChallenge = require('@jambonz/digest-utils');
|
||||
const msProxyIps = process.env.MS_TEAMS_SIP_PROXY_IPS ?
|
||||
process.env.MS_TEAMS_SIP_PROXY_IPS.split(',').map((i) => i.trim()) :
|
||||
@@ -28,7 +28,9 @@ module.exports = function(srf, logger) {
|
||||
lookupAccountBySipRealm,
|
||||
lookupAccountBySid,
|
||||
lookupAccountCapacitiesBySid,
|
||||
queryCallLimits
|
||||
queryCallLimits,
|
||||
lookupAppBySid,
|
||||
registrar
|
||||
} = srf.locals.dbHelpers;
|
||||
const {stats, writeCdrs} = srf.locals;
|
||||
|
||||
@@ -129,7 +131,7 @@ module.exports = function(srf, logger) {
|
||||
logger.info('identifyAccount: rejecting call from carrier because DID has not been provisioned');
|
||||
return res.send(404, 'Number Not Provisioned');
|
||||
}
|
||||
logger.debug({gateway}, 'identifyAccount: incoming call from gateway');
|
||||
logger.info({gateway}, 'identifyAccount: incoming call from gateway');
|
||||
|
||||
let sid;
|
||||
if (siprec) {
|
||||
@@ -155,8 +157,8 @@ module.exports = function(srf, logger) {
|
||||
...req.locals
|
||||
};
|
||||
}
|
||||
else if (msProxyIps.includes(req.source_address)) {
|
||||
logger.debug({source_address: req.source_address}, 'identifyAccount: incoming call from Microsoft Teams');
|
||||
else if (msProxyIps.includes(req.source_address) || isMSTeamsCIDR(req.source_address)) {
|
||||
logger.info({source_address: req.source_address}, 'identifyAccount: incoming call from Microsoft Teams');
|
||||
const uri = parseUri(req.uri);
|
||||
|
||||
const app = await lookupAppByTeamsTenant(uri.host);
|
||||
@@ -178,7 +180,7 @@ module.exports = function(srf, logger) {
|
||||
else {
|
||||
req.locals.originator = 'user';
|
||||
const uri = parseUri(req.uri);
|
||||
logger.debug({source_address: req.source_address, realm: uri.host},
|
||||
logger.info({source_address: req.source_address, realm: uri.host},
|
||||
'identifyAccount: incoming user call');
|
||||
const account = await lookupAccountBySipRealm(uri.host);
|
||||
if (!account) {
|
||||
@@ -196,11 +198,32 @@ module.exports = function(srf, logger) {
|
||||
res.send(404);
|
||||
return req.srf.endSession(req);
|
||||
}
|
||||
let deviceAppSid = null;
|
||||
let called_user = null;
|
||||
const queue_name = uri.user.startsWith('queue-') ? uri.user.match(/queue-(.*)/)[1] : null;
|
||||
if (uri.user.startsWith('app-')) {
|
||||
// Call from registered device to test application.
|
||||
const appSid = uri.user.match(/app-(.*)/)[1];
|
||||
const app = await lookupAppBySid(appSid);
|
||||
if (app && app.account_sid === account.account_sid) {
|
||||
deviceAppSid = app.application_sid;
|
||||
}
|
||||
} else if (!queue_name) {
|
||||
// check if call to registered user
|
||||
const {realm} = this.req.authorization.challengeResponse;
|
||||
const calledAor = `${req.calledNumber}@${realm}`;
|
||||
const reg = await registrar.query(calledAor);
|
||||
if (reg) {
|
||||
called_user = calledAor;
|
||||
}
|
||||
}
|
||||
req.locals = {
|
||||
service_provider_sid: account.service_provider_sid,
|
||||
account_sid: account.account_sid,
|
||||
account,
|
||||
application_sid: account.device_calling_application_sid,
|
||||
application_sid: deviceAppSid || account.device_calling_application_sid,
|
||||
...(queue_name && ({queue_name})),
|
||||
...(called_user && ({called_user})),
|
||||
webhook_secret: account.webhook_secret,
|
||||
realm: uri.host,
|
||||
...(account.registration_hook && {
|
||||
|
||||
+19
-2
@@ -1,5 +1,8 @@
|
||||
const CIDRMatcher = require('cidr-matcher');
|
||||
const express = require('express');
|
||||
const rtpCharacteristics = require('../data/rtp-transcoding');
|
||||
const srtpCharacteristics = require('../data/srtp-transcoding');
|
||||
|
||||
let idx = 0;
|
||||
|
||||
const isWSS = (req) => {
|
||||
@@ -96,7 +99,6 @@ const handleErrors = (logger, app, resolve, reject, e) => {
|
||||
|
||||
|
||||
const createHealthCheckApp = (port, logger) => {
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
@@ -178,6 +180,20 @@ const parseConnectionIp = (sdp) => {
|
||||
return arr ? arr[1] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if ip is one of MS Teams sip signalling ips
|
||||
* https://learn.microsoft.com/en-us/azure/communication-services/concepts
|
||||
* /telephony/direct-routing-infrastructure#sip-signaling-fqdns
|
||||
* @param ip IP address, example 172.31.0.1
|
||||
* */
|
||||
const isMSTeamsCIDR = (ip) => {
|
||||
const cidrs = [
|
||||
'52.112.0.0/14',
|
||||
'52.120.0.0/14'
|
||||
];
|
||||
const matcher = new CIDRMatcher(cidrs);
|
||||
return matcher.contains(ip);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
isWSS,
|
||||
@@ -194,5 +210,6 @@ module.exports = {
|
||||
createHealthCheckApp,
|
||||
nudgeCallCounts,
|
||||
roundTripTime,
|
||||
parseConnectionIp
|
||||
parseConnectionIp,
|
||||
isMSTeamsCIDR
|
||||
};
|
||||
|
||||
Generated
+31
-14
@@ -14,10 +14,11 @@
|
||||
"@jambonz/db-helpers": "^0.9.1",
|
||||
"@jambonz/digest-utils": "^0.0.3",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/mw-registrar": "^0.2.4",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.6",
|
||||
"@jambonz/rtpengine-utils": "^0.4.3",
|
||||
"@jambonz/siprec-client-utils": "^0.2.5",
|
||||
"@jambonz/stats-collector": "^0.1.8",
|
||||
"@jambonz/siprec-client-utils": "^0.2.6",
|
||||
"@jambonz/stats-collector": "^0.1.9",
|
||||
"@jambonz/time-series": "^0.2.5",
|
||||
"bent": "^7.3.12",
|
||||
"cidr-matcher": "^2.1.1",
|
||||
@@ -1696,6 +1697,14 @@
|
||||
"node": ">=14.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/mw-registrar": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.5.tgz",
|
||||
"integrity": "sha512-+aBI2xpR6Ir140Hi7/ED+z5Hl7NgCalyVzTLNlgUVzTvsMLtyZZh6n9IQipKnuKvhh4nPM4aJ+JuFhi1UH9zEA==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/realtimedb-helpers": {
|
||||
"version": "0.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.6.tgz",
|
||||
@@ -1716,18 +1725,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/siprec-client-utils": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.5.tgz",
|
||||
"integrity": "sha512-Ib3M2ecFNxi80gZRG3hcCvxXLLImti1/0bVjAtglGjo1+qn3MyirIVYDchqdabzOC2nWl5aKBEcpG30c2saIDg==",
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.6.tgz",
|
||||
"integrity": "sha512-z2x6nghLaCfOBPcr36f+1vxsV557X3z5JW1L1RxZg8YPWkTboNIHyHxtEcAua7V9g6EB4G1qv2KDwA+iE5n5Ww==",
|
||||
"dependencies": {
|
||||
"sdp-transform": "^2.14.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/stats-collector": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.8.tgz",
|
||||
"integrity": "sha512-PadBKTmcphU7bZI7pVr4awhoIi+DMLw7An6AGE0GGsLCn2x0IGnxr9k47gI4Bk3OaSF6N7RyVLEAMkJfr24l8Q==",
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.9.tgz",
|
||||
"integrity": "sha512-JNRBaHQ47pWsXydj4gUp7zc64/0pM89a6E9pA8uQ15l1KxPGYYTrNRdone5aJqLTFOoPl3tYeF1kXj+3nU1nEA==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.2",
|
||||
"hot-shots": "^8.5.0"
|
||||
@@ -7664,6 +7673,14 @@
|
||||
"express": "^4.17.2"
|
||||
}
|
||||
},
|
||||
"@jambonz/mw-registrar": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/mw-registrar/-/mw-registrar-0.2.5.tgz",
|
||||
"integrity": "sha512-+aBI2xpR6Ir140Hi7/ED+z5Hl7NgCalyVzTLNlgUVzTvsMLtyZZh6n9IQipKnuKvhh4nPM4aJ+JuFhi1UH9zEA==",
|
||||
"requires": {
|
||||
"debug": "^4.3.4"
|
||||
}
|
||||
},
|
||||
"@jambonz/realtimedb-helpers": {
|
||||
"version": "0.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.6.tgz",
|
||||
@@ -7684,18 +7701,18 @@
|
||||
}
|
||||
},
|
||||
"@jambonz/siprec-client-utils": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.5.tgz",
|
||||
"integrity": "sha512-Ib3M2ecFNxi80gZRG3hcCvxXLLImti1/0bVjAtglGjo1+qn3MyirIVYDchqdabzOC2nWl5aKBEcpG30c2saIDg==",
|
||||
"version": "0.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/siprec-client-utils/-/siprec-client-utils-0.2.6.tgz",
|
||||
"integrity": "sha512-z2x6nghLaCfOBPcr36f+1vxsV557X3z5JW1L1RxZg8YPWkTboNIHyHxtEcAua7V9g6EB4G1qv2KDwA+iE5n5Ww==",
|
||||
"requires": {
|
||||
"sdp-transform": "^2.14.1",
|
||||
"uuid": "^8.3.2"
|
||||
}
|
||||
},
|
||||
"@jambonz/stats-collector": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.8.tgz",
|
||||
"integrity": "sha512-PadBKTmcphU7bZI7pVr4awhoIi+DMLw7An6AGE0GGsLCn2x0IGnxr9k47gI4Bk3OaSF6N7RyVLEAMkJfr24l8Q==",
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/stats-collector/-/stats-collector-0.1.9.tgz",
|
||||
"integrity": "sha512-JNRBaHQ47pWsXydj4gUp7zc64/0pM89a6E9pA8uQ15l1KxPGYYTrNRdone5aJqLTFOoPl3tYeF1kXj+3nU1nEA==",
|
||||
"requires": {
|
||||
"debug": "^4.3.2",
|
||||
"hot-shots": "^8.5.0"
|
||||
|
||||
+3
-2
@@ -29,10 +29,11 @@
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.6",
|
||||
"@jambonz/rtpengine-utils": "^0.4.3",
|
||||
"@jambonz/siprec-client-utils": "^0.2.5",
|
||||
"@jambonz/stats-collector": "^0.1.8",
|
||||
"@jambonz/siprec-client-utils": "^0.2.6",
|
||||
"@jambonz/stats-collector": "^0.1.9",
|
||||
"@jambonz/time-series": "^0.2.5",
|
||||
"@jambonz/digest-utils": "^0.0.3",
|
||||
"@jambonz/mw-registrar": "^0.2.4",
|
||||
"@aws-sdk/client-sns": "^3.360.0",
|
||||
"@aws-sdk/client-auto-scaling": "^3.360.0",
|
||||
"bent": "^7.3.12",
|
||||
|
||||
Reference in New Issue
Block a user