mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-20 16:50:39 +00:00
add tag task and varioius cleanup
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"SipNotify": "sip:notify",
|
||||
"SipRedirect": "sip:redirect",
|
||||
"Say": "say",
|
||||
"Tag": "tag",
|
||||
"Transcribe": "transcribe"
|
||||
},
|
||||
"CallStatus": {
|
||||
|
||||
@@ -1,23 +1,36 @@
|
||||
const request = require('request');
|
||||
require('request-debug')(request);
|
||||
const retrieveApp = require('./retrieve-app');
|
||||
|
||||
function hooks(logger, callAttributes) {
|
||||
function actionHook(url, method, auth, opts, expectResponse = true) {
|
||||
const params = Object.assign({}, callAttributes, opts);
|
||||
let basicauth, qs, body;
|
||||
if (auth && typeof auth === 'object' && Object.keys(auth) === 2) basicauth = auth;
|
||||
if ('GET' === method.toUpperCase()) qs = params;
|
||||
else body = params;
|
||||
const obj = {url, method, auth: basicauth, json: expectResponse || !!body, qs, body};
|
||||
logger.debug({opts: obj}, 'actionHook');
|
||||
function hooks(logger, callInfo) {
|
||||
function actionHook(hook, obj, expectResponse = true) {
|
||||
const method = hook.method.toUpperCase();
|
||||
const auth = (hook.username && hook.password) ?
|
||||
{username: hook.username, password: hook.password} :
|
||||
null;
|
||||
|
||||
const data = Object.assign({}, obj, callInfo);
|
||||
if ('GET' === method) {
|
||||
// remove customer data - only for POSTs since it might be quite complex
|
||||
delete data.customerData;
|
||||
}
|
||||
const opts = {
|
||||
url: hook.url,
|
||||
method,
|
||||
json: 'POST' === method || expectResponse
|
||||
};
|
||||
if (auth) obj.auth = auth;
|
||||
if ('POST' === method) obj.body = data;
|
||||
else obj.qs = data;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(obj, (err, response, body) => {
|
||||
request(opts, (err, response, body) => {
|
||||
if (err) {
|
||||
logger.info(`actionHook error ${method} ${url}: ${err.message}`);
|
||||
logger.info(`actionHook error ${method} ${hook.url}: ${err.message}`);
|
||||
return reject(err);
|
||||
}
|
||||
if (body && expectResponse) {
|
||||
logger.debug(body, `actionHook response ${method} ${url}`);
|
||||
logger.debug(body, `actionHook response ${method} ${hook.url}`);
|
||||
return resolve(retrieveApp(logger, body));
|
||||
}
|
||||
resolve(body);
|
||||
@@ -25,7 +38,7 @@ function hooks(logger, callAttributes) {
|
||||
});
|
||||
}
|
||||
|
||||
function notifyHook(url, method, auth, opts) {
|
||||
function notifyHook(url, method, auth, opts = {}) {
|
||||
return actionHook(url, method, auth, opts, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
const Emitter = require('events');
|
||||
const {CallStatus} = require('./constants');
|
||||
const uuidv4 = require('uuid/v4');
|
||||
const SipError = require('drachtio-srf').SipError;
|
||||
const {TaskPreconditions} = require('../utils/constants');
|
||||
const {TaskPreconditions, CallDirection} = require('../utils/constants');
|
||||
const CallInfo = require('../session/call-info');
|
||||
const assert = require('assert');
|
||||
const ConfirmCallSession = require('../session/confirm-call-session');
|
||||
const hooks = require('./notifiers');
|
||||
const moment = require('moment');
|
||||
const parseUrl = require('parse-url');
|
||||
|
||||
class SingleDialer extends Emitter {
|
||||
constructor({logger, sbcAddress, target, opts, application, callInfo}) {
|
||||
@@ -18,13 +19,21 @@ class SingleDialer extends Emitter {
|
||||
this.sbcAddress = sbcAddress;
|
||||
this.opts = opts;
|
||||
this.application = application;
|
||||
this.url = opts.url;
|
||||
this.method = opts.method;
|
||||
this.url = target.url;
|
||||
this.method = target.method;
|
||||
|
||||
this._callSid = uuidv4();
|
||||
this.bindings = logger.bindings();
|
||||
this.callInfo = Object.assign({}, callInfo, {callSid: this._callSid});
|
||||
this.sipStatus;
|
||||
|
||||
this.parentCallInfo = callInfo;
|
||||
/*
|
||||
this.callInfo = Object.assign({}, callInfo, {
|
||||
callSid: this._callSid,
|
||||
parentCallSid: callInfo.callSid,
|
||||
direction: CallDirection.Outbound,
|
||||
callStatus: CallStatus.Trying,
|
||||
sipStatus: 100
|
||||
});
|
||||
*/
|
||||
this.callGone = false;
|
||||
|
||||
this.on('callStatusChange', this._notifyCallStatusChange.bind(this));
|
||||
@@ -86,18 +95,21 @@ class SingleDialer extends Emitter {
|
||||
* (a) create a logger for this call
|
||||
* (b) augment this.callInfo with additional call info
|
||||
*/
|
||||
this.callInfo = new CallInfo({
|
||||
direction: CallDirection.Outbound,
|
||||
parentCallInfo: this.parentCallInfo,
|
||||
req
|
||||
});
|
||||
this.logger = srf.locals.parentLogger.child({
|
||||
callSid: this.callSid,
|
||||
parentCallSid: this.bindings.callSid,
|
||||
callId: req.get('Call-ID')
|
||||
callSid: this.callInfo.callSid,
|
||||
parentCallSid: this.parentCallInfo.callSid,
|
||||
callId: this.callInfo.callId
|
||||
});
|
||||
this.inviteInProgress = req;
|
||||
const status = {callStatus: CallStatus.Trying, sipStatus: 100};
|
||||
Object.assign(this.callInfo, {callId: req.get('Call-ID'), from: req.callingNumber, to});
|
||||
const {actionHook, notifyHook} = hooks(this.logger, this.callInfo);
|
||||
this.actionHook = actionHook;
|
||||
this.notifyHook = notifyHook;
|
||||
this.emit('callStatusChange', status);
|
||||
this.emit('callStatusChange', {callStatus: CallStatus.Trying, sipStatus: 100});
|
||||
},
|
||||
cbProvisional: (prov) => {
|
||||
const status = {sipStatus: prov.status};
|
||||
@@ -168,7 +180,24 @@ class SingleDialer extends Emitter {
|
||||
async _executeApp(url) {
|
||||
this.logger.debug(`SingleDialer:_executeApp: executing ${url} after connect`);
|
||||
try {
|
||||
const tasks = await this.actionHook(this.url, this.method);
|
||||
let auth;
|
||||
const app = Object.assign({}, this.application);
|
||||
if (url.startsWith('/')) {
|
||||
const savedUrl = url;
|
||||
const or = app.originalRequest;
|
||||
url = `${or.baseUrl}${url}`;
|
||||
auth = or.auth;
|
||||
this.logger.debug({originalUrl: savedUrl, normalizedUrl: url}, 'SingleDialer:_executeApp normalized url');
|
||||
}
|
||||
else {
|
||||
const u = parseUrl(url);
|
||||
const myPort = u.port ? `:${u.port}` : '';
|
||||
app.originalRequest = {
|
||||
baseUrl: `${u.protocol}://${u.resource}${myPort}`
|
||||
};
|
||||
}
|
||||
|
||||
const tasks = await this.actionHook(url, this.method, auth);
|
||||
const allowedTasks = tasks.filter((task) => {
|
||||
return [
|
||||
TaskPreconditions.StableCall,
|
||||
@@ -180,7 +209,7 @@ class SingleDialer extends Emitter {
|
||||
}
|
||||
|
||||
this.logger.debug(`SingleDialer:_executeApp: executing ${tasks.length} tasks`);
|
||||
const cs = new ConfirmCallSession(this.logger, this.application, this.dlg, this.ep, tasks);
|
||||
const cs = new ConfirmCallSession({logger: this.logger, application: app, dlg: this.dlg, ep: this.ep, tasks});
|
||||
await cs.exec();
|
||||
this.emit(this.dlg.connected ? 'accept' : 'decline');
|
||||
} catch (err) {
|
||||
@@ -190,18 +219,13 @@ class SingleDialer extends Emitter {
|
||||
}
|
||||
}
|
||||
|
||||
_notifyCallStatusChange(callStatus) {
|
||||
_notifyCallStatusChange({callStatus, sipStatus}) {
|
||||
this.logger.debug(`SingleDialer:_notifyCallStatusChange: ${callStatus} ${sipStatus}`);
|
||||
this.callInfo.updateStatus(callStatus, sipStatus);
|
||||
try {
|
||||
const auth = {};
|
||||
if (this.application.hook_basic_auth_user && this.application.hook_basic_auth_password) {
|
||||
Object.assign(auth, {user: this.application.hook_basic_auth_user, password: this.hook_basic_auth_password});
|
||||
}
|
||||
this.notifyHook(this.application.call_status_hook,
|
||||
this.application.hook_http_method,
|
||||
auth,
|
||||
callStatus);
|
||||
this.notifyHook(this.application.call_status_hook);
|
||||
} catch (err) {
|
||||
this.logger.info(err, `SingleDialer:_notifyCallStatusChange: error sending ${JSON.stringify(callStatus)}`);
|
||||
this.logger.info(err, `SingleDialer:_notifyCallStatusChange error sending ${callStatus} ${sipStatus}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,25 @@ const makeTask = require('../tasks/make_task');
|
||||
const normalizeJamones = require('./normalize-jamones');
|
||||
|
||||
|
||||
function retrieveUrl(logger, url, method, auth, qs, body) {
|
||||
logger.debug(`body: ${body}`);
|
||||
const opts = {url, method, auth, qs, json: true};
|
||||
if (body) {
|
||||
logger.debug('adding body');
|
||||
Object.assign(opts, {body});
|
||||
}
|
||||
function retrieveUrl(logger, url, method, auth, obj) {
|
||||
const opts = {url, method, auth, json: true};
|
||||
if (method === 'GET') Object.assign(opts, {qs: obj});
|
||||
else Object.assign(opts, {body: obj});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request(opts, (err, response, body) => {
|
||||
if (err) throw err;
|
||||
if (body) logger.debug({body}, 'retrieveUrl: customer returned an application');
|
||||
resolve(body);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function retrieveApp(logger, url, method, auth, qs, body) {
|
||||
async function retrieveApp(logger, url, method, auth, obj) {
|
||||
let json;
|
||||
|
||||
if (typeof url === 'object') json = url;
|
||||
else json = await retrieveUrl(logger, url, method, auth, qs, body);
|
||||
else json = await retrieveUrl(logger, url, method, auth, obj);
|
||||
return normalizeJamones(logger, json).map((tdata) => makeTask(logger, tdata));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user