mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
added initial support for REST-initiated outdials
This commit is contained in:
@@ -5,6 +5,7 @@ class CallInfo {
|
||||
constructor(opts) {
|
||||
this.direction = opts.direction;
|
||||
if (this.direction === CallDirection.Inbound) {
|
||||
// inbound call
|
||||
const {app, req} = opts;
|
||||
this.callSid = req.locals.callSid,
|
||||
this.accountSid = app.account_sid,
|
||||
@@ -19,19 +20,32 @@ class CallInfo {
|
||||
this.originatingSipTrunkName = req.get('X-Originating-Carrier');
|
||||
}
|
||||
else if (opts.parentCallInfo) {
|
||||
console.log(`is opts.parentCallInfo a CallInfo ${opts.parentCallInfo instanceof CallInfo}`);
|
||||
const {req, parentCallInfo} = opts;
|
||||
this.callSid = uuidv4();
|
||||
// outbound call that is a child of an existing call
|
||||
const {req, parentCallInfo, to, callSid} = opts;
|
||||
this.callSid = callSid || uuidv4();
|
||||
this.parentCallSid = parentCallInfo.callSid;
|
||||
this.accountSid = parentCallInfo.accountSid;
|
||||
this.applicationSid = parentCallInfo.applicationSid;
|
||||
this.from = req.callingNumber;
|
||||
this.to = req.calledNumber;
|
||||
this.to = to || req.calledNumber;
|
||||
this.callerName = this.from.name || req.callingNumber;
|
||||
this.callId = req.get('Call-ID');
|
||||
this.callStatus = CallStatus.Trying,
|
||||
this.sipStatus = 100;
|
||||
}
|
||||
else {
|
||||
// outbound call triggered by REST
|
||||
const {req, accountSid, applicationSid, to, tag} = opts;
|
||||
this.callSid = uuidv4();
|
||||
this.accountSid = accountSid;
|
||||
this.applicationSid = applicationSid;
|
||||
this.callStatus = CallStatus.Trying,
|
||||
this.callId = req.get('Call-ID');
|
||||
this.sipStatus = 100;
|
||||
this.from = req.callingNumber;
|
||||
this.to = to;
|
||||
if (tag) this._customerData = tag;
|
||||
}
|
||||
}
|
||||
|
||||
updateCallStatus(callStatus, sipStatus) {
|
||||
@@ -43,6 +57,10 @@ class CallInfo {
|
||||
this._customerData = obj;
|
||||
}
|
||||
|
||||
get customerData() {
|
||||
return this._customerData;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
const obj = {
|
||||
callSid: this.callSid,
|
||||
@@ -59,9 +77,10 @@ class CallInfo {
|
||||
['parentCallSid', 'originatingSipIP', 'originatingSipTrunkName'].forEach((prop) => {
|
||||
if (this[prop]) obj[prop] = this[prop];
|
||||
});
|
||||
if (typeof this.duration === 'number') obj.duration = this.duration;
|
||||
|
||||
if (this._customerData && Object.keys(this._customerData).length) {
|
||||
obj.customerData = this._customerData;
|
||||
if (this._customerData) {
|
||||
Object.assign(obj, {customerData: this._customerData});
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,24 @@ class CallSession extends Emitter {
|
||||
return this.callInfo.direction;
|
||||
}
|
||||
|
||||
get call_status_hook() {
|
||||
return this.application.call_status_hook;
|
||||
}
|
||||
|
||||
get speechSynthesisVendor() {
|
||||
return this.application.speech_synthesis_vendor;
|
||||
}
|
||||
get speechSynthesisVoice() {
|
||||
return this.application.speech_synthesis_voice;
|
||||
}
|
||||
|
||||
get speechRecognizerVendor() {
|
||||
return this.application.speech_recognizer_vendor;
|
||||
}
|
||||
get speechRecognizerLanguage() {
|
||||
return this.application.speech_recognizer_language;
|
||||
}
|
||||
|
||||
async exec() {
|
||||
this.logger.info(`CallSession:exec starting task list with ${this.tasks.length} tasks`);
|
||||
while (this.tasks.length && !this.callGone) {
|
||||
@@ -196,11 +214,16 @@ class CallSession extends Emitter {
|
||||
}
|
||||
return {ms: this.ms, ep: this.ep};
|
||||
}
|
||||
_notifyCallStatusChange({callStatus, sipStatus}) {
|
||||
this.logger.debug(`CallSession:_notifyCallStatusChange: ${callStatus} ${sipStatus}`);
|
||||
_notifyCallStatusChange({callStatus, sipStatus, duration}) {
|
||||
assert((typeof duration === 'number' && callStatus === CallStatus.Completed) ||
|
||||
(!duration && callStatus !== CallStatus.Completed),
|
||||
'duration MUST be supplied when call completed AND ONLY when call completed');
|
||||
|
||||
const call_status_hook = this.call_status_hook;
|
||||
this.callInfo.updateCallStatus(callStatus, sipStatus);
|
||||
if (typeof duration === 'number') this.callInfo.duration = duration;
|
||||
try {
|
||||
this.notifyHook(this.application.call_status_hook);
|
||||
this.notifyHook(call_status_hook);
|
||||
} catch (err) {
|
||||
this.logger.info(err, `CallSession:_notifyCallStatusChange error sending ${callStatus} ${sipStatus}`);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
const CallSession = require('./call-session');
|
||||
const {CallDirection} = require('../utils/constants');
|
||||
|
||||
class ConfirmCallSession extends CallSession {
|
||||
constructor({logger, application, dlg, ep, tasks}) {
|
||||
constructor({logger, application, dlg, ep, tasks, callInfo}) {
|
||||
super({
|
||||
logger,
|
||||
application,
|
||||
srf: dlg.srf,
|
||||
callSid: dlg.callSid,
|
||||
tasks
|
||||
tasks,
|
||||
callInfo
|
||||
});
|
||||
this.dlg = dlg;
|
||||
this.ep = ep;
|
||||
this.direction = CallDirection.Outbound;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,20 +21,6 @@ class InboundCallSession extends CallSession {
|
||||
this._notifyCallStatusChange({callStatus: CallStatus.Trying, sipStatus: 100});
|
||||
}
|
||||
|
||||
get speechSynthesisVendor() {
|
||||
return this.application.speech_synthesis_vendor;
|
||||
}
|
||||
get speechSynthesisVoice() {
|
||||
return this.application.speech_synthesis_voice;
|
||||
}
|
||||
|
||||
get speechRecognizerVendor() {
|
||||
return this.application.speech_recognizer_vendor;
|
||||
}
|
||||
get speechRecognizerLanguage() {
|
||||
return this.application.speech_recognizer_language;
|
||||
}
|
||||
|
||||
_onTasksDone() {
|
||||
if (!this.res.finalResponseSent) {
|
||||
this.logger.info('InboundCallSession:_onTasksDone auto-generating non-success response to invite');
|
||||
|
||||
34
lib/session/rest-call-session.js
Normal file
34
lib/session/rest-call-session.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const CallSession = require('./call-session');
|
||||
const {CallStatus} = require('../utils/constants');
|
||||
const moment = require('moment');
|
||||
|
||||
class RestCallSession extends CallSession {
|
||||
constructor({logger, application, srf, req, ep, tasks, callInfo}) {
|
||||
super({
|
||||
logger,
|
||||
application,
|
||||
srf,
|
||||
callSid: callInfo.callSid,
|
||||
tasks,
|
||||
callInfo
|
||||
});
|
||||
this.req = req;
|
||||
this.ep = ep;
|
||||
}
|
||||
|
||||
setDialog(dlg) {
|
||||
this.dlg = dlg;
|
||||
dlg.on('destroy', this._callerHungup.bind(this));
|
||||
dlg.connectTime = moment();
|
||||
}
|
||||
|
||||
_callerHungup() {
|
||||
const duration = moment().diff(this.dlg.connectTime, 'seconds');
|
||||
this.emit('callStatusChange', {callStatus: CallStatus.Completed, duration});
|
||||
this.logger.debug('InboundCallSession: caller hung up');
|
||||
this._callReleased();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = RestCallSession;
|
||||
Reference in New Issue
Block a user