mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2026-02-14 18:30:59 +00:00
Compare commits
1 Commits
revert/tts
...
v0.8.3-4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3df8b66a09 |
9
app.js
9
app.js
@@ -20,9 +20,7 @@ const tracer = require('./tracer')(JAMBONES_OTEL_SERVICE_NAME);
|
|||||||
const api = require('@opentelemetry/api');
|
const api = require('@opentelemetry/api');
|
||||||
srf.locals = {...srf.locals, otel: {tracer, api}};
|
srf.locals = {...srf.locals, otel: {tracer, api}};
|
||||||
|
|
||||||
const opts = {
|
const opts = {level: JAMBONES_LOGLEVEL};
|
||||||
level: JAMBONES_LOGLEVEL
|
|
||||||
};
|
|
||||||
const pino = require('pino');
|
const pino = require('pino');
|
||||||
const logger = pino(opts, pino.destination({sync: false}));
|
const logger = pino(opts, pino.destination({sync: false}));
|
||||||
const {LifeCycleEvents, FS_UUID_SET_NAME} = require('./lib/utils/constants');
|
const {LifeCycleEvents, FS_UUID_SET_NAME} = require('./lib/utils/constants');
|
||||||
@@ -120,15 +118,10 @@ function handle(signal) {
|
|||||||
srf.locals.disabled = true;
|
srf.locals.disabled = true;
|
||||||
logger.info(`got signal ${signal}`);
|
logger.info(`got signal ${signal}`);
|
||||||
const setName = `${(JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
const setName = `${(JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||||
const fsServiceUrlSetName = `${(JAMBONES_CLUSTER_ID || 'default')}:fs-service-url`;
|
|
||||||
if (setName && srf.locals.localSipAddress) {
|
if (setName && srf.locals.localSipAddress) {
|
||||||
logger.info(`got signal ${signal}, removing ${srf.locals.localSipAddress} from set ${setName}`);
|
logger.info(`got signal ${signal}, removing ${srf.locals.localSipAddress} from set ${setName}`);
|
||||||
removeFromSet(setName, srf.locals.localSipAddress);
|
removeFromSet(setName, srf.locals.localSipAddress);
|
||||||
}
|
}
|
||||||
if (fsServiceUrlSetName && srf.locals.serviceUrl) {
|
|
||||||
logger.info(`got signal ${signal}, removing ${srf.locals.serviceUrl} from set ${fsServiceUrlSetName}`);
|
|
||||||
removeFromSet(fsServiceUrlSetName, srf.locals.serviceUrl);
|
|
||||||
}
|
|
||||||
removeFromSet(FS_UUID_SET_NAME, srf.locals.fsUUID);
|
removeFromSet(FS_UUID_SET_NAME, srf.locals.fsUUID);
|
||||||
if (K8S) {
|
if (K8S) {
|
||||||
srf.locals.lifecycleEmitter.operationalState = LifeCycleEvents.ScaleIn;
|
srf.locals.lifecycleEmitter.operationalState = LifeCycleEvents.ScaleIn;
|
||||||
|
|||||||
@@ -144,9 +144,6 @@ const JAMBONES_REDIS_SENTINELS = process.env.JAMBONES_REDIS_SENTINELS ? {
|
|||||||
username: process.env.JAMBONES_REDIS_SENTINEL_USERNAME
|
username: process.env.JAMBONES_REDIS_SENTINEL_USERNAME
|
||||||
})
|
})
|
||||||
} : null;
|
} : null;
|
||||||
const JAMBONZ_RECORD_WS_BASE_URL = process.env.JAMBONZ_RECORD_WS_BASE_URL;
|
|
||||||
const JAMBONZ_RECORD_WS_USERNAME = process.env.JAMBONZ_RECORD_WS_USERNAME;
|
|
||||||
const JAMBONZ_RECORD_WS_PASSWORD = process.env.JAMBONZ_RECORD_WS_PASSWORD;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
JAMBONES_MYSQL_HOST,
|
JAMBONES_MYSQL_HOST,
|
||||||
@@ -222,8 +219,5 @@ module.exports = {
|
|||||||
MICROSOFT_REGION,
|
MICROSOFT_REGION,
|
||||||
MICROSOFT_API_KEY,
|
MICROSOFT_API_KEY,
|
||||||
SONIOX_API_KEY,
|
SONIOX_API_KEY,
|
||||||
DEEPGRAM_API_KEY,
|
DEEPGRAM_API_KEY
|
||||||
JAMBONZ_RECORD_WS_BASE_URL,
|
|
||||||
JAMBONZ_RECORD_WS_USERNAME,
|
|
||||||
JAMBONZ_RECORD_WS_PASSWORD
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ router.post('/', async(req, res) => {
|
|||||||
const restDial = makeTask(logger, {'rest:dial': req.body});
|
const restDial = makeTask(logger, {'rest:dial': req.body});
|
||||||
restDial.appJson = app_json;
|
restDial.appJson = app_json;
|
||||||
const {lookupAccountDetails, lookupCarrierByPhoneNumber, lookupCarrier} = dbUtils(logger, srf);
|
const {lookupAccountDetails, lookupCarrierByPhoneNumber, lookupCarrier} = dbUtils(logger, srf);
|
||||||
const {
|
|
||||||
lookupAppBySid
|
|
||||||
} = srf.locals.dbHelpers;
|
|
||||||
const {getSBC, getFreeswitch} = srf.locals;
|
const {getSBC, getFreeswitch} = srf.locals;
|
||||||
const sbcAddress = getSBC();
|
const sbcAddress = getSBC();
|
||||||
if (!sbcAddress) throw new Error('no available SBCs for outbound call creation');
|
if (!sbcAddress) throw new Error('no available SBCs for outbound call creation');
|
||||||
@@ -44,9 +41,6 @@ router.post('/', async(req, res) => {
|
|||||||
const account = await lookupAccountBySid(req.body.account_sid);
|
const account = await lookupAccountBySid(req.body.account_sid);
|
||||||
const accountInfo = await lookupAccountDetails(req.body.account_sid);
|
const accountInfo = await lookupAccountDetails(req.body.account_sid);
|
||||||
const callSid = uuidv4();
|
const callSid = uuidv4();
|
||||||
const application = req.body.application_sid ? await lookupAppBySid(req.body.application_sid) : null;
|
|
||||||
const record_all_calls = account.record_all_calls || (application && application.record_all_calls);
|
|
||||||
const recordOutputFormat = account.record_format || 'mp3';
|
|
||||||
|
|
||||||
opts.headers = {
|
opts.headers = {
|
||||||
...opts.headers,
|
...opts.headers,
|
||||||
@@ -55,8 +49,7 @@ router.post('/', async(req, res) => {
|
|||||||
'X-Call-Sid': callSid,
|
'X-Call-Sid': callSid,
|
||||||
'X-Account-Sid': accountSid,
|
'X-Account-Sid': accountSid,
|
||||||
...(req.body?.application_sid && {'X-Application-Sid': req.body.application_sid}),
|
...(req.body?.application_sid && {'X-Application-Sid': req.body.application_sid}),
|
||||||
...(restDial.fromHost && {'X-Preferred-From-Host': restDial.fromHost}),
|
...(restDial.fromHost && {'X-Preferred-From-Host': restDial.fromHost})
|
||||||
...(record_all_calls && {'X-Record-All-Calls': recordOutputFormat})
|
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (target.type) {
|
switch (target.type) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const dbUtils = require('./utils/db-utils');
|
|||||||
const RootSpan = require('./utils/call-tracer');
|
const RootSpan = require('./utils/call-tracer');
|
||||||
const listTaskNames = require('./utils/summarize-tasks');
|
const listTaskNames = require('./utils/summarize-tasks');
|
||||||
const {
|
const {
|
||||||
JAMBONES_MYSQL_REFRESH_TTL
|
JAMBONES_MYSQL_REFRESH_TTL,
|
||||||
} = require('./config');
|
} = require('./config');
|
||||||
|
|
||||||
module.exports = function(srf, logger) {
|
module.exports = function(srf, logger) {
|
||||||
@@ -322,7 +322,6 @@ module.exports = function(srf, logger) {
|
|||||||
const httpHeaders = b3 && { b3 };
|
const httpHeaders = b3 && { b3 };
|
||||||
json = await app.requestor.request('session:new', app.call_hook, params, httpHeaders);
|
json = await app.requestor.request('session:new', app.call_hook, params, httpHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.tasks = normalizeJambones(logger, json).map((tdata) => makeTask(logger, tdata));
|
app.tasks = normalizeJambones(logger, json).map((tdata) => makeTask(logger, tdata));
|
||||||
span?.setAttributes({
|
span?.setAttributes({
|
||||||
'http.statusCode': 200,
|
'http.statusCode': 200,
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ const HttpRequestor = require('../utils/http-requestor');
|
|||||||
const WsRequestor = require('../utils/ws-requestor');
|
const WsRequestor = require('../utils/ws-requestor');
|
||||||
const {
|
const {
|
||||||
JAMBONES_INJECT_CONTENT,
|
JAMBONES_INJECT_CONTENT,
|
||||||
AWS_REGION,
|
AWS_REGION
|
||||||
JAMBONZ_RECORD_WS_BASE_URL,
|
|
||||||
JAMBONZ_RECORD_WS_USERNAME,
|
|
||||||
JAMBONZ_RECORD_WS_PASSWORD,
|
|
||||||
} = require('../config');
|
} = require('../config');
|
||||||
const BADPRECONDITIONS = 'preconditions not met';
|
const BADPRECONDITIONS = 'preconditions not met';
|
||||||
const CALLER_CANCELLED_ERR_MSG = 'Response not sent due to unknown transaction';
|
const CALLER_CANCELLED_ERR_MSG = 'Response not sent due to unknown transaction';
|
||||||
@@ -135,11 +132,6 @@ class CallSession extends Emitter {
|
|||||||
return this.callInfo.callStatus;
|
return this.callInfo.callStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isBackGroundListen() {
|
|
||||||
return !(this.backgroundListenTask === null ||
|
|
||||||
this.backgroundListenTask === undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SIP call-id for the call
|
* SIP call-id for the call
|
||||||
*/
|
*/
|
||||||
@@ -423,10 +415,7 @@ class CallSession extends Emitter {
|
|||||||
'X-Call-Sid': this.callSid,
|
'X-Call-Sid': this.callSid,
|
||||||
'X-Account-Sid': this.accountSid,
|
'X-Account-Sid': this.accountSid,
|
||||||
'X-Application-Sid': this.applicationSid,
|
'X-Application-Sid': this.applicationSid,
|
||||||
...(this.recordOptions.headers && {'Content-Type': 'application/json'})
|
}
|
||||||
},
|
|
||||||
// Siprect Client is initiated from startCallRecording, so just need to pass custom headers in startRecording
|
|
||||||
...(this.recordOptions.headers && {body: JSON.stringify(this.recordOptions.headers) + '\n'})
|
|
||||||
});
|
});
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
this._recordState = RecordState.RecordingOn;
|
this._recordState = RecordState.RecordingOn;
|
||||||
@@ -447,7 +436,7 @@ class CallSession extends Emitter {
|
|||||||
const res = await this.dlg.request({
|
const res = await this.dlg.request({
|
||||||
method: 'INFO',
|
method: 'INFO',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Reason': 'stopCallRecording'
|
'X-Reason': 'stopCallRecording',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
@@ -469,7 +458,7 @@ class CallSession extends Emitter {
|
|||||||
const res = await this.dlg.request({
|
const res = await this.dlg.request({
|
||||||
method: 'INFO',
|
method: 'INFO',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Reason': 'pauseCallRecording'
|
'X-Reason': 'pauseCallRecording',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
@@ -491,7 +480,7 @@ class CallSession extends Emitter {
|
|||||||
const res = await this.dlg.request({
|
const res = await this.dlg.request({
|
||||||
method: 'INFO',
|
method: 'INFO',
|
||||||
headers: {
|
headers: {
|
||||||
'X-Reason': 'resumeCallRecording'
|
'X-Reason': 'resumeCallRecording',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
@@ -506,7 +495,7 @@ class CallSession extends Emitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async startBackgroundListen(opts, bugname) {
|
async startBackgroundListen(opts) {
|
||||||
if (this.isListenEnabled) {
|
if (this.isListenEnabled) {
|
||||||
this.logger.info('CallSession:startBackgroundListen - listen is already enabled, ignoring request');
|
this.logger.info('CallSession:startBackgroundListen - listen is already enabled, ignoring request');
|
||||||
return;
|
return;
|
||||||
@@ -515,11 +504,8 @@ class CallSession extends Emitter {
|
|||||||
this.logger.debug({opts}, 'CallSession:startBackgroundListen');
|
this.logger.debug({opts}, 'CallSession:startBackgroundListen');
|
||||||
const t = normalizeJambones(this.logger, [opts]);
|
const t = normalizeJambones(this.logger, [opts]);
|
||||||
this.backgroundListenTask = makeTask(this.logger, t[0]);
|
this.backgroundListenTask = makeTask(this.logger, t[0]);
|
||||||
this.backgroundListenTask.bugname = bugname;
|
|
||||||
// Remove unneeded customer data to be sent to api server.
|
|
||||||
this.backgroundListenTask.ignoreCustomerData = true;
|
|
||||||
const resources = await this._evaluatePreconditions(this.backgroundListenTask);
|
const resources = await this._evaluatePreconditions(this.backgroundListenTask);
|
||||||
const {span, ctx} = this.rootSpan.startChildSpan(`background-listen:${this.backgroundListenTask.summary}`);
|
const {span, ctx} = this.rootSpan.startChildSpan(`background-gather:${this.backgroundListenTask.summary}`);
|
||||||
this.backgroundListenTask.span = span;
|
this.backgroundListenTask.span = span;
|
||||||
this.backgroundListenTask.ctx = ctx;
|
this.backgroundListenTask.ctx = ctx;
|
||||||
this.backgroundListenTask.exec(this, resources)
|
this.backgroundListenTask.exec(this, resources)
|
||||||
@@ -542,7 +528,6 @@ class CallSession extends Emitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async stopBackgroundListen() {
|
async stopBackgroundListen() {
|
||||||
this.logger.debug('CallSession:stopBackgroundListen');
|
|
||||||
try {
|
try {
|
||||||
if (this.backgroundListenTask) {
|
if (this.backgroundListenTask) {
|
||||||
this.backgroundListenTask.removeAllListeners();
|
this.backgroundListenTask.removeAllListeners();
|
||||||
@@ -551,6 +536,7 @@ class CallSession extends Emitter {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.info({err}, 'CallSession:stopBackgroundListen - Error stopping listen task');
|
this.logger.info({err}, 'CallSession:stopBackgroundListen - Error stopping listen task');
|
||||||
}
|
}
|
||||||
|
this.backgroundListenTask = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async enableBotMode(gather, autoEnable) {
|
async enableBotMode(gather, autoEnable) {
|
||||||
@@ -1355,10 +1341,7 @@ class CallSession extends Emitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we are going from an early media connection to answer
|
// we are going from an early media connection to answer
|
||||||
if (this.direction === CallDirection.Inbound) {
|
await this.propagateAnswer();
|
||||||
// only do this for inbound call.
|
|
||||||
await this.propagateAnswer();
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
...resources,
|
...resources,
|
||||||
...(this.isSipRecCallSession && {ep2: this.ep2})
|
...(this.isSipRecCallSession && {ep2: this.ep2})
|
||||||
@@ -1529,6 +1512,7 @@ class CallSession extends Emitter {
|
|||||||
}
|
}
|
||||||
this.dlg.on('modify', this._onReinvite.bind(this));
|
this.dlg.on('modify', this._onReinvite.bind(this));
|
||||||
this.dlg.on('refer', this._onRefer.bind(this));
|
this.dlg.on('refer', this._onRefer.bind(this));
|
||||||
|
|
||||||
this.logger.debug(`CallSession:propagateAnswer - answered callSid ${this.callSid}`);
|
this.logger.debug(`CallSession:propagateAnswer - answered callSid ${this.callSid}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1765,13 +1749,6 @@ class CallSession extends Emitter {
|
|||||||
async _notifyCallStatusChange({callStatus, sipStatus, sipReason, duration}) {
|
async _notifyCallStatusChange({callStatus, sipStatus, sipReason, duration}) {
|
||||||
if (this.callMoved) return;
|
if (this.callMoved) return;
|
||||||
|
|
||||||
if (callStatus === CallStatus.InProgress) {
|
|
||||||
// nice, call is in progress, good time to enable record
|
|
||||||
await this.enableRecordAllCall();
|
|
||||||
} else if (callStatus == CallStatus.Completed && this.isBackGroundListen) {
|
|
||||||
await this.stopBackgroundListen();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* race condition: we hang up at the same time as the caller */
|
/* race condition: we hang up at the same time as the caller */
|
||||||
if (callStatus === CallStatus.Completed) {
|
if (callStatus === CallStatus.Completed) {
|
||||||
if (this.notifiedComplete) return;
|
if (this.notifiedComplete) return;
|
||||||
@@ -1784,15 +1761,6 @@ class CallSession extends Emitter {
|
|||||||
|
|
||||||
this.callInfo.updateCallStatus(callStatus, sipStatus, sipReason);
|
this.callInfo.updateCallStatus(callStatus, sipStatus, sipReason);
|
||||||
if (typeof duration === 'number') this.callInfo.duration = duration;
|
if (typeof duration === 'number') this.callInfo.duration = duration;
|
||||||
this.executeStatusCallback(callStatus, sipStatus);
|
|
||||||
|
|
||||||
// update calls db
|
|
||||||
//this.logger.debug(`updating redis with ${JSON.stringify(this.callInfo)}`);
|
|
||||||
this.updateCallStatus(Object.assign({}, this.callInfo.toJSON()), this.serviceUrl)
|
|
||||||
.catch((err) => this.logger.error(err, 'redis error'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeStatusCallback(callStatus, sipStatus) {
|
|
||||||
const {span} = this.rootSpan.startChildSpan(`call-status:${this.callInfo.callStatus}`);
|
const {span} = this.rootSpan.startChildSpan(`call-status:${this.callInfo.callStatus}`);
|
||||||
span.setAttributes(this.callInfo.toJSON());
|
span.setAttributes(this.callInfo.toJSON());
|
||||||
try {
|
try {
|
||||||
@@ -1804,23 +1772,11 @@ class CallSession extends Emitter {
|
|||||||
span.end();
|
span.end();
|
||||||
this.logger.info(err, `CallSession:_notifyCallStatusChange error sending ${callStatus} ${sipStatus}`);
|
this.logger.info(err, `CallSession:_notifyCallStatusChange error sending ${callStatus} ${sipStatus}`);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async enableRecordAllCall() {
|
// update calls db
|
||||||
if (this.accountInfo.account.record_all_calls || this.application.record_all_calls) {
|
//this.logger.debug(`updating redis with ${JSON.stringify(this.callInfo)}`);
|
||||||
const listenOpts = {
|
this.updateCallStatus(Object.assign({}, this.callInfo.toJSON()), this.serviceUrl)
|
||||||
url: `${JAMBONZ_RECORD_WS_BASE_URL}/record/${this.accountInfo.account.bucket_credential.vendor}`,
|
.catch((err) => this.logger.error(err, 'redis error'));
|
||||||
wsAuth: {
|
|
||||||
username: JAMBONZ_RECORD_WS_USERNAME,
|
|
||||||
password: JAMBONZ_RECORD_WS_PASSWORD
|
|
||||||
},
|
|
||||||
mixType : 'stereo',
|
|
||||||
passDtmf: true
|
|
||||||
};
|
|
||||||
|
|
||||||
this.logger.debug({listenOpts}, 'Record all calls: enabling listen');
|
|
||||||
await this.startBackgroundListen({verb: 'listen', ...listenOpts}, 'jambonz-session-record');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -114,12 +114,7 @@ class Conference extends Task {
|
|||||||
}
|
}
|
||||||
this.emitter.emit('kill');
|
this.emitter.emit('kill');
|
||||||
await this._doFinalMemberCheck(cs);
|
await this._doFinalMemberCheck(cs);
|
||||||
if (this.ep && this.ep.connected) {
|
if (this.ep && this.ep.connected) this.ep.conn.removeAllListeners('esl::event::CUSTOM::*') ;
|
||||||
this.ep.conn.removeAllListeners('esl::event::CUSTOM::*');
|
|
||||||
this.ep.api(`conference ${this.confName} kick ${this.memberId}`)
|
|
||||||
.catch((err) => this.logger.info({err}, 'Error kicking participant'));
|
|
||||||
}
|
|
||||||
cs.clearConferenceDetails();
|
|
||||||
this.notifyTaskDone();
|
this.notifyTaskDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,6 @@ class TaskDial extends Task {
|
|||||||
|
|
||||||
get canReleaseMedia() {
|
get canReleaseMedia() {
|
||||||
const keepAnchor = this.data.anchorMedia ||
|
const keepAnchor = this.data.anchorMedia ||
|
||||||
this.cs.isBackGroundListen ||
|
|
||||||
ANCHOR_MEDIA_ALWAYS ||
|
ANCHOR_MEDIA_ALWAYS ||
|
||||||
this.listenTask ||
|
this.listenTask ||
|
||||||
this.transcribeTask ||
|
this.transcribeTask ||
|
||||||
|
|||||||
@@ -817,11 +817,7 @@ class TaskGather extends Task {
|
|||||||
this.logger.debug({evt}, 'TaskGather:resolve buffered results');
|
this.logger.debug({evt}, 'TaskGather:resolve buffered results');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.span.setAttributes({
|
this.span.setAttributes({'stt.resolve': reason, 'stt.result': JSON.stringify(evt)});
|
||||||
channel: 1,
|
|
||||||
'stt.resolve': reason,
|
|
||||||
'stt.result': JSON.stringify(evt)
|
|
||||||
});
|
|
||||||
if (this.needsStt && this.ep && this.ep.connected) {
|
if (this.needsStt && this.ep && this.ep.connected) {
|
||||||
this.ep.stopTranscription({vendor: this.vendor})
|
this.ep.stopTranscription({vendor: this.vendor})
|
||||||
.catch((err) => this.logger.error({err}, 'Error stopping transcription'));
|
.catch((err) => this.logger.error({err}, 'Error stopping transcription'));
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ const {TaskName, TaskPreconditions, ListenEvents, ListenStatus} = require('../ut
|
|||||||
const makeTask = require('./make_task');
|
const makeTask = require('./make_task');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
const MAX_PLAY_AUDIO_QUEUE_SIZE = 10;
|
const MAX_PLAY_AUDIO_QUEUE_SIZE = 10;
|
||||||
const DTMF_SPAN_NAME = 'dtmf';
|
|
||||||
|
|
||||||
class TaskListen extends Task {
|
class TaskListen extends Task {
|
||||||
constructor(logger, opts, parentTask) {
|
constructor(logger, opts, parentTask) {
|
||||||
@@ -30,10 +29,6 @@ class TaskListen extends Task {
|
|||||||
|
|
||||||
get name() { return TaskName.Listen; }
|
get name() { return TaskName.Listen; }
|
||||||
|
|
||||||
set bugname(name) { this._bugname = name; }
|
|
||||||
|
|
||||||
set ignoreCustomerData(val) { this._ignoreCustomerData = val; }
|
|
||||||
|
|
||||||
async exec(cs, {ep}) {
|
async exec(cs, {ep}) {
|
||||||
await super.exec(cs);
|
await super.exec(cs);
|
||||||
this.ep = ep;
|
this.ep = ep;
|
||||||
@@ -70,8 +65,7 @@ class TaskListen extends Task {
|
|||||||
if (this.ep && this.ep.connected) {
|
if (this.ep && this.ep.connected) {
|
||||||
this.logger.debug('TaskListen:kill closing websocket');
|
this.logger.debug('TaskListen:kill closing websocket');
|
||||||
try {
|
try {
|
||||||
const args = this._bugname ? [this._bugname] : [];
|
await this.ep.forkAudioStop();
|
||||||
await this.ep.forkAudioStop(...args);
|
|
||||||
this.logger.debug('TaskListen:kill successfully closed websocket');
|
this.logger.debug('TaskListen:kill successfully closed websocket');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.info(err, 'TaskListen:kill');
|
this.logger.info(err, 'TaskListen:kill');
|
||||||
@@ -91,16 +85,13 @@ class TaskListen extends Task {
|
|||||||
|
|
||||||
async updateListen(status) {
|
async updateListen(status) {
|
||||||
if (!this.killed && this.ep && this.ep.connected) {
|
if (!this.killed && this.ep && this.ep.connected) {
|
||||||
const args = this._bugname ? [this._bugname] : [];
|
|
||||||
this.logger.info(`TaskListen:updateListen status ${status}`);
|
this.logger.info(`TaskListen:updateListen status ${status}`);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case ListenStatus.Pause:
|
case ListenStatus.Pause:
|
||||||
await this.ep.forkAudioPause(...args)
|
await this.ep.forkAudioPause().catch((err) => this.logger.info(err, 'TaskListen: error pausing audio'));
|
||||||
.catch((err) => this.logger.info(err, 'TaskListen: error pausing audio'));
|
|
||||||
break;
|
break;
|
||||||
case ListenStatus.Resume:
|
case ListenStatus.Resume:
|
||||||
await this.ep.forkAudioResume(...args)
|
await this.ep.forkAudioResume().catch((err) => this.logger.info(err, 'TaskListen: error resuming audio'));
|
||||||
.catch((err) => this.logger.info(err, 'TaskListen: error resuming audio'));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,13 +104,9 @@ class TaskListen extends Task {
|
|||||||
|
|
||||||
async _startListening(cs, ep) {
|
async _startListening(cs, ep) {
|
||||||
this._initListeners(ep);
|
this._initListeners(ep);
|
||||||
const ci = this.nested ? this.parentTask.sd.callInfo : cs.callInfo.toJSON();
|
|
||||||
if (this._ignoreCustomerData) {
|
|
||||||
delete ci.customerData;
|
|
||||||
}
|
|
||||||
const metadata = Object.assign(
|
const metadata = Object.assign(
|
||||||
{sampleRate: this.sampleRate, mixType: this.mixType},
|
{sampleRate: this.sampleRate, mixType: this.mixType},
|
||||||
ci,
|
this.nested ? this.parentTask.sd.callInfo : cs.callInfo.toJSON(),
|
||||||
this.metadata);
|
this.metadata);
|
||||||
if (this.hook.auth) {
|
if (this.hook.auth) {
|
||||||
this.logger.debug({username: this.hook.auth.username, password: this.hook.auth.password},
|
this.logger.debug({username: this.hook.auth.username, password: this.hook.auth.password},
|
||||||
@@ -133,7 +120,6 @@ class TaskListen extends Task {
|
|||||||
wsUrl: this.hook.url,
|
wsUrl: this.hook.url,
|
||||||
mixType: this.mixType,
|
mixType: this.mixType,
|
||||||
sampling: this.sampleRate,
|
sampling: this.sampleRate,
|
||||||
...(this._bugname && {bugname: this._bugname}),
|
|
||||||
metadata
|
metadata
|
||||||
});
|
});
|
||||||
this.recordStartTime = moment();
|
this.recordStartTime = moment();
|
||||||
@@ -175,25 +161,12 @@ class TaskListen extends Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onDtmf(ep, evt) {
|
_onDtmf(ep, evt) {
|
||||||
const {dtmf, duration} = evt;
|
this.logger.debug({evt}, `TaskListen:_onDtmf received dtmf ${evt.dtmf}`);
|
||||||
this.logger.debug({evt}, `TaskListen:_onDtmf received dtmf ${dtmf}`);
|
|
||||||
if (this.passDtmf && this.ep?.connected) {
|
if (this.passDtmf && this.ep?.connected) {
|
||||||
const obj = {event: 'dtmf', dtmf, duration};
|
const obj = {event: 'dtmf', dtmf: evt.dtmf, duration: evt.duration};
|
||||||
const args = this._bugname ? [this._bugname, obj] : [obj];
|
this.ep.forkAudioSendText(obj)
|
||||||
this.ep.forkAudioSendText(...args)
|
|
||||||
.catch((err) => this.logger.info({err}, 'TaskListen:_onDtmf error sending dtmf'));
|
.catch((err) => this.logger.info({err}, 'TaskListen:_onDtmf error sending dtmf'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add a child span for the dtmf event */
|
|
||||||
const msDuration = Math.floor((duration / 8000) * 1000);
|
|
||||||
const {span} = this.startChildSpan(`${DTMF_SPAN_NAME}:${dtmf}`);
|
|
||||||
span.setAttributes({
|
|
||||||
channel: 1,
|
|
||||||
dtmf,
|
|
||||||
duration: `${msDuration}ms`
|
|
||||||
});
|
|
||||||
span.end();
|
|
||||||
|
|
||||||
if (evt.dtmf === this.finishOnKey) {
|
if (evt.dtmf === this.finishOnKey) {
|
||||||
this.logger.info(`TaskListen:_onDtmf terminating task due to dtmf ${evt.dtmf}`);
|
this.logger.info(`TaskListen:_onDtmf terminating task due to dtmf ${evt.dtmf}`);
|
||||||
this.results.digits = evt.dtmf;
|
this.results.digits = evt.dtmf;
|
||||||
@@ -219,15 +192,7 @@ class TaskListen extends Task {
|
|||||||
try {
|
try {
|
||||||
const results = await ep.play(evt.file);
|
const results = await ep.play(evt.file);
|
||||||
logger.debug(`Finished playing file, result: ${JSON.stringify(results)}`);
|
logger.debug(`Finished playing file, result: ${JSON.stringify(results)}`);
|
||||||
const obj = {
|
ep.forkAudioSendText({type: 'playDone', data: Object.assign({id: evt.id}, results)});
|
||||||
type: 'playDone',
|
|
||||||
data: {
|
|
||||||
id: evt.id,
|
|
||||||
...results
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const args = this._bugname ? [this._bugname, obj] : [obj];
|
|
||||||
ep.forkAudioSendText(...args);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error({err}, 'Error playing file');
|
logger.error({err}, 'Error playing file');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,11 +298,7 @@ class TaskTranscribe extends Task {
|
|||||||
|
|
||||||
/* we've got a transcript, so end the otel child span for this channel */
|
/* we've got a transcript, so end the otel child span for this channel */
|
||||||
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
||||||
this.childSpan[channel - 1].span.setAttributes({
|
this.childSpan[channel - 1].span.setAttributes({'stt.resolve': 'transcript', 'stt.result': JSON.stringify(evt)});
|
||||||
channel,
|
|
||||||
'stt.resolve': 'transcript',
|
|
||||||
'stt.result': JSON.stringify(evt)
|
|
||||||
});
|
|
||||||
this.childSpan[channel - 1].span.end();
|
this.childSpan[channel - 1].span.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,10 +342,7 @@ class TaskTranscribe extends Task {
|
|||||||
_onNoAudio(cs, ep, channel) {
|
_onNoAudio(cs, ep, channel) {
|
||||||
this.logger.debug(`TaskTranscribe:_onNoAudio restarting transcription on channel ${channel}`);
|
this.logger.debug(`TaskTranscribe:_onNoAudio restarting transcription on channel ${channel}`);
|
||||||
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
||||||
this.childSpan[channel - 1].span.setAttributes({
|
this.childSpan[channel - 1].span.setAttributes({'stt.resolve': 'timeout'});
|
||||||
channel,
|
|
||||||
'stt.resolve': 'timeout'
|
|
||||||
});
|
|
||||||
this.childSpan[channel - 1].span.end();
|
this.childSpan[channel - 1].span.end();
|
||||||
}
|
}
|
||||||
this._transcribe(ep);
|
this._transcribe(ep);
|
||||||
@@ -362,10 +355,7 @@ class TaskTranscribe extends Task {
|
|||||||
_onMaxDurationExceeded(cs, ep, channel) {
|
_onMaxDurationExceeded(cs, ep, channel) {
|
||||||
this.logger.debug(`TaskTranscribe:_onMaxDurationExceeded restarting transcription on channel ${channel}`);
|
this.logger.debug(`TaskTranscribe:_onMaxDurationExceeded restarting transcription on channel ${channel}`);
|
||||||
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
||||||
this.childSpan[channel - 1].span.setAttributes({
|
this.childSpan[channel - 1].span.setAttributes({'stt.resolve': 'max duration exceeded'});
|
||||||
channel,
|
|
||||||
'stt.resolve': 'max duration exceeded'
|
|
||||||
});
|
|
||||||
this.childSpan[channel - 1].span.end();
|
this.childSpan[channel - 1].span.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,10 +389,7 @@ class TaskTranscribe extends Task {
|
|||||||
this.notifyError(`Failed connecting to speech vendor deepgram: ${reason}`);
|
this.notifyError(`Failed connecting to speech vendor deepgram: ${reason}`);
|
||||||
|
|
||||||
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
||||||
this.childSpan[channel - 1].span.setAttributes({
|
this.childSpan[channel - 1].span.setAttributes({'stt.resolve': 'connection failure'});
|
||||||
channel,
|
|
||||||
'stt.resolve': 'connection failure'
|
|
||||||
});
|
|
||||||
this.childSpan[channel - 1].span.end();
|
this.childSpan[channel - 1].span.end();
|
||||||
}
|
}
|
||||||
this.notifyTaskDone();
|
this.notifyTaskDone();
|
||||||
@@ -425,10 +412,7 @@ class TaskTranscribe extends Task {
|
|||||||
this.notifyError(`Failed connecting to speech vendor IBM: ${reason}`);
|
this.notifyError(`Failed connecting to speech vendor IBM: ${reason}`);
|
||||||
|
|
||||||
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
if (this.childSpan[channel - 1] && this.childSpan[channel - 1].span) {
|
||||||
this.childSpan[channel - 1].span.setAttributes({
|
this.childSpan[channel - 1].span.setAttributes({'stt.resolve': 'connection failure'});
|
||||||
channel,
|
|
||||||
'stt.resolve': 'connection failure'
|
|
||||||
});
|
|
||||||
this.childSpan[channel - 1].span.end();
|
this.childSpan[channel - 1].span.end();
|
||||||
}
|
}
|
||||||
this.notifyTaskDone();
|
this.notifyTaskDone();
|
||||||
|
|||||||
@@ -11,20 +11,15 @@ const {LifeCycleEvents} = require('./constants');
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const app = express();
|
const app = express();
|
||||||
const getString = bent('string');
|
const getString = bent('string');
|
||||||
const {
|
const AWS = require('aws-sdk');
|
||||||
SNSClient,
|
const sns = new AWS.SNS({apiVersion: '2010-03-31'});
|
||||||
SubscribeCommand,
|
const autoscaling = new AWS.AutoScaling({apiVersion: '2011-01-01'});
|
||||||
UnsubscribeCommand } = require('@aws-sdk/client-sns');
|
|
||||||
const snsClient = new SNSClient({ region: AWS_REGION, apiVersion: '2010-03-31' });
|
|
||||||
const {
|
|
||||||
AutoScalingClient,
|
|
||||||
DescribeAutoScalingGroupsCommand,
|
|
||||||
CompleteLifecycleActionCommand } = require('@aws-sdk/client-auto-scaling');
|
|
||||||
const autoScalingClient = new AutoScalingClient({ region: AWS_REGION, apiVersion: '2011-01-01' });
|
|
||||||
const {Parser} = require('xml2js');
|
const {Parser} = require('xml2js');
|
||||||
const parser = new Parser();
|
const parser = new Parser();
|
||||||
const {validatePayload} = require('verify-aws-sns-signature');
|
const {validatePayload} = require('verify-aws-sns-signature');
|
||||||
|
|
||||||
|
AWS.config.update({region: AWS_REGION});
|
||||||
|
|
||||||
class SnsNotifier extends Emitter {
|
class SnsNotifier extends Emitter {
|
||||||
constructor(logger) {
|
constructor(logger) {
|
||||||
super();
|
super();
|
||||||
@@ -74,7 +69,7 @@ class SnsNotifier extends Emitter {
|
|||||||
subscriptionRequestId: this.subscriptionRequestId
|
subscriptionRequestId: this.subscriptionRequestId
|
||||||
}, 'response from SNS SubscribeURL');
|
}, 'response from SNS SubscribeURL');
|
||||||
const data = await this.describeInstance();
|
const data = await this.describeInstance();
|
||||||
this.lifecycleState = data.AutoScalingGroups[0].Instances[0].LifecycleState;
|
this.lifecycleState = data.AutoScalingInstances[0].LifecycleState;
|
||||||
this.emit('SubscriptionConfirmation', {publicIp: this.publicIp});
|
this.emit('SubscriptionConfirmation', {publicIp: this.publicIp});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -140,12 +135,11 @@ class SnsNotifier extends Emitter {
|
|||||||
|
|
||||||
async subscribe() {
|
async subscribe() {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const response = await sns.subscribe({
|
||||||
Protocol: 'http',
|
Protocol: 'http',
|
||||||
TopicArn: AWS_SNS_TOPIC_ARM,
|
TopicArn: AWS_SNS_TOPIC_ARM,
|
||||||
Endpoint: this.snsEndpoint
|
Endpoint: this.snsEndpoint
|
||||||
};
|
}).promise();
|
||||||
const response = await snsClient.send(new SubscribeCommand(params));
|
|
||||||
this.logger.info({response}, `response to SNS subscribe to ${AWS_SNS_TOPIC_ARM}`);
|
this.logger.info({response}, `response to SNS subscribe to ${AWS_SNS_TOPIC_ARM}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error({err}, `Error subscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
this.logger.error({err}, `Error subscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
||||||
@@ -155,10 +149,9 @@ class SnsNotifier extends Emitter {
|
|||||||
async unsubscribe() {
|
async unsubscribe() {
|
||||||
if (!this.subscriptionArn) throw new Error('SnsNotifier#unsubscribe called without an active subscription');
|
if (!this.subscriptionArn) throw new Error('SnsNotifier#unsubscribe called without an active subscription');
|
||||||
try {
|
try {
|
||||||
const params = {
|
const response = await sns.unsubscribe({
|
||||||
SubscriptionArn: this.subscriptionArn
|
SubscriptionArn: this.subscriptionArn
|
||||||
};
|
}).promise();
|
||||||
const response = await snsClient.send(new UnsubscribeCommand(params));
|
|
||||||
this.logger.info({response}, `response to SNS unsubscribe to ${AWS_SNS_TOPIC_ARM}`);
|
this.logger.info({response}, `response to SNS unsubscribe to ${AWS_SNS_TOPIC_ARM}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error({err}, `Error unsubscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
this.logger.error({err}, `Error unsubscribing to SNS topic arn ${AWS_SNS_TOPIC_ARM}`);
|
||||||
@@ -167,29 +160,26 @@ class SnsNotifier extends Emitter {
|
|||||||
|
|
||||||
completeScaleIn() {
|
completeScaleIn() {
|
||||||
assert(this.scaleInParams);
|
assert(this.scaleInParams);
|
||||||
autoScalingClient.send(new CompleteLifecycleActionCommand(this.scaleInParams))
|
autoscaling.completeLifecycleAction(this.scaleInParams, (err, response) => {
|
||||||
.then((data) => {
|
if (err) return this.logger.error({err}, 'Error completing scale-in');
|
||||||
return this.logger.info({data}, 'Successfully completed scale-in action');
|
this.logger.info({response}, 'Successfully completed scale-in action');
|
||||||
})
|
});
|
||||||
.catch((err) => {
|
|
||||||
this.logger.error({err}, 'Error completing scale-in');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describeInstance() {
|
describeInstance() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!this.instanceId) return reject('instance-id unknown');
|
if (!this.instanceId) return reject('instance-id unknown');
|
||||||
autoScalingClient.send(new DescribeAutoScalingGroupsCommand({
|
autoscaling.describeAutoScalingInstances({
|
||||||
InstanceIds: [this.instanceId]
|
InstanceIds: [this.instanceId]
|
||||||
}))
|
}, (err, data) => {
|
||||||
.then((data) => {
|
if (err) {
|
||||||
this.logger.info({data}, 'SnsNotifier: describeInstance');
|
|
||||||
return resolve(data);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
this.logger.error({err}, 'Error describing instances');
|
this.logger.error({err}, 'Error describing instances');
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
} else {
|
||||||
|
this.logger.info({data}, 'SnsNotifier: describeInstance');
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +193,7 @@ module.exports = async function(logger) {
|
|||||||
process.on('SIGHUP', async() => {
|
process.on('SIGHUP', async() => {
|
||||||
try {
|
try {
|
||||||
const data = await notifier.describeInstance();
|
const data = await notifier.describeInstance();
|
||||||
const state = data.AutoScalingGroups[0].Instances[0].LifecycleState;
|
const state = data.AutoScalingInstances[0].LifecycleState;
|
||||||
if (state !== notifier.lifecycleState) {
|
if (state !== notifier.lifecycleState) {
|
||||||
notifier.lifecycleState = state;
|
notifier.lifecycleState = state;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
|||||||
@@ -94,12 +94,6 @@ const speechMapper = (cred) => {
|
|||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bucketCredentialDecrypt = (account) => {
|
|
||||||
const { bucket_credential } = account.account;
|
|
||||||
if (!bucket_credential || bucket_credential.vendor) return;
|
|
||||||
account.account.bucket_credential = JSON.parse(decrypt(bucket_credential));
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = (logger, srf) => {
|
module.exports = (logger, srf) => {
|
||||||
const {pool} = srf.locals.dbHelpers;
|
const {pool} = srf.locals.dbHelpers;
|
||||||
const pp = pool.promise();
|
const pp = pool.promise();
|
||||||
@@ -118,11 +112,9 @@ module.exports = (logger, srf) => {
|
|||||||
speech.push(speechMapper(s));
|
speech.push(speechMapper(s));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const account = r[0];
|
|
||||||
bucketCredentialDecrypt(account);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...account,
|
...r[0],
|
||||||
speech
|
speech
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -101,8 +101,7 @@ module.exports = (logger) => {
|
|||||||
method: 'OPTIONS',
|
method: 'OPTIONS',
|
||||||
headers: {
|
headers: {
|
||||||
'X-FS-Status': ms && !dryUpCalls ? 'open' : 'closed',
|
'X-FS-Status': ms && !dryUpCalls ? 'open' : 'closed',
|
||||||
'X-FS-Calls': srf.locals.sessionTracker.count,
|
'X-FS-Calls': srf.locals.sessionTracker.count
|
||||||
'X-FS-ServiceUrl': srf.locals.serviceUrl
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
req.on('response', (res) => {
|
req.on('response', (res) => {
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ class WsRequestor extends BaseRequestor {
|
|||||||
|
|
||||||
/* simple notifications */
|
/* simple notifications */
|
||||||
if (['call:status', 'verb:status', 'jambonz:error'].includes(type) || reconnectingWithoutAck) {
|
if (['call:status', 'verb:status', 'jambonz:error'].includes(type) || reconnectingWithoutAck) {
|
||||||
this.ws?.send(JSON.stringify(obj), () => {
|
this.ws.send(JSON.stringify(obj), () => {
|
||||||
this.logger.debug({obj}, `WsRequestor:request websocket: sent (${url})`);
|
this.logger.debug({obj}, `WsRequestor:request websocket: sent (${url})`);
|
||||||
sendQueuedMsgs();
|
sendQueuedMsgs();
|
||||||
});
|
});
|
||||||
|
|||||||
6923
package-lock.json
generated
6923
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jambonz-feature-server",
|
"name": "jambonz-feature-server",
|
||||||
"version": "0.8.4",
|
"version": "0.8.3",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 10.16.0"
|
"node": ">= 10.16.0"
|
||||||
@@ -19,19 +19,19 @@
|
|||||||
"bugs": {},
|
"bugs": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node app",
|
"start": "node app",
|
||||||
"test": "NODE_ENV=test JAMBONES_HOSTING=1 HTTP_POOL=1 JAMBONES_TTS_TRIM_SILENCE=1 ENCRYPTION_SECRET=foobar DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 DRACHTIO_SECRET=cymru JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_PORT=3360 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=127.0.0.1 JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=error ENABLE_METRICS=0 HTTP_PORT=3000 JAMBONES_SBCS=172.38.0.10 JAMBONES_FREESWITCH=127.0.0.1:8022:JambonzR0ck$:docker-host JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_NETWORK_CIDR=172.38.0.0/16 node test/ ",
|
"test": "NODE_ENV=test JAMBONES_HOSTING=1 HTTP_POOL=1 ENCRYPTION_SECRET=foobar DRACHTIO_HOST=127.0.0.1 DRACHTIO_PORT=9060 DRACHTIO_SECRET=cymru JAMBONES_MYSQL_HOST=127.0.0.1 JAMBONES_MYSQL_PORT=3360 JAMBONES_MYSQL_USER=jambones_test JAMBONES_MYSQL_PASSWORD=jambones_test JAMBONES_MYSQL_DATABASE=jambones_test JAMBONES_REDIS_HOST=127.0.0.1 JAMBONES_REDIS_PORT=16379 JAMBONES_LOGLEVEL=error ENABLE_METRICS=0 HTTP_PORT=3000 JAMBONES_SBCS=172.38.0.10 JAMBONES_FREESWITCH=127.0.0.1:8022:JambonzR0ck$:docker-host JAMBONES_TIME_SERIES_HOST=127.0.0.1 JAMBONES_NETWORK_CIDR=172.38.0.0/16 node test/ ",
|
||||||
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
|
"coverage": "./node_modules/.bin/nyc --reporter html --report-dir ./coverage npm run test",
|
||||||
"jslint": "eslint app.js tracer.js lib",
|
"jslint": "eslint app.js tracer.js lib",
|
||||||
"jslint:fix": "eslint app.js tracer.js lib --fix"
|
"jslint:fix": "eslint app.js tracer.js lib --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jambonz/db-helpers": "^0.9.1",
|
"@jambonz/db-helpers": "^0.9.0",
|
||||||
"@jambonz/http-health-check": "^0.0.1",
|
"@jambonz/http-health-check": "^0.0.1",
|
||||||
"@jambonz/realtimedb-helpers": "^0.8.6",
|
"@jambonz/realtimedb-helpers": "^0.8.6",
|
||||||
"@jambonz/speech-utils": "^0.0.19",
|
"@jambonz/speech-utils": "^0.0.15",
|
||||||
"@jambonz/stats-collector": "^0.1.8",
|
"@jambonz/stats-collector": "^0.1.8",
|
||||||
"@jambonz/time-series": "^0.2.8",
|
"@jambonz/time-series": "^0.2.5",
|
||||||
"@jambonz/verb-specifications": "^0.0.26",
|
"@jambonz/verb-specifications": "^0.0.24",
|
||||||
"@opentelemetry/api": "^1.4.0",
|
"@opentelemetry/api": "^1.4.0",
|
||||||
"@opentelemetry/exporter-jaeger": "^1.9.0",
|
"@opentelemetry/exporter-jaeger": "^1.9.0",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.35.0",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.35.0",
|
||||||
@@ -41,13 +41,12 @@
|
|||||||
"@opentelemetry/sdk-trace-base": "^1.9.0",
|
"@opentelemetry/sdk-trace-base": "^1.9.0",
|
||||||
"@opentelemetry/sdk-trace-node": "^1.9.0",
|
"@opentelemetry/sdk-trace-node": "^1.9.0",
|
||||||
"@opentelemetry/semantic-conventions": "^1.9.0",
|
"@opentelemetry/semantic-conventions": "^1.9.0",
|
||||||
"@aws-sdk/client-sns": "^3.360.0",
|
"aws-sdk": "^2.1313.0",
|
||||||
"@aws-sdk/client-auto-scaling": "^3.360.0",
|
|
||||||
"bent": "^7.3.12",
|
"bent": "^7.3.12",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"deepcopy": "^2.1.0",
|
"deepcopy": "^2.1.0",
|
||||||
"drachtio-fsmrf": "^3.0.23",
|
"drachtio-fsmrf": "^3.0.21",
|
||||||
"drachtio-srf": "^4.5.26",
|
"drachtio-srf": "^4.5.23",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"ip": "^1.1.8",
|
"ip": "^1.1.8",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ const getJSON = bent('json')
|
|||||||
const clearModule = require('clear-module');
|
const clearModule = require('clear-module');
|
||||||
const {provisionCallHook} = require('./utils')
|
const {provisionCallHook} = require('./utils')
|
||||||
|
|
||||||
const sleepFor = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
||||||
|
|
||||||
process.on('unhandledRejection', (reason, p) => {
|
process.on('unhandledRejection', (reason, p) => {
|
||||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||||
});
|
});
|
||||||
@@ -49,7 +47,6 @@ test('\'dial-phone\'', async(t) => {
|
|||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||||
await sleepFor(1000);
|
|
||||||
|
|
||||||
let account_sid = '622f62e4-303a-49f2-bbe0-eb1e1714e37a';
|
let account_sid = '622f62e4-303a-49f2-bbe0-eb1e1714e37a';
|
||||||
let post = bent('http://127.0.0.1:3000/', 'POST', 'json', 201);
|
let post = bent('http://127.0.0.1:3000/', 'POST', 'json', 201);
|
||||||
@@ -87,7 +84,7 @@ test('\'dial-sip\'', async(t) => {
|
|||||||
try {
|
try {
|
||||||
await connect(srf);
|
await connect(srf);
|
||||||
// wait for fs connected to drachtio server.
|
// wait for fs connected to drachtio server.
|
||||||
await sleepFor(1000);
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
// GIVEN
|
// GIVEN
|
||||||
const from = "dial_sip";
|
const from = "dial_sip";
|
||||||
let verbs = [
|
let verbs = [
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ services:
|
|||||||
ipv4_address: 172.38.0.7
|
ipv4_address: 172.38.0.7
|
||||||
|
|
||||||
drachtio:
|
drachtio:
|
||||||
image: drachtio/drachtio-server:0.8.22
|
image: drachtio/drachtio-server:latest
|
||||||
restart: always
|
restart: always
|
||||||
command: drachtio --contact "sip:*;transport=udp" --mtu 4096 --address 0.0.0.0 --port 9022
|
command: drachtio --contact "sip:*;transport=udp" --mtu 4096 --address 0.0.0.0 --port 9022
|
||||||
ports:
|
ports:
|
||||||
@@ -57,7 +57,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
freeswitch:
|
freeswitch:
|
||||||
image: drachtio/drachtio-freeswitch-mrf:0.4.33
|
image: drachtio/drachtio-freeswitch-mrf:0.4.18
|
||||||
restart: always
|
restart: always
|
||||||
command: freeswitch --rtp-range-start 20000 --rtp-range-end 20100
|
command: freeswitch --rtp-range-start 20000 --rtp-range-end 20100
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ obj.sippUac = (file, bindAddress, from='sipp', to='16174000000', loop=1) => {
|
|||||||
'-cid_str', `%u-%p@%s-${idx++}`,
|
'-cid_str', `%u-%p@%s-${idx++}`,
|
||||||
'172.38.0.50',
|
'172.38.0.50',
|
||||||
'-key','from', from,
|
'-key','from', from,
|
||||||
'-key','to', to, '-trace_msg', '-trace_err'
|
'-key','to', to, '-trace_msg'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (bindAddress) args.splice(5, 0, '--ip', bindAddress);
|
if (bindAddress) args.splice(5, 0, '--ip', bindAddress);
|
||||||
|
|||||||
Reference in New Issue
Block a user