mirror of
https://github.com/jambonz/sbc-outbound.git
synced 2026-10-04 02:04:19 +00:00
Compare commits
7
Commits
v0.7.6-rc7
...
v0.7.7-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76625c7596 | ||
|
|
3b0f7ff6eb | ||
|
|
33c75acc9e | ||
|
|
bae9ef7638 | ||
|
|
4ed4b38301 | ||
|
|
6b6f89264f | ||
|
|
f0e0fba2f1 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM --platform=linux/amd64 node:18.6.0-alpine as base
|
||||
FROM --platform=linux/amd64 node:18.8.0-alpine as base
|
||||
|
||||
RUN apk --update --no-cache add --virtual .builds-deps build-base python3
|
||||
|
||||
|
||||
+26
-10
@@ -1,6 +1,7 @@
|
||||
const Emitter = require('events');
|
||||
const sdpTransform = require('sdp-transform');
|
||||
const SrsClient = require('@jambonz/siprec-client-utils');
|
||||
const {makeRtpEngineOpts, makeCallCountKey} = require('./utils');
|
||||
const {makeRtpEngineOpts, makeAccountCallCountKey, makeSPCallCountKey} = require('./utils');
|
||||
const {forwardInDialogRequests} = require('drachtio-fn-b2b-sugar');
|
||||
const {SipError, stringifyUri, parseUri} = require('drachtio-srf');
|
||||
const debug = require('debug')('jambonz:sbc-outbound');
|
||||
@@ -49,6 +50,15 @@ const initCdr = (srf, req) => {
|
||||
};
|
||||
};
|
||||
|
||||
const updateRtpEngineFlags = (sdp, opts) => {
|
||||
try {
|
||||
const parsed = sdpTransform.parse(sdp);
|
||||
const codec = parsed.media[0].rtp[0].codec;
|
||||
if (['PCMU', 'PCMA'].includes(codec)) opts.flags.push(`codec-accept-${codec}`);
|
||||
} catch (err) {}
|
||||
return opts;
|
||||
};
|
||||
|
||||
class CallSession extends Emitter {
|
||||
constructor(logger, req, res) {
|
||||
super();
|
||||
@@ -63,7 +73,8 @@ class CallSession extends Emitter {
|
||||
|
||||
this.incrKey = req.srf.locals.realtimeDbHelpers.incrKey;
|
||||
this.decrKey = req.srf.locals.realtimeDbHelpers.decrKey;
|
||||
this.callCountKey = makeCallCountKey(req.locals.account_sid);
|
||||
this.callCountKey = makeAccountCallCountKey(req.locals.account_sid);
|
||||
this.callCountKeySP = makeSPCallCountKey(req.locals.service_provider_sid);
|
||||
|
||||
const {performLcr, lookupCarrierBySid, lookupSipGatewaysByCarrier} = this.srf.locals.dbHelpers;
|
||||
this.performLcr = performLcr;
|
||||
@@ -236,13 +247,13 @@ class CallSession extends Emitter {
|
||||
}
|
||||
|
||||
// rtpengine 'offer'
|
||||
const opts = {
|
||||
const opts = updateRtpEngineFlags(this.req.body, {
|
||||
...this.rtpEngineOpts.common,
|
||||
...this.rtpEngineOpts.uac.mediaOpts,
|
||||
'from-tag': this.rtpEngineOpts.uas.tag,
|
||||
direction: ['private', 'public'],
|
||||
sdp: this.req.body
|
||||
};
|
||||
});
|
||||
const response = await this.offer(opts);
|
||||
debug(`response from rtpengine to offer ${JSON.stringify(response)}`);
|
||||
this.logger.debug({offer: opts, response}, 'initial offer to rtpengine');
|
||||
@@ -351,6 +362,7 @@ class CallSession extends Emitter {
|
||||
if (!this.req.locals.account.disable_cdrs) {
|
||||
this.req.locals.cdr = {
|
||||
...initCdr(this.req.srf, inv),
|
||||
service_provider_sid: this.req.locals.service_provider_sid,
|
||||
account_sid: this.req.locals.account_sid,
|
||||
trunk
|
||||
};
|
||||
@@ -445,13 +457,17 @@ class CallSession extends Emitter {
|
||||
await other.destroy();
|
||||
} catch (err) {}
|
||||
|
||||
this.decrKey(this.callCountKey)
|
||||
.then((count) => {
|
||||
this.logger.debug(`after hangup there are ${count} active calls for this account`);
|
||||
debug(`after hangup there are ${count} active calls for this account`);
|
||||
return;
|
||||
Promise.all([
|
||||
this.decrKey(this.callCountKey),
|
||||
this.decrKey(this.callCountKeySP)
|
||||
])
|
||||
.then(([calls, callsSP]) => {
|
||||
this.logger.info({calls, callsSP}, 'decremented call counts after call completion');
|
||||
return [calls, callsSP];
|
||||
})
|
||||
.catch((err) => this.logger.error({err}, 'Error decrementing call count'));
|
||||
.catch((err) => {
|
||||
this.logger.error({err}, 'error decrementing call counts after call completion');
|
||||
});
|
||||
|
||||
/* write cdr for connected call */
|
||||
if (this.req.locals.cdr) {
|
||||
|
||||
+26
-31
@@ -1,7 +1,7 @@
|
||||
const debug = require('debug')('jambonz:sbc-outbound');
|
||||
const parseUri = require('drachtio-srf').parseUri;
|
||||
const Registrar = require('@jambonz/mw-registrar');
|
||||
const {selectHostPort, makeCallCountKey} = require('./utils');
|
||||
const {selectHostPort, makeAccountCallCountKey, makeSPCallCountKey} = require('./utils');
|
||||
const FS_UUID_SET_NAME = 'fsUUIDs';
|
||||
|
||||
module.exports = (srf, logger, opts) => {
|
||||
@@ -63,7 +63,6 @@ module.exports = (srf, logger, opts) => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stats.increment('sbc.invites', ['direction:outbound']);
|
||||
|
||||
req.on('cancel', () => {
|
||||
@@ -76,6 +75,7 @@ module.exports = (srf, logger, opts) => {
|
||||
|
||||
try {
|
||||
req.locals.account = await lookupAccountBySid(req.locals.account_sid);
|
||||
req.locals.service_provider_sid = req.locals.account.service_provider_sid;
|
||||
} catch (err) {
|
||||
req.locals.logger.error({err}, `Error looking up account sid ${req.locals.account_sid}`);
|
||||
res.send(500);
|
||||
@@ -85,26 +85,21 @@ module.exports = (srf, logger, opts) => {
|
||||
};
|
||||
|
||||
const checkLimits = async(req, res, next) => {
|
||||
const {logger, account_sid} = req.locals;
|
||||
const {logger, account_sid, service_provider_sid} = req.locals;
|
||||
const {writeAlerts, AlertType} = req.srf.locals;
|
||||
|
||||
const key = makeCallCountKey(account_sid);
|
||||
const keyAccount = makeAccountCallCountKey(account_sid);
|
||||
const keySP = makeSPCallCountKey(service_provider_sid);
|
||||
try {
|
||||
/* increment the call count */
|
||||
const calls = await incrKey(key);
|
||||
debug(`checkLimits: call count is now ${calls}`);
|
||||
const [calls, callsSP] = await Promise.all([incrKey(keyAccount), incrKey(keySP)]);
|
||||
logger.info({calls, callsSP}, 'incremented call counts');
|
||||
|
||||
/* decrement count if INVITE is later rejected */
|
||||
res.once('end', ({status}) => {
|
||||
res.once('end', async({status}) => {
|
||||
if (status > 200) {
|
||||
debug('checkLimits: decrementing call count due to rejection');
|
||||
decrKey(key)
|
||||
.then((count) => {
|
||||
logger.debug({key}, `after rejection there are ${count} active calls for this account`);
|
||||
debug({key}, `after rejection there are ${count} active calls for this account`);
|
||||
return;
|
||||
})
|
||||
.catch((err) => logger.error({err}, 'checkLimits: decrKey err'));
|
||||
const [calls, callsSP] = await Promise.all([decrKey(keyAccount), decrKey(keySP)]);
|
||||
logger.info({calls, callsSP}, `decremented call counts after ${status} response`);
|
||||
const tags = ['accepted:no', `sipStatus:${status}`];
|
||||
stats.increment('sbc.originations', tags);
|
||||
}
|
||||
@@ -122,24 +117,24 @@ module.exports = (srf, logger, opts) => {
|
||||
|
||||
const capacities = await lookupAccountCapacitiesBySid(account_sid);
|
||||
const limit = capacities.find((c) => c.category == 'voice_call_session');
|
||||
if (!limit) {
|
||||
logger.debug('checkLimits: no call limits specified');
|
||||
return next();
|
||||
}
|
||||
const limit_sessions = limit.quantity;
|
||||
if (limit) {
|
||||
const limit_sessions = limit.quantity;
|
||||
|
||||
if (calls > limit_sessions) {
|
||||
debug(`checkLimits: limits exceeded: call count ${calls}, limit ${limit_sessions}`);
|
||||
logger.info({calls, limit_sessions}, 'checkLimits: limits exceeded');
|
||||
writeAlerts({
|
||||
alert_type: AlertType.CALL_LIMIT,
|
||||
account_sid,
|
||||
count: limit_sessions
|
||||
}).catch((err) => logger.info({err}, 'checkLimits: error writing alert'));
|
||||
|
||||
res.send(503, 'Maximum Calls In Progress');
|
||||
return req.srf.endSession(req);
|
||||
if (calls > limit_sessions) {
|
||||
logger.info({calls, limit_sessions}, 'checkLimits: limits exceeded');
|
||||
writeAlerts({
|
||||
alert_type: AlertType.ACCOUNT_CALL_LIMIT,
|
||||
service_provider_sid,
|
||||
account_sid,
|
||||
count: limit_sessions
|
||||
}).catch((err) => logger.info({err}, 'checkLimits: error writing alert'));
|
||||
res.send(503, 'Maximum Calls In Progress');
|
||||
return req.srf.endSession(req);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: check SP limits
|
||||
|
||||
next();
|
||||
} catch (err) {
|
||||
logger.error({err}, 'error checking limits error for inbound call');
|
||||
|
||||
+4
-2
@@ -77,7 +77,8 @@ const pingMsTeamsGateways = (logger, srf) => {
|
||||
});
|
||||
};
|
||||
|
||||
const makeCallCountKey = (sid) => `${sid}:outcalls`;
|
||||
const makeAccountCallCountKey = (sid) => `${sid}:outcalls:account`;
|
||||
const makeSPCallCountKey = (sid) => `${sid}:outcalls:sp`;
|
||||
|
||||
const equalsIgnoreOrder = (a, b) => {
|
||||
if (a.length !== b.length) return false;
|
||||
@@ -114,7 +115,8 @@ module.exports = {
|
||||
makeRtpEngineOpts,
|
||||
selectHostPort,
|
||||
pingMsTeamsGateways,
|
||||
makeCallCountKey,
|
||||
makeAccountCallCountKey,
|
||||
makeSPCallCountKey,
|
||||
equalsIgnoreOrder,
|
||||
systemHealth,
|
||||
createHealthCheckApp
|
||||
|
||||
Generated
+19
-16
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sbc-outbound",
|
||||
"version": "v0.7.5",
|
||||
"version": "v0.7.6",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sbc-outbound",
|
||||
"version": "v0.7.5",
|
||||
"version": "v0.7.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.6.18",
|
||||
@@ -16,13 +16,14 @@
|
||||
"@jambonz/rtpengine-utils": "^0.3.1",
|
||||
"@jambonz/siprec-client-utils": "^0.1.4",
|
||||
"@jambonz/stats-collector": "^0.1.6",
|
||||
"@jambonz/time-series": "^0.1.9",
|
||||
"@jambonz/time-series": "^0.2.1",
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.4",
|
||||
"drachtio-fn-b2b-sugar": "^0.0.12",
|
||||
"drachtio-srf": "^4.5.1",
|
||||
"express": "^4.18.1",
|
||||
"pino": "^7.11.0"
|
||||
"pino": "^7.11.0",
|
||||
"sdp-transform": "^2.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bent": "^7.3.12",
|
||||
@@ -643,12 +644,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/time-series": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.9.tgz",
|
||||
"integrity": "sha512-FLD7mLGEMToG7s6LGWr/GtNp61753RBxyYuKSxCVI6G14bm6ydgcBdG85h8EGTVQlIp9dnwbn5ebSVsGb8a46w==",
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.2.1.tgz",
|
||||
"integrity": "sha512-uAoeZ3ibS7kEOGdT+vaY8BB8hOV4q38eEaF+d5OvLQaHCrPonNiwB8tWhhXDwtYdDompfqVRUy/plNA9fyS7Vw==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"influx": "^5.8.0"
|
||||
"influx": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@protobufjs/aspromise": {
|
||||
@@ -2643,8 +2644,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/influx": {
|
||||
"version": "5.9.2",
|
||||
"integrity": "sha512-N2YRIQiwCO60BzmzEzTxyWj/hDNsce2CLSmki8S1qbRwwuKecfvC6n0OwJrFV70lk5CpU/sLsOZFIy6PP01nOA=="
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/influx/-/influx-5.9.3.tgz",
|
||||
"integrity": "sha512-QQU9CgwnaEV6zMrK8+vhVItsdoKFqDioXJrjJhRQaff9utvT3N0jcrQJT9qnxFLktqgJ5ngbDY68Zh4eo4uD/w=="
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
@@ -5596,12 +5598,12 @@
|
||||
}
|
||||
},
|
||||
"@jambonz/time-series": {
|
||||
"version": "0.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.1.9.tgz",
|
||||
"integrity": "sha512-FLD7mLGEMToG7s6LGWr/GtNp61753RBxyYuKSxCVI6G14bm6ydgcBdG85h8EGTVQlIp9dnwbn5ebSVsGb8a46w==",
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/time-series/-/time-series-0.2.1.tgz",
|
||||
"integrity": "sha512-uAoeZ3ibS7kEOGdT+vaY8BB8hOV4q38eEaF+d5OvLQaHCrPonNiwB8tWhhXDwtYdDompfqVRUy/plNA9fyS7Vw==",
|
||||
"requires": {
|
||||
"debug": "^4.3.1",
|
||||
"influx": "^5.8.0"
|
||||
"influx": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"@protobufjs/aspromise": {
|
||||
@@ -7131,8 +7133,9 @@
|
||||
}
|
||||
},
|
||||
"influx": {
|
||||
"version": "5.9.2",
|
||||
"integrity": "sha512-N2YRIQiwCO60BzmzEzTxyWj/hDNsce2CLSmki8S1qbRwwuKecfvC6n0OwJrFV70lk5CpU/sLsOZFIy6PP01nOA=="
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/influx/-/influx-5.9.3.tgz",
|
||||
"integrity": "sha512-QQU9CgwnaEV6zMrK8+vhVItsdoKFqDioXJrjJhRQaff9utvT3N0jcrQJT9qnxFLktqgJ5ngbDY68Zh4eo4uD/w=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
|
||||
+5
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sbc-outbound",
|
||||
"version": "v0.7.5",
|
||||
"version": "v0.7.6",
|
||||
"main": "app.js",
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
@@ -22,7 +22,7 @@
|
||||
"description": "jambonz session border controller application for outbound calls",
|
||||
"scripts": {
|
||||
"start": "node app",
|
||||
"test": "NODE_ENV=test HTTP_PORT=3050 JAMBONZ_HOSTING=1 JAMBONES_NETWORK_CIDR=127.0.0.1/32 JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=localhost JAMBONES_REDIS_PORT=16379 JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_LOGLEVEL=error DRACHTIO_SECRET=cymru DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 JAMBONES_RTPENGINES=127.0.0.1:12222 node test/ ",
|
||||
"test": "NODE_ENV=test HTTP_PORT=3050 JAMBONZ_HOSTING=1 JAMBONES_NETWORK_CIDR=127.0.0.1/32 JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=localhost JAMBONES_REDIS_PORT=16379 JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_LOGLEVEL=info DRACHTIO_SECRET=cymru DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 JAMBONES_RTPENGINES=127.0.0.1:12222 node test/ ",
|
||||
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
|
||||
"jslint": "eslint app.js lib"
|
||||
},
|
||||
@@ -34,13 +34,14 @@
|
||||
"@jambonz/rtpengine-utils": "^0.3.1",
|
||||
"@jambonz/siprec-client-utils": "^0.1.4",
|
||||
"@jambonz/stats-collector": "^0.1.6",
|
||||
"@jambonz/time-series": "^0.1.9",
|
||||
"@jambonz/time-series": "^0.2.1",
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.4",
|
||||
"drachtio-fn-b2b-sugar": "^0.0.12",
|
||||
"drachtio-srf": "^4.5.1",
|
||||
"express": "^4.18.1",
|
||||
"pino": "^7.11.0"
|
||||
"pino": "^7.11.0",
|
||||
"sdp-transform": "^2.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bent": "^7.3.12",
|
||||
|
||||
Reference in New Issue
Block a user