mirror of
https://github.com/jambonz/jambonz-node.git
synced 2026-01-25 02:08:15 +00:00
add support for calls.create to create a new call using REST
This commit is contained in:
25
README.md
25
README.md
@@ -32,7 +32,9 @@ app.listen(port, () => {
|
||||
[See here](https://docs.jambonz.org/jambonz/) for information on the available verbs you can use in a jambonz application, and for their associated properties.
|
||||
|
||||
### REST API calls
|
||||
To use the REST API you need to know your account sid (which you can see in the jambonz portal), and an api key (which you can generate in the jambonz portal). You generate a REST client as shown below.
|
||||
|
||||
#### Creating a client
|
||||
To use the REST API you need to know your account sid and api key (both of which you can view in the jambonz portal). You generate a REST client as shown below.
|
||||
```
|
||||
const client = require('@jambonz/node-client')(<my-account-sid>, <my-api-key>, {
|
||||
baseUrl: http://<my-jambonz-sbc>
|
||||
@@ -41,8 +43,26 @@ const client = require('@jambonz/node-client')(<my-account-sid>, <my-api-key>, {
|
||||
|
||||
All of the above parameters are required (account sid, api key, and baseUrl);
|
||||
|
||||
An example of using the client to perform live control to play a whisper prompt to the caller is shown below:
|
||||
#### Calls
|
||||
##### Creating a call
|
||||
```
|
||||
const sid = await client.calls.create({
|
||||
from: '16172223333',
|
||||
to: {
|
||||
type: 'phone',
|
||||
number: '15083084808'
|
||||
},
|
||||
call_hook: 'http://myurl.com/myapp-webhook',
|
||||
call_status_hook: 'http://myurl.com/call-status'
|
||||
});
|
||||
```
|
||||
[See here](https://docs.jambonz.org/rest/#create-a-call) for further details.
|
||||
|
||||
##### Updating a call
|
||||
To update a call in progress -- for example to mute/unmute, hangup the call etc -- you need to know the call sid. Typically you would get this from a webhook sent from an existing call event.
|
||||
|
||||
```
|
||||
// play a whisper prompt to one party on the call
|
||||
await client.calls.update(<my-call-sid>, {
|
||||
whisper: {
|
||||
verb: 'say',
|
||||
@@ -51,6 +71,7 @@ An example of using the client to perform live control to play a whisper prompt
|
||||
}
|
||||
});
|
||||
```
|
||||
[See here](https://docs.jambonz.org/rest/#updating-a-call) for further details.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const {validate, specs} = require('./utils');
|
||||
const {validate, specs} = require('../utils');
|
||||
|
||||
class WebhookResponse {
|
||||
constructor() {
|
||||
@@ -20,7 +20,7 @@ class WebhookResponse {
|
||||
|
||||
addVerb(verb, payload) {
|
||||
validate(verb, payload);
|
||||
this.payload.push({verb, ...payload});
|
||||
this.payload.push({verb: verb.replace('_', ':'), ...payload});
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const assert = require('assert');
|
||||
const {validateCallUpdate, validateCallCreate} = require('../utils');
|
||||
|
||||
class Calls {
|
||||
constructor(accountSid, apiKey, opts) {
|
||||
@@ -8,22 +8,32 @@ class Calls {
|
||||
['post', 'put', 'get', 'del'].forEach((m) => this[m] = opts[m]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new outbound call
|
||||
* @param {*} opts - see https://docs.jambonz.org/rest/#create-a-call for details
|
||||
*/
|
||||
async create(opts) {
|
||||
validateCallCreate(opts);
|
||||
const res = await this.post(`Accounts/${this.accountSid}/Calls`, opts);
|
||||
return res.sid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a call in progress. Available operations are:
|
||||
* - mute / unmute
|
||||
* - pause / resume a "listen" audio stream
|
||||
* - hang up the call
|
||||
* - play a whisper prompt to one party
|
||||
* - redirect the call to a new application
|
||||
* @param {*} callSid - identifies call leg to operate on
|
||||
* @param {*} opts - see https://docs.jambonz.org/rest/#updating-a-call for details
|
||||
*/
|
||||
async update(callSid, opts) {
|
||||
const {call_hook, call_status, listen_status, mute_status, whisper} = opts;
|
||||
|
||||
assert.ok(call_hook || call_status || listen_status || mute_status || whisper,
|
||||
`calls.update: invalid request ${JSON.stringify(opts)}`);
|
||||
|
||||
if (call_status) assert.ok(['completed', 'no-answer'].includes(call_status),
|
||||
`invalid call_status: ${call_status}, must be 'completed' or 'no-answer'`);
|
||||
|
||||
if (mute_status) assert.ok(['mute', 'unmute'].includes(mute_status),
|
||||
`invalid mute_status: ${mute_status}, must be 'mute' or 'unmute'`);
|
||||
|
||||
if (whisper) assert.ok(whisper.verb,
|
||||
`invalid whisper: ${JSON.stringify(whisper)}, must be a 'play' or 'say' verb`);
|
||||
|
||||
await this.post(`Accounts/${this.accountSid}/Calls/${callSid}`, opts);
|
||||
validateCallUpdate(opts);
|
||||
const res = await this.put(`Accounts/${this.accountSid}/Calls/${callSid}`, opts);
|
||||
if (res.statusCode === 404) throw new Error(`Calls.update: call_sid ${callSid} not found`);
|
||||
if (res.statusCode !== 204) throw new Error(`Calls.update: unexpected status code ${res.statusCode}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ class Jambonz {
|
||||
|
||||
const headers = {'Authorization': `Bearer ${apiKey}`};
|
||||
|
||||
const post = bent(baseUrl, 'POST', 'buffer', headers, 200, 201, 202);
|
||||
const put = bent(baseUrl, 'POST', 'buffer', headers, 204);
|
||||
const get = bent(baseUrl, 'GET', 'buffer', headers, 200);
|
||||
const del = bent(baseUrl, 'DELETE', 'buffer', headers, 204);
|
||||
const post = bent(baseUrl, 'POST', 'json', headers, 201);
|
||||
const put = bent(baseUrl, 'PUT', headers, 204);
|
||||
const get = bent(baseUrl, 'GET', 'json', headers, 200);
|
||||
const del = bent(baseUrl, 'DELETE', headers, 204);
|
||||
|
||||
this.calls = new Calls(accountSid, apiKey, {baseUrl, post, put, get, del});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const debug = require('debug')('jambonz:jambonz-node');
|
||||
const assert = require('assert');
|
||||
const specs = new Map(Object.entries(require('./specs.json')));
|
||||
const specs = new Map(Object.entries(require('./jambonz/specs.json')));
|
||||
|
||||
/**
|
||||
* copied from jambonz-feature-server/lib/tasks.js
|
||||
@@ -70,7 +70,45 @@ function validate(name, data) {
|
||||
* end of copy
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validate the payload for an updateCall request
|
||||
*/
|
||||
const validateCallUpdate = (opts) => {
|
||||
const {call_hook, call_status, listen_status, mute_status, whisper} = opts;
|
||||
|
||||
assert.ok(call_hook || call_status || listen_status || mute_status || whisper,
|
||||
`calls.update: invalid request ${JSON.stringify(opts)}`);
|
||||
|
||||
if (call_status) assert.ok(['completed', 'no-answer'].includes(call_status),
|
||||
`invalid call_status: ${call_status}, must be 'completed' or 'no-answer'`);
|
||||
|
||||
if (mute_status) assert.ok(['mute', 'unmute'].includes(mute_status),
|
||||
`invalid mute_status: ${mute_status}, must be 'mute' or 'unmute'`);
|
||||
|
||||
if (whisper) assert.ok(whisper.verb,
|
||||
`invalid whisper: ${JSON.stringify(whisper)}, must be a 'play' or 'say' verb`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate the payload for a createCall request
|
||||
*/
|
||||
const validateCallCreate = (opts) => {
|
||||
const {application_sid, call_hook, call_status_hook, from, to} = opts;
|
||||
|
||||
assert.ok(from && typeof from === 'string', 'calls.create: from property is required');
|
||||
assert.ok(to && typeof to === 'object', 'calls.create: to property is required');
|
||||
assert.ok(application_sid || call_hook, 'calls.create: application_sid or call_hook is required');
|
||||
assert.ok(call_status_hook || !call_hook, 'calls.create: call_status_hook is required when call_hook is used');
|
||||
|
||||
const hookUrl = typeof call_hook === 'object' ? call_hook.url : call_hook;
|
||||
if (hookUrl) assert.ok(/^https?:/.test(hookUrl), 'call_hook must be an absolute url');
|
||||
const hookStatusUrl = typeof call_status_hook === 'object' ? call_status_hook.url : call_status_hook;
|
||||
if (hookStatusUrl) assert.ok(/^https?:/.test(hookStatusUrl), 'call_status_hook must be an absolute url');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
validate,
|
||||
specs
|
||||
specs,
|
||||
validateCallUpdate,
|
||||
validateCallCreate
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@jambonz/node-client",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.5",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
||||
Reference in New Issue
Block a user