mirror of
https://github.com/jambonz/jambonz-feature-server.git
synced 2025-12-19 04:17:44 +00:00
feat: advanced queues (#362)
* feat: advanced queues * feat: advanced queues * feat: advanced queues * feat: advanced queues * update verb specification * add testcase * add testcase * add testcase * updte testcase * fixed * update queue * fix: fix waithook params * fix: fix waithook params * fix: performQueueWebhook with correct members length * fix merge conflict * debug log * debug listen test * debug listen test * debug listen test * debug listen test * debug listen test * debug listen issue * feat: add tts on account level --------- Co-authored-by: Dave Horton <daveh@beachdognet.com>
This commit is contained in:
@@ -16,6 +16,7 @@ class TaskDequeue extends Task {
|
||||
this.queueName = this.data.name;
|
||||
this.timeout = this.data.timeout || 0;
|
||||
this.beep = this.data.beep === true;
|
||||
this.callSid = this.data.callSid;
|
||||
|
||||
this.emitter = new Emitter();
|
||||
this.state = DequeueResults.Timeout;
|
||||
@@ -53,7 +54,7 @@ class TaskDequeue extends Task {
|
||||
}
|
||||
|
||||
_getMemberFromQueue(cs) {
|
||||
const {popFront} = cs.srf.locals.dbHelpers;
|
||||
const {retrieveFromSortedSet, retrieveByPatternSortedSet} = cs.srf.locals.dbHelpers;
|
||||
|
||||
return new Promise(async(resolve) => {
|
||||
let timer;
|
||||
@@ -70,7 +71,12 @@ class TaskDequeue extends Task {
|
||||
|
||||
do {
|
||||
try {
|
||||
const url = await popFront(this.queueName);
|
||||
let url;
|
||||
if (this.callSid) {
|
||||
url = await retrieveByPatternSortedSet(this.queueName, `*${this.callSid}`);
|
||||
} else {
|
||||
url = await retrieveFromSortedSet(this.queueName);
|
||||
}
|
||||
if (url) {
|
||||
found = true;
|
||||
clearTimeout(timer);
|
||||
@@ -78,7 +84,7 @@ class TaskDequeue extends Task {
|
||||
resolve(url);
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.debug({err}, 'TaskDequeue:_getMemberFromQueue error popFront');
|
||||
this.logger.debug({err}, 'TaskDequeue:_getMemberFromQueue error Sorted Set');
|
||||
}
|
||||
await sleepFor(5000);
|
||||
} while (!this.killed && !timedout && !found);
|
||||
|
||||
@@ -18,6 +18,7 @@ class TaskEnqueue extends Task {
|
||||
this.preconditions = TaskPreconditions.Endpoint;
|
||||
|
||||
this.queueName = this.data.name;
|
||||
this.priority = this.data.priority;
|
||||
this.waitHook = this.data.waitHook;
|
||||
|
||||
this.emitter = new Emitter();
|
||||
@@ -70,12 +71,22 @@ class TaskEnqueue extends Task {
|
||||
}
|
||||
|
||||
async _addToQueue(cs, dlg) {
|
||||
const {pushBack} = cs.srf.locals.dbHelpers;
|
||||
const {addToSortedSet, sortedSetLength} = cs.srf.locals.dbHelpers;
|
||||
const url = getUrl(cs);
|
||||
this.waitStartTime = Date.now();
|
||||
this.logger.debug({queue: this.queueName, url}, 'pushing url onto queue');
|
||||
const members = await pushBack(this.queueName, url);
|
||||
this.logger.info(`TaskEnqueue:_addToQueue: added to queue, length now ${members}`);
|
||||
if (this.priority < 0) {
|
||||
this.logger.warn(`priority ${this.priority} is invalid, need to be non-negative integer,
|
||||
999 will be used for priority`);
|
||||
}
|
||||
let members = await addToSortedSet(this.queueName, url, this.priority);
|
||||
if (members === 1) {
|
||||
this.logger.info('TaskEnqueue:_addToQueue: added to queue');
|
||||
} else {
|
||||
this.logger.info('TaskEnqueue:_addToQueue: failed to add to queue');
|
||||
}
|
||||
members = await sortedSetLength(this.queueName);
|
||||
|
||||
this.notifyUrl = url;
|
||||
|
||||
/* invoke account-level webhook for queue event notifications */
|
||||
@@ -90,9 +101,9 @@ class TaskEnqueue extends Task {
|
||||
}
|
||||
|
||||
async _removeFromQueue(cs) {
|
||||
const {removeFromList, lengthOfList} = cs.srf.locals.dbHelpers;
|
||||
await removeFromList(this.queueName, getUrl(cs));
|
||||
return await lengthOfList(this.queueName);
|
||||
const {retrieveByPatternSortedSet, sortedSetLength} = cs.srf.locals.dbHelpers;
|
||||
await retrieveByPatternSortedSet(this.queueName, `*${getUrl(cs)}`);
|
||||
return await sortedSetLength(this.queueName);
|
||||
}
|
||||
|
||||
async performAction() {
|
||||
@@ -279,8 +290,8 @@ class TaskEnqueue extends Task {
|
||||
this.emitter.emit('dequeue', opts);
|
||||
|
||||
try {
|
||||
const {lengthOfList} = cs.srf.locals.dbHelpers;
|
||||
const members = await lengthOfList(this.queueName);
|
||||
const {sortedSetLength} = cs.srf.locals.dbHelpers;
|
||||
const members = await sortedSetLength(this.queueName);
|
||||
this.dequeued = true;
|
||||
cs.performQueueWebhook({
|
||||
event: 'leave',
|
||||
@@ -301,7 +312,7 @@ class TaskEnqueue extends Task {
|
||||
}
|
||||
|
||||
async _playHook(cs, dlg, hook, allowed = [TaskName.Play, TaskName.Say, TaskName.Pause, TaskName.Leave]) {
|
||||
const {lengthOfList, getListPosition} = cs.srf.locals.dbHelpers;
|
||||
const {sortedSetLength, sortedSetPositionByPattern} = cs.srf.locals.dbHelpers;
|
||||
const b3 = this.getTracingPropagation();
|
||||
const httpHeaders = b3 && {b3};
|
||||
|
||||
@@ -313,9 +324,14 @@ class TaskEnqueue extends Task {
|
||||
queueTime: getElapsedTime(this.waitStartTime)
|
||||
};
|
||||
try {
|
||||
const queueSize = await lengthOfList(this.queueName);
|
||||
const queuePosition = await getListPosition(this.queueName, this.notifyUrl);
|
||||
Object.assign(params, {queueSize, queuePosition});
|
||||
const queueSize = await sortedSetLength(this.queueName);
|
||||
const queuePosition = await sortedSetPositionByPattern(this.queueName, `*${this.notifyUrl}`);
|
||||
Object.assign(params, {
|
||||
queueSize,
|
||||
queuePosition: queuePosition.length ? queuePosition[0] : 0,
|
||||
callSid: this.cs.callSid,
|
||||
callId: this.cs.callId,
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error({err}, `TaskEnqueue:_playHook error retrieving list info for queue ${this.queueName}`);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ function installSrfLocals(srf, logger) {
|
||||
password: JAMBONES_MYSQL_PASSWORD,
|
||||
database: JAMBONES_MYSQL_DATABASE,
|
||||
connectionLimit: JAMBONES_MYSQL_CONNECTION_LIMIT || 10
|
||||
}, logger, tracer);
|
||||
}, logger);
|
||||
const {
|
||||
client,
|
||||
updateCallStatus,
|
||||
@@ -167,6 +167,11 @@ function installSrfLocals(srf, logger) {
|
||||
removeFromList,
|
||||
getListPosition,
|
||||
lengthOfList,
|
||||
addToSortedSet,
|
||||
retrieveFromSortedSet,
|
||||
retrieveByPatternSortedSet,
|
||||
sortedSetLength,
|
||||
sortedSetPositionByPattern
|
||||
} = require('@jambonz/realtimedb-helpers')({
|
||||
host: JAMBONES_REDIS_HOST,
|
||||
port: JAMBONES_REDIS_PORT || 6379
|
||||
@@ -228,7 +233,12 @@ function installSrfLocals(srf, logger) {
|
||||
lengthOfList,
|
||||
getListPosition,
|
||||
getNuanceAccessToken,
|
||||
getIbmAccessToken
|
||||
getIbmAccessToken,
|
||||
addToSortedSet,
|
||||
retrieveFromSortedSet,
|
||||
retrieveByPatternSortedSet,
|
||||
sortedSetLength,
|
||||
sortedSetPositionByPattern
|
||||
},
|
||||
parentLogger: logger,
|
||||
getSBC,
|
||||
|
||||
126
package-lock.json
generated
126
package-lock.json
generated
@@ -9,9 +9,9 @@
|
||||
"version": "0.8.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.8.1",
|
||||
"@jambonz/db-helpers": "^0.9.0",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/realtimedb-helpers": "^0.7.2",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.1",
|
||||
"@jambonz/speech-utils": "^0.0.13",
|
||||
"@jambonz/stats-collector": "^0.1.8",
|
||||
"@jambonz/time-series": "^0.2.5",
|
||||
@@ -1560,6 +1560,11 @@
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ioredis/commands": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
@@ -1595,9 +1600,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/db-helpers": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.8.1.tgz",
|
||||
"integrity": "sha512-pc5TRAYnb89oyD5Ncy9Ik+v/tBqQcNOthbDwaX1OJyGRhPdolgs4YvOTpc0KpSqx7TDjKPS9n5MlqOFWgyDbTA==",
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.0.tgz",
|
||||
"integrity": "sha512-4fvwONj4jQNIHyG76WGdE7AuMt9vDl4sfHmHrY3PSgOh+kf2BCtBEYqoxyJ96/NH9OeUYkuXoM6fjSvpS7GYVw==",
|
||||
"dependencies": {
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.4",
|
||||
@@ -1629,13 +1634,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/realtimedb-helpers": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.7.2.tgz",
|
||||
"integrity": "sha512-hTlMw0pmwNHTAQVm3O1asHllRSwi5C+kLXjqZN4C8bdw08f6CY48qdX/aNHLlx5TWI1I5l0ReO745KrUFVPA6w==",
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.2.tgz",
|
||||
"integrity": "sha512-v7zlJ9D3gFIegqoLXdrIqDYMPsZbyZGW/Y8NBImmZ9mC6QrId9fVi5705/04g9SK870C/IadrGNiFPYVmn8JwA==",
|
||||
"dependencies": {
|
||||
"@jambonz/promisify-redis": "^0.0.6",
|
||||
"debug": "^4.3.4",
|
||||
"redis": "^3.1.2"
|
||||
"ioredis": "^5.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@jambonz/speech-utils": {
|
||||
@@ -3053,6 +3057,14 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -5028,6 +5040,29 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ioredis": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||
"dependencies": {
|
||||
"@ioredis/commands": "^1.1.1",
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"denque": "^2.1.0",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.isarguments": "^3.1.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.22.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/ioredis"
|
||||
}
|
||||
},
|
||||
"node_modules/ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
@@ -5862,6 +5897,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||
},
|
||||
"node_modules/lodash.flattendeep": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
|
||||
@@ -5873,6 +5913,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||
},
|
||||
"node_modules/lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||
},
|
||||
"node_modules/lodash.isempty": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
|
||||
@@ -7797,6 +7842,11 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
@@ -10025,6 +10075,11 @@
|
||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
||||
"dev": true
|
||||
},
|
||||
"@ioredis/commands": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||
},
|
||||
"@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
|
||||
@@ -10053,9 +10108,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@jambonz/db-helpers": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.8.1.tgz",
|
||||
"integrity": "sha512-pc5TRAYnb89oyD5Ncy9Ik+v/tBqQcNOthbDwaX1OJyGRhPdolgs4YvOTpc0KpSqx7TDjKPS9n5MlqOFWgyDbTA==",
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/db-helpers/-/db-helpers-0.9.0.tgz",
|
||||
"integrity": "sha512-4fvwONj4jQNIHyG76WGdE7AuMt9vDl4sfHmHrY3PSgOh+kf2BCtBEYqoxyJ96/NH9OeUYkuXoM6fjSvpS7GYVw==",
|
||||
"requires": {
|
||||
"cidr-matcher": "^2.1.1",
|
||||
"debug": "^4.3.4",
|
||||
@@ -10081,13 +10136,12 @@
|
||||
}
|
||||
},
|
||||
"@jambonz/realtimedb-helpers": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.7.2.tgz",
|
||||
"integrity": "sha512-hTlMw0pmwNHTAQVm3O1asHllRSwi5C+kLXjqZN4C8bdw08f6CY48qdX/aNHLlx5TWI1I5l0ReO745KrUFVPA6w==",
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/@jambonz/realtimedb-helpers/-/realtimedb-helpers-0.8.2.tgz",
|
||||
"integrity": "sha512-v7zlJ9D3gFIegqoLXdrIqDYMPsZbyZGW/Y8NBImmZ9mC6QrId9fVi5705/04g9SK870C/IadrGNiFPYVmn8JwA==",
|
||||
"requires": {
|
||||
"@jambonz/promisify-redis": "^0.0.6",
|
||||
"debug": "^4.3.4",
|
||||
"redis": "^3.1.2"
|
||||
"ioredis": "^5.3.2"
|
||||
}
|
||||
},
|
||||
"@jambonz/speech-utils": {
|
||||
@@ -11174,6 +11228,11 @@
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"cluster-key-slot": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@@ -12707,6 +12766,22 @@
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"ioredis": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz",
|
||||
"integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==",
|
||||
"requires": {
|
||||
"@ioredis/commands": "^1.1.1",
|
||||
"cluster-key-slot": "^1.1.0",
|
||||
"debug": "^4.3.4",
|
||||
"denque": "^2.1.0",
|
||||
"lodash.defaults": "^4.2.0",
|
||||
"lodash.isarguments": "^3.1.0",
|
||||
"redis-errors": "^1.2.0",
|
||||
"redis-parser": "^3.0.0",
|
||||
"standard-as-callback": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
|
||||
@@ -13336,6 +13411,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
|
||||
"integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
|
||||
},
|
||||
"lodash.defaults": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||
},
|
||||
"lodash.flattendeep": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
|
||||
@@ -13347,6 +13427,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="
|
||||
},
|
||||
"lodash.isarguments": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg=="
|
||||
},
|
||||
"lodash.isempty": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz",
|
||||
@@ -14797,6 +14882,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"standard-as-callback": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
|
||||
},
|
||||
"statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"jslint:fix": "eslint app.js tracer.js lib --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonz/db-helpers": "^0.8.1",
|
||||
"@jambonz/db-helpers": "^0.9.0",
|
||||
"@jambonz/http-health-check": "^0.0.1",
|
||||
"@jambonz/realtimedb-helpers": "^0.7.2",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.1",
|
||||
"@jambonz/speech-utils": "^0.0.13",
|
||||
"@jambonz/stats-collector": "^0.1.8",
|
||||
"@jambonz/time-series": "^0.2.5",
|
||||
|
||||
@@ -39,7 +39,7 @@ test('\'config: listen\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success-send-bye.xml', '172.38.0.10', from);
|
||||
@@ -86,7 +86,7 @@ test('\'config: listen - stop\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success-send-bye.xml', '172.38.0.10', from);
|
||||
|
||||
@@ -92,7 +92,7 @@ test('test create-call call-hook basic authentication', async(t) => {
|
||||
"text": "hello"
|
||||
}
|
||||
];
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
//THEN
|
||||
await p;
|
||||
|
||||
@@ -150,7 +150,7 @@ test('test create-call amd', async(t) => {
|
||||
"length": 7
|
||||
}
|
||||
];
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
//THEN
|
||||
await p;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,4 @@
|
||||
/* SQLEditor (MySQL (2))*/
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DROP TABLE IF EXISTS account_static_ips;
|
||||
@@ -16,6 +15,8 @@ DROP TABLE IF EXISTS call_routes;
|
||||
|
||||
DROP TABLE IF EXISTS dns_records;
|
||||
|
||||
DROP TABLE IF EXISTS lcr;
|
||||
|
||||
DROP TABLE IF EXISTS lcr_carrier_set_entry;
|
||||
|
||||
DROP TABLE IF EXISTS lcr_routes;
|
||||
@@ -52,6 +53,8 @@ DROP TABLE IF EXISTS smpp_addresses;
|
||||
|
||||
DROP TABLE IF EXISTS speech_credentials;
|
||||
|
||||
DROP TABLE IF EXISTS system_information;
|
||||
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
DROP TABLE IF EXISTS smpp_gateways;
|
||||
@@ -136,11 +139,23 @@ PRIMARY KEY (dns_record_sid)
|
||||
CREATE TABLE lcr_routes
|
||||
(
|
||||
lcr_route_sid CHAR(36),
|
||||
lcr_sid CHAR(36) NOT NULL,
|
||||
regex VARCHAR(32) NOT NULL COMMENT 'regex-based pattern match against dialed number, used for LCR routing of PSTN calls',
|
||||
description VARCHAR(1024),
|
||||
priority INTEGER NOT NULL UNIQUE COMMENT 'lower priority routes are attempted first',
|
||||
priority INTEGER NOT NULL COMMENT 'lower priority routes are attempted first',
|
||||
PRIMARY KEY (lcr_route_sid)
|
||||
) COMMENT='Least cost routing table';
|
||||
) COMMENT='An ordered list of digit patterns in an LCR table. The patterns are tested in sequence until one matches';
|
||||
|
||||
CREATE TABLE lcr
|
||||
(
|
||||
lcr_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
name VARCHAR(64) COMMENT 'User-assigned name for this LCR table',
|
||||
is_active BOOLEAN NOT NULL DEFAULT 1,
|
||||
default_carrier_set_entry_sid CHAR(36) COMMENT 'default carrier/route to use when no digit match based results are found.',
|
||||
service_provider_sid CHAR(36),
|
||||
account_sid CHAR(36),
|
||||
PRIMARY KEY (lcr_sid)
|
||||
) COMMENT='An LCR (least cost routing) table that is used by a service provider or account to make decisions about routing outbound calls when multiple carriers are available.';
|
||||
|
||||
CREATE TABLE password_settings
|
||||
(
|
||||
@@ -248,7 +263,10 @@ CREATE TABLE sbc_addresses
|
||||
sbc_address_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
ipv4 VARCHAR(255) NOT NULL,
|
||||
port INTEGER NOT NULL DEFAULT 5060,
|
||||
tls_port INTEGER,
|
||||
wss_port INTEGER,
|
||||
service_provider_sid CHAR(36),
|
||||
last_updated DATETIME,
|
||||
PRIMARY KEY (sbc_address_sid)
|
||||
);
|
||||
|
||||
@@ -307,6 +325,13 @@ created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (speech_credential_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE system_information
|
||||
(
|
||||
domain_name VARCHAR(255),
|
||||
sip_domain_name VARCHAR(255),
|
||||
monitoring_domain_name VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE users
|
||||
(
|
||||
user_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
@@ -357,6 +382,7 @@ smpp_inbound_password VARCHAR(64),
|
||||
register_from_user VARCHAR(128),
|
||||
register_from_domain VARCHAR(255),
|
||||
register_public_ip_in_contact BOOLEAN NOT NULL DEFAULT false,
|
||||
register_status VARCHAR(4096),
|
||||
PRIMARY KEY (voip_carrier_sid)
|
||||
) COMMENT='A Carrier or customer PBX that can send or receive calls';
|
||||
|
||||
@@ -403,6 +429,7 @@ inbound BOOLEAN NOT NULL COMMENT 'if true, whitelist this IP to allow inbound ca
|
||||
outbound BOOLEAN NOT NULL COMMENT 'if true, include in least-cost routing when placing calls to the PSTN',
|
||||
voip_carrier_sid CHAR(36) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT 1,
|
||||
protocol ENUM('udp','tcp','tls', 'tls/srtp') DEFAULT 'udp' COMMENT 'Outbound call protocol',
|
||||
PRIMARY KEY (sip_gateway_sid)
|
||||
) COMMENT='A whitelisted sip gateway used for origination/termination';
|
||||
|
||||
@@ -435,7 +462,7 @@ account_sid CHAR(36) COMMENT 'account that this application belongs to (if null,
|
||||
call_hook_sid CHAR(36) COMMENT 'webhook to call for inbound calls ',
|
||||
call_status_hook_sid CHAR(36) COMMENT 'webhook to call for call status events',
|
||||
messaging_hook_sid CHAR(36) COMMENT 'webhook to call for inbound SMS/MMS ',
|
||||
app_json VARCHAR(16384),
|
||||
app_json TEXT,
|
||||
speech_synthesis_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_synthesis_language VARCHAR(12) NOT NULL DEFAULT 'en-US',
|
||||
speech_synthesis_voice VARCHAR(64),
|
||||
@@ -502,6 +529,14 @@ ALTER TABLE call_routes ADD FOREIGN KEY application_sid_idxfk (application_sid)
|
||||
CREATE INDEX dns_record_sid_idx ON dns_records (dns_record_sid);
|
||||
ALTER TABLE dns_records ADD FOREIGN KEY account_sid_idxfk_4 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX lcr_sid_idx ON lcr_routes (lcr_sid);
|
||||
ALTER TABLE lcr_routes ADD FOREIGN KEY lcr_sid_idxfk (lcr_sid) REFERENCES lcr (lcr_sid);
|
||||
|
||||
CREATE INDEX lcr_sid_idx ON lcr (lcr_sid);
|
||||
ALTER TABLE lcr ADD FOREIGN KEY default_carrier_set_entry_sid_idxfk (default_carrier_set_entry_sid) REFERENCES lcr_carrier_set_entry (lcr_carrier_set_entry_sid);
|
||||
|
||||
CREATE INDEX service_provider_sid_idx ON lcr (service_provider_sid);
|
||||
CREATE INDEX account_sid_idx ON lcr (account_sid);
|
||||
CREATE INDEX permission_sid_idx ON permissions (permission_sid);
|
||||
CREATE INDEX predefined_carrier_sid_idx ON predefined_carriers (predefined_carrier_sid);
|
||||
CREATE INDEX predefined_sip_gateway_sid_idx ON predefined_sip_gateways (predefined_sip_gateway_sid);
|
||||
@@ -648,4 +683,4 @@ ALTER TABLE accounts ADD FOREIGN KEY device_calling_application_sid_idxfk (devic
|
||||
|
||||
ALTER TABLE accounts ADD FOREIGN KEY siprec_hook_sid_idxfk (siprec_hook_sid) REFERENCES applications (application_sid);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
|
||||
@@ -43,7 +43,7 @@ test('\'dial-phone\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||
@@ -102,7 +102,7 @@ test('\'dial-sip\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||
@@ -169,7 +169,7 @@ test('\'dial-user\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
const p = sippUac('uas-dial.xml', '172.38.0.10', undefined, undefined, 2);
|
||||
|
||||
@@ -50,7 +50,7 @@ test('\'gather\' test - google', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -86,7 +86,7 @@ test('\'gather\' test - default (google)', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -133,7 +133,7 @@ test('\'config\' test - reset to app defaults', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -173,7 +173,7 @@ test('\'gather\' test - microsoft', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -213,7 +213,7 @@ test('\'gather\' test - aws', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -256,7 +256,7 @@ test('\'gather\' test - deepgram', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -298,7 +298,7 @@ test('\'gather\' test - soniox', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
|
||||
@@ -14,5 +14,6 @@ require('./play-tests');
|
||||
require('./sip-refer-tests');
|
||||
require('./listen-tests');
|
||||
require('./config-test');
|
||||
require('./queue-test');
|
||||
require('./remove-test-db');
|
||||
require('./docker_stop');
|
||||
@@ -35,7 +35,7 @@ test('\'listen-success\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success-send-bye.xml', '172.38.0.10', from);
|
||||
@@ -69,13 +69,13 @@ test('\'listen-maxLength\'', async(t) => {
|
||||
{
|
||||
"verb": "listen",
|
||||
"url": `ws://172.38.0.60:3000/${from}`,
|
||||
"mixType" : "mixed",
|
||||
"mixType" : "stereo",
|
||||
"timeout": 2,
|
||||
"maxLength": 2
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
@@ -109,7 +109,7 @@ test('\'listen-pause-resume\'', async(t) => {
|
||||
}
|
||||
];
|
||||
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
|
||||
// THEN
|
||||
const p = sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
|
||||
@@ -33,7 +33,7 @@ test('\'play\' tests single link in plain text', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'play_single_link';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
@@ -62,7 +62,7 @@ test('\'play\' tests multi links in array', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'play_multi_links_in_array';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
@@ -100,8 +100,8 @@ test('\'play\' tests single link in conference', async(t) => {
|
||||
waitHook: `/customHook`
|
||||
}
|
||||
];
|
||||
provisionCustomHook(from, waitHookVerbs)
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCustomHook(from, waitHookVerbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-send-bye.xml', '172.38.0.10', from);
|
||||
@@ -141,8 +141,8 @@ test('\'play\' tests multi links in array in conference', async(t) => {
|
||||
waitHook: `/customHook`
|
||||
}
|
||||
];
|
||||
provisionCustomHook(from, waitHookVerbs)
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCustomHook(from, waitHookVerbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-send-bye.xml', '172.38.0.10', from);
|
||||
@@ -178,8 +178,8 @@ test('\'play\' tests with seekOffset and actionHook', async(t) => {
|
||||
const waitHookVerbs = [];
|
||||
|
||||
const from = 'play_action_hook';
|
||||
provisionCallHook(from, verbs)
|
||||
provisionCustomHook(from, waitHookVerbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
await provisionCustomHook(from, waitHookVerbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
@@ -218,7 +218,7 @@ test('\'play\' tests with earlymedia', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'play_early_media';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-invite-expect-183-cancel.xml', '172.38.0.10', from);
|
||||
|
||||
127
test/queue-test.js
Normal file
127
test/queue-test.js
Normal file
@@ -0,0 +1,127 @@
|
||||
const test = require('tape');
|
||||
const { sippUac } = require('./sipp')('test_fs');
|
||||
const clearModule = require('clear-module');
|
||||
const {provisionCallHook, provisionActionHook, provisionAnyHook} = require('./utils');
|
||||
const bent = require('bent');
|
||||
const getJSON = bent('json');
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
});
|
||||
|
||||
function connect(connectable) {
|
||||
return new Promise((resolve, reject) => {
|
||||
connectable.on('connect', () => {
|
||||
return resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const sleepFor = (ms) => new Promise((resolve) => setTimeout(() => resolve(), ms));
|
||||
|
||||
test('\'enqueue-dequeue\' tests', async(t) => {
|
||||
|
||||
clearModule.all();
|
||||
const {srf, disconnect} = require('../app');
|
||||
try {
|
||||
await connect(srf);
|
||||
// GIVEN
|
||||
const verbs = [
|
||||
{
|
||||
verb: 'enqueue',
|
||||
name: 'support',
|
||||
actionHook: '/actionHook'
|
||||
}
|
||||
];
|
||||
|
||||
const verbs2 = [
|
||||
{
|
||||
verb: 'dequeue',
|
||||
name: 'support'
|
||||
}
|
||||
];
|
||||
|
||||
const actionVerbs = [
|
||||
{
|
||||
verb: 'play',
|
||||
url: 'silence_stream://1000',
|
||||
earlyMedia: true
|
||||
}
|
||||
];
|
||||
|
||||
const from = 'enqueue_success';
|
||||
await provisionCallHook(from, verbs);
|
||||
await provisionActionHook(from, actionVerbs)
|
||||
|
||||
const from2 = 'dequeue_success';
|
||||
await provisionCallHook(from2, verbs2);
|
||||
|
||||
|
||||
// THEN
|
||||
const p1 = sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
|
||||
await sleepFor(1000);
|
||||
|
||||
const p2 = sippUac('uac-success-send-bye.xml', '172.38.0.11', from2);
|
||||
await Promise.all([p1, p2]);
|
||||
const obj = await getJSON(`http:127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
t.ok(obj.body.queue_result === 'bridged');
|
||||
t.pass('enqueue-dequeue: succeeds connect');
|
||||
disconnect();
|
||||
} catch (err) {
|
||||
console.log(`error received: ${err}`);
|
||||
disconnect();
|
||||
t.error(err);
|
||||
}
|
||||
});
|
||||
|
||||
test('\leave\' tests', async(t) => {
|
||||
|
||||
clearModule.all();
|
||||
const {srf, disconnect} = require('../app');
|
||||
try {
|
||||
await connect(srf);
|
||||
// GIVEN
|
||||
const verbs = [
|
||||
{
|
||||
verb: 'enqueue',
|
||||
name: 'support1',
|
||||
waitHook: '/anyHook/enqueue_success_leave',
|
||||
actionHook: '/actionHook'
|
||||
}
|
||||
];
|
||||
|
||||
const anyHookVerbs = [
|
||||
{
|
||||
verb: 'leave'
|
||||
}
|
||||
];
|
||||
|
||||
const actionVerbs = [
|
||||
{
|
||||
verb: 'play',
|
||||
url: 'silence_stream://1000',
|
||||
earlyMedia: true
|
||||
}
|
||||
];
|
||||
|
||||
const from = 'enqueue_success_leave';
|
||||
await provisionCallHook(from, verbs);
|
||||
await provisionAnyHook(from, anyHookVerbs);
|
||||
await provisionActionHook(from, actionVerbs)
|
||||
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
const obj = await getJSON(`http:127.0.0.1:3100/lastRequest/enqueue_success_leave`);
|
||||
t.ok(obj.body.queue_position === 0);
|
||||
const obj1 = await getJSON(`http:127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
t.ok(obj1.body.queue_result === 'leave');
|
||||
t.pass('enqueue-dequeue: succeeds connect');
|
||||
disconnect();
|
||||
} catch (err) {
|
||||
console.log(`error received: ${err}`);
|
||||
disconnect();
|
||||
t.error(err);
|
||||
}
|
||||
});
|
||||
@@ -31,7 +31,7 @@ test('\'say\' tests', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'say_test_success';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
@@ -71,7 +71,7 @@ test('\'config\' reset synthesizer tests', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'say_test_success';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
@@ -111,7 +111,7 @@ if (MICROSOFT_CUSTOM_API_KEY && MICROSOFT_DEPLOYMENT_ID && MICROSOFT_CUSTOM_REGI
|
||||
];
|
||||
|
||||
const from = 'say_test_success';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-success-received-bye.xml', '172.38.0.10', from);
|
||||
|
||||
@@ -41,8 +41,8 @@ test('\'refer\' tests w/202 and NOTIFY', {timeout: 25000}, async(t) => {
|
||||
const noVerbs = [];
|
||||
|
||||
const from = 'refer_with_notify';
|
||||
provisionCallHook(from, verbs);
|
||||
provisionActionHook(from, noVerbs)
|
||||
await provisionCallHook(from, verbs);
|
||||
await provisionActionHook(from, noVerbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-refer-with-notify.xml', '172.38.0.10', from);
|
||||
@@ -81,8 +81,8 @@ test('\'refer\' tests w/202 but no NOTIFY', {timeout: 25000}, async(t) => {
|
||||
const noVerbs = [];
|
||||
|
||||
const from = 'refer_no_notify';
|
||||
provisionCallHook(from, verbs);
|
||||
provisionActionHook(from, noVerbs)
|
||||
await provisionCallHook(from, verbs);
|
||||
await provisionActionHook(from, noVerbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-refer-no-notify.xml', '172.38.0.10', from);
|
||||
|
||||
@@ -40,7 +40,7 @@ test('sending SIP in-dialog requests tests', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "sip_indialog_test";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-send-info-during-dialog.xml', '172.38.0.10', from);
|
||||
const obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
|
||||
@@ -48,7 +48,7 @@ test('\'transcribe\' test - google', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -85,7 +85,7 @@ test('\'transcribe\' test - microsoft', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -122,7 +122,7 @@ test('\'transcribe\' test - aws', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -162,7 +162,7 @@ test('\'transcribe\' test - deepgram', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
@@ -202,7 +202,7 @@ test('\'transcribe\' test - soniox', async(t) => {
|
||||
}
|
||||
];
|
||||
let from = "gather_success";
|
||||
provisionCallHook(from, verbs);
|
||||
await provisionCallHook(from, verbs);
|
||||
// THEN
|
||||
await sippUac('uac-gather-account-creds-success.xml', '172.38.0.10', from);
|
||||
let obj = await getJSON(`http://127.0.0.1:3100/lastRequest/${from}_actionHook`);
|
||||
|
||||
@@ -6,31 +6,40 @@ const bent = require('bent');
|
||||
* The function help testcase to register desired jambonz json response for an application call
|
||||
* When a call has From number match the registered hook event, the desired jambonz json will be responded.
|
||||
*/
|
||||
const provisionCallHook = (from, verbs) => {
|
||||
const provisionCallHook = async (from, verbs) => {
|
||||
const mapping = {
|
||||
from,
|
||||
data: JSON.stringify(verbs)
|
||||
};
|
||||
const post = bent('http://127.0.0.1:3100', 'POST', 'string', 200);
|
||||
post('/appMapping', mapping);
|
||||
await post('/appMapping', mapping);
|
||||
}
|
||||
|
||||
const provisionCustomHook = (from, verbs) => {
|
||||
const provisionCustomHook = async(from, verbs) => {
|
||||
const mapping = {
|
||||
from,
|
||||
data: JSON.stringify(verbs)
|
||||
};
|
||||
const post = bent('http://127.0.0.1:3100', 'POST', 'string', 200);
|
||||
post(`/customHookMapping`, mapping);
|
||||
await post(`/customHookMapping`, mapping);
|
||||
}
|
||||
|
||||
const provisionActionHook = (from, verbs) => {
|
||||
const provisionActionHook = async(from, verbs) => {
|
||||
const mapping = {
|
||||
from,
|
||||
data: JSON.stringify(verbs)
|
||||
};
|
||||
const post = bent('http://127.0.0.1:3100', 'POST', 'string', 200);
|
||||
post(`/actionHook`, mapping);
|
||||
await post(`/actionHook`, mapping);
|
||||
}
|
||||
|
||||
module.exports = { provisionCallHook, provisionCustomHook, provisionActionHook}
|
||||
const provisionAnyHook = async(key, verbs) => {
|
||||
const mapping = {
|
||||
key,
|
||||
data: JSON.stringify(verbs)
|
||||
};
|
||||
const post = bent('http://127.0.0.1:3100', 'POST', 'string', 200);
|
||||
await post(`/anyHookMapping`, mapping);
|
||||
}
|
||||
|
||||
module.exports = { provisionCallHook, provisionCustomHook, provisionActionHook, provisionAnyHook}
|
||||
|
||||
@@ -2,6 +2,7 @@ const express = require('express');
|
||||
const app = express();
|
||||
const Websocket = require('ws');
|
||||
const listenPort = process.env.HTTP_PORT || 3000;
|
||||
const any_hook_json_mapping = new Map();
|
||||
let json_mapping = new Map();
|
||||
let hook_mapping = new Map();
|
||||
let ws_packet_count = new Map();
|
||||
@@ -61,7 +62,7 @@ app.all('/', (req, res) => {
|
||||
console.log(req.body, 'POST /');
|
||||
const key = req.body.from
|
||||
addRequestToMap(key, req, hook_mapping);
|
||||
return getJsonFromMap(key, req, res);
|
||||
return getJsonFromMap(json_mapping, key, req, res);
|
||||
});
|
||||
|
||||
app.post('/appMapping', (req, res) => {
|
||||
@@ -106,7 +107,7 @@ app.post('/actionHook', (req, res) => {
|
||||
app.all('/customHook', (req, res) => {
|
||||
let key = `${req.body.from}_customHook`;;
|
||||
console.log(req.body, `POST /customHook`);
|
||||
return getJsonFromMap(key, req, res);
|
||||
return getJsonFromMap(json_mapping, key, req, res);
|
||||
});
|
||||
|
||||
app.post('/customHookMapping', (req, res) => {
|
||||
@@ -116,6 +117,23 @@ app.post('/customHookMapping', (req, res) => {
|
||||
return res.sendStatus(200);
|
||||
});
|
||||
|
||||
/**
|
||||
* Any Hook
|
||||
*/
|
||||
|
||||
app.all('/anyHook/:key', (req, res) => {
|
||||
let key = req.params.key;
|
||||
console.log(req.body, `POST /anyHook/${key}`);
|
||||
return getJsonFromMap(any_hook_json_mapping, key, req, res);
|
||||
});
|
||||
|
||||
app.post('/anyHookMapping', (req, res) => {
|
||||
let key = req.body.key;
|
||||
console.log(req.body, `POST /anyHookMapping/${key}`);
|
||||
any_hook_json_mapping.set(key, req.body.data);
|
||||
return res.sendStatus(200);
|
||||
});
|
||||
|
||||
// Fetch Requests
|
||||
app.get('/requests/:key', (req, res) => {
|
||||
let key = req.params.key;
|
||||
@@ -162,9 +180,9 @@ app.get('/ws_metadata/:key', (req, res) => {
|
||||
* private function
|
||||
*/
|
||||
|
||||
function getJsonFromMap(key, req, res) {
|
||||
if (!json_mapping.has(key)) return res.sendStatus(404);
|
||||
const retData = JSON.parse(json_mapping.get(key));
|
||||
function getJsonFromMap(map, key, req, res) {
|
||||
if (!map.has(key)) return res.sendStatus(404);
|
||||
const retData = JSON.parse(map.get(key));
|
||||
console.log(retData, ` Response to ${req.method} ${req.url}`);
|
||||
addRequestToMap(key, req, hook_mapping);
|
||||
return res.json(retData);
|
||||
|
||||
@@ -45,7 +45,7 @@ test('basic webhook tests', async(t) => {
|
||||
];
|
||||
|
||||
const from = 'sip_decline_test_success';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
await sippUac('uac-expect-603.xml', '172.38.0.10', from);
|
||||
t.pass('webhook successfully declines call');
|
||||
@@ -73,7 +73,7 @@ test('invalid jambonz json create alert tests', async(t) => {
|
||||
};
|
||||
|
||||
const from = 'invalid_json_create_alert';
|
||||
provisionCallHook(from, verbs)
|
||||
await provisionCallHook(from, verbs)
|
||||
|
||||
// THEN
|
||||
await sippUac('uac-invite-expect-480.xml', '172.38.0.10', from);
|
||||
|
||||
Reference in New Issue
Block a user