mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
snake case REST payloads, support for LCC with child_call_hook, handle 302 on outdial
This commit is contained in:
@@ -113,6 +113,11 @@ class TaskDial extends Task {
|
||||
}
|
||||
|
||||
get ep() {
|
||||
/**
|
||||
* Note:
|
||||
* this.ep is the B leg-facing endpoint
|
||||
* this.epOther is the A leg-facing endpoint
|
||||
*/
|
||||
if (this.sd) return this.sd.ep;
|
||||
}
|
||||
|
||||
@@ -133,6 +138,8 @@ class TaskDial extends Task {
|
||||
this._installDtmfDetection(cs, this.epOther, this.parentDtmfCollector);
|
||||
await this._attemptCalls(cs);
|
||||
await this.awaitTaskDone();
|
||||
|
||||
this.logger.debug({callSid: this.cs.callSid}, 'Dial:exec task is done, sending actionHook if any');
|
||||
await this.performAction(this.results);
|
||||
this._removeDtmfDetection(cs, this.epOther);
|
||||
this._removeDtmfDetection(cs, this.ep);
|
||||
@@ -146,6 +153,8 @@ class TaskDial extends Task {
|
||||
super.kill(cs);
|
||||
this._removeDtmfDetection(this.cs, this.epOther);
|
||||
this._removeDtmfDetection(this.cs, this.ep);
|
||||
this.logger.debug({callSid: this.cs.callSid}, 'Dial:kill removed dtmf listeners');
|
||||
|
||||
this._killOutdials();
|
||||
if (this.sd) {
|
||||
this.sd.kill();
|
||||
@@ -212,6 +221,7 @@ class TaskDial extends Task {
|
||||
_removeDtmfDetection(cs, ep) {
|
||||
if (ep) {
|
||||
delete ep.dtmfDetector;
|
||||
this.logger.debug(`Dial:_removeDtmfDetection endpoint ${ep.uuid}`);
|
||||
ep.removeAllListeners('dtmf');
|
||||
}
|
||||
}
|
||||
@@ -219,13 +229,18 @@ class TaskDial extends Task {
|
||||
_onDtmf(cs, ep, evt) {
|
||||
if (ep.dtmfDetector) {
|
||||
const match = ep.dtmfDetector.keyPress(evt.dtmf);
|
||||
const requestor = ep.dtmfDetector === this.parentDtmfCollector ?
|
||||
cs.requestor :
|
||||
this.sd.requestor;
|
||||
if (match) {
|
||||
this.logger.debug(`parentCall triggered dtmf match: ${match}`);
|
||||
requestor.request(this.dtmfHook, Object.assign({dtmf: match}, cs.callInfo))
|
||||
.catch((err) => this.logger.info(err, 'Dial:_onDtmf - error'));
|
||||
this.logger.debug({callSid: this.cs.callSid}, `Dial:_onDtmf triggered dtmf match: ${match}`);
|
||||
const requestor = ep.dtmfDetector === this.parentDtmfCollector ?
|
||||
cs.requestor :
|
||||
(this.sd ? this.sd.requestor : null);
|
||||
if (!requestor) {
|
||||
this.logger.info(`Dial:_onDtmf got digits on B leg after adulting: ${evt.dtmf}`);
|
||||
}
|
||||
else {
|
||||
requestor.request(this.dtmfHook, Object.assign({dtmf: match}, cs.callInfo))
|
||||
.catch((err) => this.logger.info(err, 'Dial:_onDtmf - error'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,6 +366,16 @@ class TaskDial extends Task {
|
||||
this.logger.debug('Dial:_attemptCalls - all calls failed after decline, ending task');
|
||||
this.kill(cs);
|
||||
}
|
||||
})
|
||||
.once('adulting', () => {
|
||||
/* child call just adulted and got its own session */
|
||||
this.logger.info('Dial:on_adulting: detaching child call leg');
|
||||
if (this.ep) {
|
||||
this.logger.debug(`Dial:on_adulting: removing dtmf from ${this.ep.uuid}`);
|
||||
this.ep.removeAllListeners('dtmf');
|
||||
}
|
||||
this.sd = null;
|
||||
this.callSid = null;
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Dial:_attemptCalls');
|
||||
@@ -399,11 +424,14 @@ class TaskDial extends Task {
|
||||
}
|
||||
sessionTracker.add(this.callSid, cs);
|
||||
this.dlg.on('destroy', () => {
|
||||
this.logger.debug('Dial:_selectSingleDial called party hungup, ending dial operation');
|
||||
sessionTracker.remove(this.callSid);
|
||||
if (this.timerMaxCallDuration) clearTimeout(this.timerMaxCallDuration);
|
||||
this.ep.unbridge();
|
||||
this.kill(cs);
|
||||
/* if our child is adulting, he's own his own now.. */
|
||||
if (this.dlg) {
|
||||
this.logger.debug('Dial:_selectSingleDial called party hungup, ending dial operation');
|
||||
sessionTracker.remove(this.callSid);
|
||||
if (this.timerMaxCallDuration) clearTimeout(this.timerMaxCallDuration);
|
||||
this.ep.unbridge();
|
||||
this.kill(cs);
|
||||
}
|
||||
});
|
||||
|
||||
Object.assign(this.results, {
|
||||
|
||||
@@ -275,18 +275,19 @@ class TaskEnqueue extends Task {
|
||||
this.logger.error({err}, `TaskEnqueue:_playHook error retrieving list info for queue ${this.queueName}`);
|
||||
}
|
||||
const json = await cs.application.requestor.request(hook, params);
|
||||
const tasks = normalizeJambones(this.logger, json).map((tdata) => makeTask(this.logger, tdata));
|
||||
|
||||
const allowedTasks = json.filter((task) => allowed.includes(task.verb));
|
||||
if (json.length !== allowedTasks.length) {
|
||||
this.logger.debug({json, allowedTasks}, 'unsupported task');
|
||||
throw new Error(`unsupported verb in dial enqueue waitHook: only ${JSON.stringify(allowed)}`);
|
||||
const allowedTasks = tasks.filter((t) => allowed.includes(t.verb));
|
||||
if (tasks.length !== allowedTasks.length) {
|
||||
this.logger.debug({tasks, allowedTasks}, 'unsupported task');
|
||||
throw new Error(`unsupported verb in enqueue waitHook: only ${JSON.stringify(allowed)}`);
|
||||
}
|
||||
this.logger.debug(`TaskEnqueue:_playHook: executing ${json.length} tasks`);
|
||||
this.logger.debug(`TaskEnqueue:_playHook: executing ${tasks.length} tasks`);
|
||||
|
||||
// check for 'leave' verb and only execute tasks up till then
|
||||
const tasksToRun = [];
|
||||
let leave = false;
|
||||
for (const o of json) {
|
||||
for (const o of tasks) {
|
||||
if (o.verb === TaskName.Leave) {
|
||||
leave = true;
|
||||
this.logger.info('waitHook returned a leave task');
|
||||
@@ -297,14 +298,13 @@ class TaskEnqueue extends Task {
|
||||
|
||||
if (this.killed) return [];
|
||||
else if (tasksToRun.length > 0) {
|
||||
const tasks = normalizeJambones(this.logger, tasksToRun).map((tdata) => makeTask(this.logger, tdata));
|
||||
this._playSession = new ConfirmCallSession({
|
||||
logger: this.logger,
|
||||
application: cs.application,
|
||||
dlg,
|
||||
ep: cs.ep,
|
||||
callInfo: cs.callInfo,
|
||||
tasks
|
||||
tasksToRun
|
||||
});
|
||||
await this._playSession.exec();
|
||||
this._playSession = null;
|
||||
|
||||
@@ -91,6 +91,7 @@ class TaskGather extends Task {
|
||||
kill(cs) {
|
||||
super.kill(cs);
|
||||
this._killAudio();
|
||||
this.ep.removeAllListeners('dtmf');
|
||||
this._resolve('killed');
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,13 @@ class TaskSay extends Task {
|
||||
})))
|
||||
.filter((fp) => fp && fp.length);
|
||||
|
||||
this.logger.debug({files}, 'synthesized files for tts');
|
||||
this.logger.debug({files, loop: this.loop}, 'synthesized files for tts');
|
||||
if (!this.ep.connected) this.logger.debug('say: endpoint is not connected!');
|
||||
|
||||
while (!this.killed && this.loop-- && this.ep.connected) {
|
||||
let segment = 0;
|
||||
do {
|
||||
this.logger.debug(`playing file ${files[segment]}`);
|
||||
await ep.play(files[segment]);
|
||||
} while (!this.killed && ++segment < files.length);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user