Skip to content

Commit

Permalink
Merge pull request #60 from twilio-labs/feature/start-stop-recording
Browse files Browse the repository at this point in the history
Feature/start stop recording
  • Loading branch information
timmydoza authored Jan 6, 2021
2 parents cbaeafc + dfffe25 commit 2070cec
Show file tree
Hide file tree
Showing 13 changed files with 466 additions and 146 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.7.0

### Enhancements

- This version adds a new endpoint which allows users to update the recording rules for a given room. See the [README](README.md#recording-rules) for more details.
- Upgraded @twilio/cli-core from 5.9.1 to 5.9.3
- Upgraded moment from 2.28.0 to 2.29.0
- Upgraded nanoid from 3.1.13 to 3.1.16
- Upgraded @twilio-labs/serverless-api from 4.0.2 to 4.0.3

## 0.6.0

### Enhancements
Expand Down
118 changes: 110 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,19 @@ A mobile and web collaboration application built with Twilio Programmable Video.
- [iOS App](https://github.com/twilio/twilio-video-app-ios)
- [Android App](https://github.com/twilio/twilio-video-app-android)

#### Token Server API Documentation
## Token Server API Documentation

The following section documents the application [token server](/src/video-token-server.js) used to provide [Programable Video access tokens](https://www.twilio.com/docs/video/tutorials/user-identity-access-tokens) to supported Twilio Video applications. The token server is deployed as a [Twilio Function](https://www.twilio.com/docs/runtime/functions).

| Method | URL |
| ------ | ------------------ |
| POST | [`/token`](#token) |

##### Authentication
### Authentication

The application token server requires an [authentication mechanism](#twilio-rtcappsvideodeploy---authentication-auth) to be specified when deploying. The following section documents each support authentication mechanism.
The application token server requires an [authentication mechanism](#twilio-rtcappsvideodeploy---authentication-auth) to be specified when deploying. The following section documents each supported authentication mechanism.

###### Passcode
#### Passcode

Each request is verified using a passcode generated at deploy time. Passcodes remain valid for one week. After the passcode expires, users can redeploy an application and a new passcode will be generated. The snippet below provides an example request body used by a supported application.

Expand All @@ -80,15 +80,15 @@ Each request is verified using a passcode generated at deploy time. Passcodes re
}
```

##### Token
### Token

Returns a Programmable Video Access token.

```shell
POST /token
```

###### Parameters
#### Parameters

| Name | Type | Description |
| --------------- | --------- | -------------------------------------------------------------------------------------- |
Expand All @@ -97,7 +97,7 @@ POST /token
| `room_name` | `string` | A room name that will be used to create a token scoped to connecting to only one room. |
| `create_room` | `boolean` | (default: `true`) When false, a room will not be created when a token is requested. |

###### Success Responses
#### Success Responses

<table>
<tr>
Expand All @@ -119,7 +119,7 @@ POST /token

</table>

###### Error Responses
#### Error Responses

<table>
<tr>
Expand Down Expand Up @@ -189,6 +189,108 @@ POST /token

</table>

### Recording Rules

Changes the Recording Rules for a given room SID.

```shell
POST /recordingrules
```

#### Parameters

| Name | Type | Description |
| ---------- | -------- | ------------------------------------------------------------------- |
| `passcode` | `string` | **Required**. The application passcode. |
| `room_sid` | `string` | **Required**. The SID of the room to change the recording rules of. |
| `rules` | `array` | **Required**. An array of recording rules to apply to the room. |

#### Success Responses

<table>
<tr>
<td> <b>Status</b> </td> <td> <b>Response</b> </td>
</tr>
<tr>
<td> 200 </td>
<td>

```json
{
"roomSid": "RM00000000000000000000000000000000",
"rules": [
{
"all": true,
"type": "exclude"
}
],
"dateCreated": "2020-11-18T02:58:20.000Z",
"dateUpdated": "2020-11-18T03:21:18.000Z"
}
```

</td>
</tr>

</table>

#### Error Responses

<table>
<tr>
<td> <b>Status</b> </td> <td> <b>Response</b> </td>
</tr>

<tr>
<td> 400 </td>
<td>

```json
{
"error": {
"message": "missing room_sid",
"explanation": "The room_sid parameter is missing."
}
}
```

</td>
</tr>

<tr>
<td> 400 </td>
<td>

```json
{
"error": {
"message": "missing rules",
"explanation": "The rules parameter is missing."
}
}
```

</td>
</tr>

<tr>
<td> 401 </td>
<td>

```json
{
"error": {
"message": "passcode incorrect",
"explanation": "The passcode used to validate application users is incorrect."
}
}
```

</td>
</tr>

</table>

## Commands

<!-- commands -->
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@twilio-labs/plugin-rtc",
"version": "0.6.1",
"version": "0.7.0",
"description": "A Twilio-CLI plugin for real-time communication apps",
"main": "index.js",
"publishConfig": {
Expand Down
69 changes: 43 additions & 26 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,33 @@ async function getAssets(folder) {

const indexHTML = assets.find(asset => asset.name.includes('index.html'));

assets.push({
...indexHTML,
path: '/',
name: '/',
});
assets.push({
...indexHTML,
path: '/login',
name: '/login',
});
const allAssets = assets.concat([
{
...indexHTML,
path: '/',
name: '/',
},
{
...indexHTML,
path: '/login',
name: '/login',
},
]);

return allAssets;
}

function getMiddleware() {
const authHandlerFn = fs.readFileSync(path.join(__dirname, './serverless/middleware/auth.js'));

return assets;
return [
{
name: 'auth-handler',
path: '/auth-handler.js',
content: authHandlerFn,
access: 'private',
},
];
}

async function findApp() {
Expand All @@ -80,7 +95,7 @@ async function getAppInfo() {
const assets = await appInstance.assets.list();

const functions = await appInstance.functions.list();
const tokenServerFunction = functions.find(fn => fn.friendlyName === 'token');
const tokenServerFunction = functions.find(fn => fn.friendlyName.includes('token'));

const passcodeVar = variables.find(v => v.key === 'API_PASSCODE');
const expiryVar = variables.find(v => v.key === 'API_PASSCODE_EXPIRY');
Expand All @@ -97,7 +112,7 @@ async function getAppInfo() {
expiry: moment(Number(expiry)).toString(),
sid: app.sid,
passcode: fullPasscode,
hasAssets: Boolean(assets.length),
hasWebAssets: Boolean(assets.find(asset => asset.friendlyName.includes('index.html'))),
roomType,
environmentSid: environment.sid,
functionSid: tokenServerFunction.sid,
Expand All @@ -112,7 +127,7 @@ async function displayAppInfo() {
return;
}

if (appInfo.hasAssets) {
if (appInfo.hasWebAssets) {
console.log(`Web App URL: ${appInfo.url}`);
}

Expand All @@ -130,6 +145,12 @@ async function displayAppInfo() {

async function deploy() {
const assets = this.flags['app-directory'] ? await getAssets(this.flags['app-directory']) : [];
const { functions } = await getListOfFunctionsAndAssets(__dirname, {
functionsFolderNames: ['serverless/functions'],
assetsFolderNames: [],
});

assets.push(...getMiddleware());

if (this.twilioClient.username === this.twilioClient.accountSid) {
// When twilioClient.username equals twilioClient.accountSid, it means that the user
Expand Down Expand Up @@ -158,8 +179,6 @@ TWILIO_API_SECRET = the secret for the API Key`);
const pin = getRandomInt(6);
const expiryTime = Date.now() + EXPIRY_PERIOD;

const fn = fs.readFileSync(path.join(__dirname, './video-token-server.js'));

cli.action.start('deploying app');

const deployOptions = {
Expand All @@ -170,17 +189,14 @@ TWILIO_API_SECRET = the secret for the API Key`);
API_PASSCODE_EXPIRY: expiryTime,
ROOM_TYPE: this.flags['room-type'],
},
pkgJson: {},
functionsEnv: 'dev',
functions: [
{
name: 'token',
path: '/token',
content: fn,
access: 'public',
pkgJson: {
dependencies: {
twilio: '^3.51.0',
},
],
assets: assets,
},
functionsEnv: 'dev',
functions,
assets,
};

if (this.appInfo && this.appInfo.sid) {
Expand All @@ -205,6 +221,7 @@ module.exports = {
displayAppInfo,
findApp,
getAssets,
getMiddleware,
getAppInfo,
getPasscode,
getRandomInt,
Expand Down
52 changes: 52 additions & 0 deletions src/serverless/functions/recordingrules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* global Twilio Runtime */
'use strict';

// We need to use a newer twilio client than the one provided by context.getTwilioClient(),
// so we require it here. The version is specified in helpers.js in the 'deployOptions' object.
// TODO: replace with context.getTwilioClient() when https://issues.corp.twilio.com/browse/RUN-3731 is complete
const twilio = require('twilio');

module.exports.handler = async (context, event, callback) => {
const authHandler = require(Runtime.getAssets()['/auth-handler.js'].path);
authHandler(context, event, callback);

let response = new Twilio.Response();
response.appendHeader('Content-Type', 'application/json');

const { room_sid, rules } = event;

if (typeof room_sid === 'undefined') {
response.setStatusCode(400);
response.setBody({
error: {
message: 'missing room_sid',
explanation: 'The room_sid parameter is missing.',
},
});
return callback(null, response);
}

if (typeof rules === 'undefined') {
response.setStatusCode(400);
response.setBody({
error: {
message: 'missing rules',
explanation: 'The rules parameter is missing.',
},
});
return callback(null, response);
}

const client = twilio(context.ACCOUNT_SID, context.AUTH_TOKEN);

try {
const recordingRulesResponse = await client.video.rooms(room_sid).recordingRules.update({ rules });
response.setStatusCode(200);
response.setBody(recordingRulesResponse);
} catch (err) {
response.setStatusCode(500);
response.setBody({ error: { message: err.message, code: err.code } });
}

callback(null, response);
};
Loading

0 comments on commit 2070cec

Please sign in to comment.