mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 08:40:38 +00:00
added initial support for REST-initiated outdials
This commit is contained in:
@@ -4,7 +4,6 @@ const {CallStatus, CallDirection, TaskName, TaskPreconditions, MAX_SIMRINGS} = r
|
||||
const assert = require('assert');
|
||||
const placeCall = require('../utils/place-outdial');
|
||||
const config = require('config');
|
||||
const moment = require('moment');
|
||||
const debug = require('debug')('jambonz:feature-server');
|
||||
|
||||
function compareTasks(t1, t2) {
|
||||
@@ -68,6 +67,14 @@ class TaskDial extends Task {
|
||||
this.dials = new Map();
|
||||
}
|
||||
|
||||
get dlg() {
|
||||
if (this.sd) return this.sd.dlg;
|
||||
}
|
||||
|
||||
get ep() {
|
||||
if (this.sd) return this.sd.ep;
|
||||
}
|
||||
|
||||
get name() { return TaskName.Dial; }
|
||||
|
||||
async exec(cs) {
|
||||
@@ -87,24 +94,25 @@ class TaskDial extends Task {
|
||||
|
||||
async kill() {
|
||||
super.kill();
|
||||
if (this.dlg) {
|
||||
const duration = moment().diff(this.dlg.connectTime, 'seconds');
|
||||
this.results.dialCallDuration = duration;
|
||||
this.logger.debug(`Dial:kill call ended after ${duration} seconds`);
|
||||
}
|
||||
|
||||
this._killOutdials();
|
||||
if (this.sd) {
|
||||
this.sd.kill();
|
||||
this.sd = null;
|
||||
}
|
||||
if (this.listenTask) await this.listenTask.kill();
|
||||
if (this.transcribeTask) await this.transcribeTask.kill();
|
||||
if (this.dlg) {
|
||||
assert(this.ep);
|
||||
if (this.dlg.connected) this.dlg.destroy();
|
||||
debug(`Dial:kill deleting endpoint ${this.ep.uuid}`);
|
||||
this.ep.destroy();
|
||||
}
|
||||
if (this.timerMaxCallDuration) clearTimeout(this.timerMaxCallDuration);
|
||||
this.notifyTaskDone();
|
||||
}
|
||||
|
||||
_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.dials.clear();
|
||||
}
|
||||
|
||||
async _initializeInbound(cs) {
|
||||
const {ep} = await cs.connectInboundCallToIvr(this.earlyMedia);
|
||||
this.epOther = ep;
|
||||
@@ -153,6 +161,13 @@ class TaskDial extends Task {
|
||||
this.dials.set(sd.callSid, sd);
|
||||
|
||||
sd
|
||||
.on('callCreateFail', () => {
|
||||
this.dials.delete(sd.callSid);
|
||||
if (this.dials.size === 0 && !this.sd) {
|
||||
this.logger.debug('Dial:_attemptCalls - all calls failed after call create err, ending task');
|
||||
this.kill();
|
||||
}
|
||||
})
|
||||
.on('callStatusChange', (obj) => {
|
||||
switch (obj.callStatus) {
|
||||
case CallStatus.Trying:
|
||||
@@ -170,7 +185,7 @@ class TaskDial extends Task {
|
||||
case CallStatus.Busy:
|
||||
case CallStatus.NoAnswer:
|
||||
this.dials.delete(sd.callSid);
|
||||
if (this.dials.size === 0 && !this.dlg) {
|
||||
if (this.dials.size === 0 && !this.sd) {
|
||||
this.logger.debug('Dial:_attemptCalls - all calls failed after call failure, ending task');
|
||||
clearTimeout(timerRing);
|
||||
this.kill();
|
||||
@@ -191,7 +206,7 @@ class TaskDial extends Task {
|
||||
.on('decline', () => {
|
||||
this.logger.debug(`Dial:_attemptCalls - declined: ${sd.callSid}`);
|
||||
this.dials.delete(sd.callSid);
|
||||
if (this.dials.size === 0 && !this.dlg) {
|
||||
if (this.dials.size === 0 && !this.sd) {
|
||||
this.logger.debug('Dial:_attemptCalls - all calls failed after decline, ending task');
|
||||
this.kill();
|
||||
}
|
||||
@@ -228,17 +243,14 @@ class TaskDial extends Task {
|
||||
debug(`Dial:_selectSingleDial ep for outbound call: ${sd.ep.uuid}`);
|
||||
this.dials.delete(sd.callSid);
|
||||
|
||||
this.ep = sd.ep;
|
||||
this.dlg = sd.dlg;
|
||||
this.dlg.connectTime = moment();
|
||||
this.sd = sd;
|
||||
this.callSid = sd.callSid;
|
||||
if (this.earlyMedia) {
|
||||
debug('Dial:_selectSingleDial propagating answer supervision on A leg now that B is connected');
|
||||
cs.propagateAnswer();
|
||||
}
|
||||
let timerMaxCallDuration;
|
||||
if (this.timeLimit) {
|
||||
timerMaxCallDuration = setTimeout(() => {
|
||||
this.timerMaxCallDuration = setTimeout(() => {
|
||||
this.logger.info(`Dial:_selectSingleDial tearing down call as it has reached ${this.timeLimit}s`);
|
||||
this.ep.unbridge();
|
||||
this.kill();
|
||||
@@ -246,7 +258,7 @@ class TaskDial extends Task {
|
||||
}
|
||||
this.dlg.on('destroy', () => {
|
||||
this.logger.debug('Dial:_selectSingleDial called party hungup, ending dial operation');
|
||||
if (timerMaxCallDuration) clearTimeout(timerMaxCallDuration);
|
||||
if (this.timerMaxCallDuration) clearTimeout(this.timerMaxCallDuration);
|
||||
this.ep.unbridge();
|
||||
this.kill();
|
||||
});
|
||||
@@ -260,14 +272,6 @@ class TaskDial extends Task {
|
||||
if (this.listenTask) this.listenTask.exec(cs, this.ep, this);
|
||||
}
|
||||
|
||||
_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.dials.clear();
|
||||
}
|
||||
|
||||
_bridgeEarlyMedia(sd) {
|
||||
if (this.epOther && !this.bridged) {
|
||||
this.epOther.api('uuid_break', this.epOther.uuid);
|
||||
|
||||
Reference in New Issue
Block a user