Compare commits

...

11 Commits

Author SHA1 Message Date
snyk-bot
42e43a2148 fix: upgrade debug from 4.3.1 to 4.3.2
Snyk has created this PR to upgrade debug from 4.3.1 to 4.3.2.

See this package in npm:
https://www.npmjs.com/package/debug

See this project in Snyk:
https://app.snyk.io/org/davehorton/project/cec90d0e-0ded-433e-a42e-fe78b28ae489?utm_source=github&utm_medium=referral&page=upgrade-pr
2021-12-17 18:37:07 +00:00
Dave Horton
2b9cb5105f clean up handlers 2021-12-15 19:33:31 -05:00
Dave Horton
afbbed3f5c default options ping interval to 30s, with env override if desired 2021-12-14 12:28:02 -05:00
Dave Horton
f642967f02 add SIGTERM handler 2021-12-13 18:08:53 -05:00
Dave Horton
fbe2aa2c06 add SIGUSR2 handler to remove fs from redis set 2021-12-13 17:59:23 -05:00
Dave Horton
5321b5c651 minor change to dial _releaseMedia 2021-12-13 13:22:09 -05:00
Dave Horton
83c114803f minor logging 2021-12-13 11:48:43 -05:00
Dave Horton
0663174f46 additional logging 2021-12-12 09:30:36 -05:00
Dave Horton
3d4359fbe4 fix bug from prev checkin, destroy does not return a promise 2021-12-09 11:24:52 -05:00
Dave Horton
10382573fa clean up some retainers 2021-12-09 10:44:50 -05:00
Dave Horton
c190279927 bugfix: enqueue task was only invoking waitUrl a single time 2021-12-06 21:18:51 -05:00
11 changed files with 163 additions and 68 deletions

51
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: Docker
on:
push:
# Publish `main` as Docker `latest` image.
branches:
- main
# Publish `v1.2.3` tags as releases.
tags:
- v*
env:
IMAGE_NAME: feature-server
jobs:
push:
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME
- name: Log into registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
# Change all uppercase to lowercase
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
# Strip git ref prefix from version
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# Strip "v" prefix from tag name
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# Use Docker `latest` tag convention
[ "$VERSION" == "main" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION

11
app.js
View File

@@ -105,4 +105,15 @@ const disconnect = () => {
});
};
process.on('SIGUSR2', handle);
process.on('SIGTERM', handle);
function handle(signal) {
const {removeFromSet} = srf.locals.dbHelpers;
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
logger.info(`got signal ${signal}, removing ${srf.locals.localSipAddress} from set ${setName}`);
removeFromSet(setName, srf.locals.localSipAddress);
srf.locals.disabled = true;
}
module.exports = {srf, logger, disconnect};

View File

@@ -632,7 +632,7 @@ class CallSession extends Emitter {
try {
if (!this.ms) this.ms = this.getMS();
const ep = await this.ms.createEndpoint({remoteSdp: this.req.body});
ep.cs = this;
//ep.cs = this;
this.ep = ep;
ep.set({
hangup_after_bridge: false,
@@ -716,14 +716,12 @@ class CallSession extends Emitter {
/**
* Hang up the call and free the media endpoint
*/
async _clearResources() {
_clearResources() {
for (const resource of [this.dlg, this.ep]) {
try {
if (resource && resource.connected) await resource.destroy();
} catch (err) {
this.logger.error(err, 'CallSession:_clearResources error');
}
if (resource && resource.connected) resource.destroy();
}
this.dlg = null;
this.ep = null;
// remove any temporary tts files that were created (audio is still cached in redis)
for (const path of this.tmpFiles) {

View File

@@ -21,15 +21,17 @@ class InboundCallSession extends CallSession {
this.req = req;
this.res = res;
req.on('cancel', () => {
this._notifyCallStatusChange({callStatus: CallStatus.NoAnswer, sipStatus: 487});
this._callReleased();
});
req.once('cancel', this._onCancel.bind(this));
this.on('callStatusChange', this._notifyCallStatusChange.bind(this));
this._notifyCallStatusChange({callStatus: CallStatus.Trying, sipStatus: 100});
}
_onCancel() {
this._notifyCallStatusChange({callStatus: CallStatus.NoAnswer, sipStatus: 487});
this._callReleased();
}
_onTasksDone() {
if (!this.res.finalResponseSent) {
if (this._mediaServerFailure) {
@@ -45,6 +47,7 @@ class InboundCallSession extends CallSession {
this.res.send(603);
}
}
this.req.removeAllListeners('cancel');
}
/**
@@ -56,6 +59,7 @@ class InboundCallSession extends CallSession {
this.emit('callStatusChange', {callStatus: CallStatus.Completed, duration});
this.logger.debug('InboundCallSession: caller hung up');
this._callReleased();
this.req.removeAllListeners('cancel');
}
}

View File

@@ -166,6 +166,10 @@ class TaskDial extends Task {
clearTimeout(this.timerMaxCallDuration);
this.timerMaxCallDuration = null;
}
if (this.timerRing) {
clearTimeout(this.timerRing);
this.timerRing = null;
}
this._removeDtmfDetection(cs.dlg);
this._removeDtmfDetection(this.dlg);
this._killOutdials();
@@ -231,10 +235,19 @@ class TaskDial extends Task {
}
}
_removeHandlers(sd) {
sd.removeAllListeners('accept');
sd.removeAllListeners('decline');
sd.removeAllListeners('adulting');
sd.removeAllListeners('callStatusChange');
sd.removeAllListeners('callCreateFail');
}
_killOutdials() {
for (const [callSid, sd] of Array.from(this.dials)) {
this.logger.debug(`Dial:_killOutdials killing callSid ${callSid}`);
sd.kill().catch((err) => this.logger.info(err, `Dial:_killOutdials Error killing ${callSid}`));
this._removeHandlers(sd);
}
this.dials.clear();
}
@@ -319,8 +332,9 @@ class TaskDial extends Task {
}
const ms = await cs.getMS();
const timerRing = setTimeout(() => {
this.timerRing = setTimeout(() => {
this.logger.info(`Dial:_attemptCall: ring no answer timer ${this.timeout}s exceeded`);
this.timerRing = null;
this._killOutdials();
}, this.timeout * 1000);
@@ -387,7 +401,8 @@ class TaskDial extends Task {
break;
case CallStatus.InProgress:
this.logger.debug('Dial:_attemptCall -- call was answered');
clearTimeout(timerRing);
clearTimeout(this.timerRing);
this.timerRing = null;
break;
case CallStatus.Failed:
case CallStatus.Busy:
@@ -395,7 +410,8 @@ class TaskDial extends Task {
this.dials.delete(sd.callSid);
if (this.dials.size === 0 && !this.sd) {
this.logger.debug('Dial:_attemptCalls - all calls failed after call failure, ending task');
clearTimeout(timerRing);
clearTimeout(this.timerRing);
this.timerRing = null;
this.kill(cs);
}
break;
@@ -448,6 +464,12 @@ class TaskDial extends Task {
this._killOutdials(); // NB: order is important
}
_onMaxCallDuration(cs) {
this.logger.info(`Dial:_onMaxCallDuration tearing down call as it has reached ${this.timeLimit}s`);
this.ep && this.ep.unbridge();
this.kill(cs);
}
/**
* We now have a call leg produced by the Dial action, so
* - hangup any simrings in progress
@@ -468,11 +490,7 @@ class TaskDial extends Task {
await cs.propagateAnswer();
}
if (this.timeLimit) {
this.timerMaxCallDuration = setTimeout(() => {
this.logger.info(`Dial:_selectSingleDial tearing down call as it has reached ${this.timeLimit}s`);
this.ep && this.ep.unbridge();
this.kill(cs);
}, this.timeLimit * 1000);
this.timerMaxCallDuration = setTimeout(this._onMaxCallDuration.bind(this, cs), this.timeLimit * 1000);
}
sessionTracker.add(this.callSid, cs);
this.dlg.on('destroy', () => {
@@ -523,9 +541,9 @@ class TaskDial extends Task {
assert(cs.ep && sd.ep);
try {
this.logger.info('Dial:_releaseMedia - releasing media from freewitch');
const aLegSdp = cs.ep.remote.sdp;
const bLegSdp = sd.ep.remote.sdp;
const bLegSdp = sd.dlg.remote.sdp;
this.logger.debug({aLegSdp, bLegSdp}, 'Dial:_releaseMedia - releasing media from freewitch');
await Promise.all[sd.releaseMediaToSBC(aLegSdp), cs.releaseMediaToSBC(bLegSdp)];
this.epOther = null;
this.logger.info('Dial:_releaseMedia - successfully released media from freewitch');

View File

@@ -337,7 +337,7 @@ class TaskEnqueue extends Task {
}
tasksToRun.push(o);
}
const cloneTasks = [...tasksToRun];
if (this.killed) return [];
else if (tasksToRun.length > 0) {
this._playSession = new ConfirmCallSession({
@@ -356,7 +356,7 @@ class TaskEnqueue extends Task {
this.state = QueueResults.Leave;
this.kill(cs);
}
return tasksToRun;
return cloneTasks;
}
}

View File

@@ -64,6 +64,7 @@ class TaskListen extends Task {
this.results.dialCallDuration = duration;
}
if (this.transcribeTask) await this.transcribeTask.kill(cs);
this.ep && this._removeListeners(this.ep);
this.notifyTaskDone();
}
@@ -136,6 +137,10 @@ class TaskListen extends Task {
if (this.finishOnKey || this.passDtmf) {
ep.removeListener('dtmf', this._dtmfHandler);
}
ep.removeCustomEventListener(ListenEvents.PlayAudio);
ep.removeCustomEventListener(ListenEvents.KillAudio);
ep.removeCustomEventListener(ListenEvents.Disconnect);
}
_onDtmf(evt) {

View File

@@ -20,6 +20,13 @@ function initMS(logger, wrapper, ms) {
wrapper.connects = 1;
wrapper.active = true;
});
ms.on('channel::open', (evt) => {
logger.debug({evt}, `mediaserver ${ms.address} added endpoint`);
});
ms.on('channel::close', (evt) => {
logger.debug({evt}, `mediaserver ${ms.address} removed endpoint`);
});
}
function installSrfLocals(srf, logger) {

View File

@@ -95,7 +95,7 @@ module.exports = (logger) => {
setInterval(() => {
const {srf} = require('../..');
pingProxies(srf);
}, 20000);
}, process.env.OPTIONS_PING_INTERVAL || 30000);
// initial ping once we are up
setTimeout(async() => {

83
package-lock.json generated
View File

@@ -1,11 +1,12 @@
{
"name": "jambonz-feature-server",
"version": "v0.6.7-rc8",
"version": "v0.7.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "v0.6.7-rc8",
"name": "jambonz-feature-server",
"version": "v0.7.0",
"license": "MIT",
"dependencies": {
"@jambonz/db-helpers": "^0.6.14",
@@ -16,9 +17,9 @@
"aws-sdk": "^2.846.0",
"bent": "^7.3.12",
"cidr-matcher": "^2.1.1",
"debug": "^4.3.1",
"debug": "^4.3.2",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^2.0.11",
"drachtio-fsmrf": "^2.0.13",
"drachtio-srf": "^4.4.55",
"express": "^4.17.1",
"ip": "^1.1.5",
@@ -1300,9 +1301,9 @@
}
},
"node_modules/debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"dependencies": {
"ms": "2.1.2"
},
@@ -1454,14 +1455,14 @@
}
},
"node_modules/drachtio-fsmrf": {
"version": "2.0.11",
"resolved": "https://registry.npmjs.org/drachtio-fsmrf/-/drachtio-fsmrf-2.0.11.tgz",
"integrity": "sha512-3U1tHBh2fJd8cGbUMV+Gc2laq5VxIynmP3Ue0eRW35Za7Sp7/ucPfxbJ2OZc0PlokRCQYGvCyjTdTv8SPzoajQ==",
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/drachtio-fsmrf/-/drachtio-fsmrf-2.0.13.tgz",
"integrity": "sha512-LYHE/y7d1fBsKltcHmbLLCQ2MNUmJNURkXkAz4BfWZHyavEDGMwrmkrBAMDbOSZV1H87FstdfEzc54Ym1SsQbA==",
"dependencies": {
"async": "^1.4.2",
"debug": "^2.6.9",
"delegates": "^0.1.0",
"drachtio-modesl": "^1.2.2",
"drachtio-modesl": "^1.2.4",
"drachtio-srf": "^4.4.59",
"lodash": "^4.17.21",
"minimist": "^1.2.5",
@@ -1501,9 +1502,9 @@
}
},
"node_modules/drachtio-modesl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/drachtio-modesl/-/drachtio-modesl-1.2.2.tgz",
"integrity": "sha512-4+SVtMahFfqbxP+TIBN0usc9iMJX5Sl/vkJ3lMj3OmIRto18lkUUpFOBbj/PZbFZMoeXLz4tAWNzlzEBCC7bBw==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/drachtio-modesl/-/drachtio-modesl-1.2.4.tgz",
"integrity": "sha512-Le6/iAuRhJU2fbxuRksXMXPknjU8GN5vpw1p211CmaH/dZxJ5FSghksD9ubV7Kqc6qE73M/K/boDtu14V/GjeQ==",
"dependencies": {
"debug": "^4.1.1",
"eventemitter2": "^6.4.4",
@@ -3204,9 +3205,9 @@
}
},
"node_modules/json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
@@ -3234,17 +3235,17 @@
}
},
"node_modules/jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"engines": [
"node >=0.6.0"
],
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"json-schema": "0.4.0",
"verror": "1.10.0"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/jwa": {
@@ -6229,9 +6230,9 @@
}
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
"integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
"requires": {
"ms": "2.1.2"
}
@@ -6353,14 +6354,14 @@
}
},
"drachtio-fsmrf": {
"version": "2.0.11",
"resolved": "https://registry.npmjs.org/drachtio-fsmrf/-/drachtio-fsmrf-2.0.11.tgz",
"integrity": "sha512-3U1tHBh2fJd8cGbUMV+Gc2laq5VxIynmP3Ue0eRW35Za7Sp7/ucPfxbJ2OZc0PlokRCQYGvCyjTdTv8SPzoajQ==",
"version": "2.0.13",
"resolved": "https://registry.npmjs.org/drachtio-fsmrf/-/drachtio-fsmrf-2.0.13.tgz",
"integrity": "sha512-LYHE/y7d1fBsKltcHmbLLCQ2MNUmJNURkXkAz4BfWZHyavEDGMwrmkrBAMDbOSZV1H87FstdfEzc54Ym1SsQbA==",
"requires": {
"async": "^1.4.2",
"debug": "^2.6.9",
"delegates": "^0.1.0",
"drachtio-modesl": "^1.2.2",
"drachtio-modesl": "^1.2.4",
"drachtio-srf": "^4.4.59",
"lodash": "^4.17.21",
"minimist": "^1.2.5",
@@ -6395,9 +6396,9 @@
}
},
"drachtio-modesl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/drachtio-modesl/-/drachtio-modesl-1.2.2.tgz",
"integrity": "sha512-4+SVtMahFfqbxP+TIBN0usc9iMJX5Sl/vkJ3lMj3OmIRto18lkUUpFOBbj/PZbFZMoeXLz4tAWNzlzEBCC7bBw==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/drachtio-modesl/-/drachtio-modesl-1.2.4.tgz",
"integrity": "sha512-Le6/iAuRhJU2fbxuRksXMXPknjU8GN5vpw1p211CmaH/dZxJ5FSghksD9ubV7Kqc6qE73M/K/boDtu14V/GjeQ==",
"requires": {
"debug": "^4.1.1",
"eventemitter2": "^6.4.4",
@@ -7695,9 +7696,9 @@
}
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"json-schema-traverse": {
"version": "0.4.1",
@@ -7719,13 +7720,13 @@
}
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"json-schema": "0.4.0",
"verror": "1.10.0"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "jambonz-feature-server",
"version": "v0.6.7-rc8",
"version": "v0.7.0",
"main": "app.js",
"engines": {
"node": ">= 10.16.0"
@@ -34,9 +34,9 @@
"aws-sdk": "^2.846.0",
"bent": "^7.3.12",
"cidr-matcher": "^2.1.1",
"debug": "^4.3.1",
"debug": "^4.3.2",
"deepcopy": "^2.1.0",
"drachtio-fsmrf": "^2.0.11",
"drachtio-fsmrf": "^2.0.13",
"drachtio-srf": "^4.4.55",
"express": "^4.17.1",
"ip": "^1.1.5",