fr
Divers

Comment transférer automatiquement des enregistrements Twilio à S3

Twilio offre la possibilité d’enregistrer automatiquement les appels, mais les enregistrements peuvent s’accumuler rapidement. Dans cet article, je décris comment créer une fonction AWS lambda qui transfère automatiquement les enregistrements vers S3 à des fins d’archivage.

1) Créer un rôle IAM pour la fonction Lambda

La première étape consiste à créer un rôle que la fonction lambda peut assumer afin d’écrire dans le dossier S3 approprié. Le rôle doit faire confiance à AWS Service > Lambda,  et doit permettre s3:PutObject.

Trust Policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "Service": "lambda.amazonaws.com" },
      "Action": "sts:AssumeRole"
    }
  ]
}

Permission Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow"
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<BUCKET_NAME>/<PREFIX>/*",
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

2) Créer une fonction Lambda pour transférer les enregistrements

La deuxième étape consiste à créer une fonction Lambda utilisant Nodejs 12.x. Cette fonction lambda doit utiliser le rôle de l’étape 1 comme son rôle d’exécution. Le contenu de la fonction lambda doit être mis dans le fichier index.js. Vous devez ajuster les variables ACCOUNT_SIDAUTH_TOKEN pour mettre vos informations de Twilio, ainsi que S3_BUCKET et S3_PREFIX pour indiquer où sauvegarder les enregistrements.

'use strict';
const axios = require('axios');
const AWS = require('aws-sdk');
const S3UploadStream = require('s3-upload-stream');
const Twilio = require('twilio');

const ACCOUNT_SID = "AC2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const AUTH_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const S3_BUCKET = "BUCKET-NAME";
const S3_PREFIX = "Recordings";

function add_leading_zero(number) {
    let n = number.toString();
    if (n.length < 2) { n = '0' + n; }
    return n;
}

function get_download_url(recording) {
    const apiVersion = recording.apiVersion;
    const recordingSID = recording.sid;
    return `https://api.twilio.com/${apiVersion}/Accounts/${ACCOUNT_SID}/Recordings/${recordingSID}.mp3`
}

function get_upload_path(recording, from_number, to_number) {
    const recordingDate = new Date(recording.dateCreated);
    const year = recordingDate.getFullYear();
    const month = add_leading_zero(recordingDate.getMonth() + 1);
    const day = add_leading_zero(recordingDate.getDate());
    const hour = add_leading_zero(recordingDate.getHours());
    const minute = add_leading_zero(recordingDate.getMinutes());
    const second = add_leading_zero(recordingDate.getSeconds());
    const duration = add_leading_zero(recording.duration);
    return `${S3_PREFIX}/${year}/${month}/${year}.${month}.${day}-${hour}.${minute}.${second}_${from_number}_${to_number}_${duration}s.mp3`
}

async function transfer_recording(download_url, upload_stream) {
    const response = await axios({method: 'GET', url: download_url, responseType: 'stream'});
    response.data.pipe(upload_stream);
    return new Promise((resolve, reject) => {
        upload_stream.on('uploaded', resolve)
        upload_stream.on('error', reject)
    });
}

module.exports.handler = async function(event, context, callback) {
    const client = Twilio(ACCOUNT_SID, AUTH_TOKEN);

    // Retrieving and deleting all recordings
    const recordings = await client.recordings.list();
    for (const recording of recordings) {
        if (recording.status !== "completed") { continue; }

        // Getting the upload and download paths
        const call = await client.calls(recording.callSid).fetch();
        const download_url = get_download_url(recording);
        const upload_path = get_upload_path(recording, call.from, call.to);
        let s3Stream = S3UploadStream(new AWS.S3());

        // Alternatively, one could download a ".wav" by using ".wav" in the in the download_url and a ContentType of "audio/x-wav"
        let upload_stream = s3Stream.upload({Bucket: S3_BUCKET, Key: upload_path, ContentType: 'audio/mpeg'});

        // Transferring to S3
        console.log(`Transferring ${recording.callSid} to ${upload_path}`);
        await transfer_recording(download_url, upload_stream);

        // Deleting recording
        await client.recordings(recording.sid).remove();
    }
    callback();
};

Parce que la fonction lambda dépend d’autres packages npm, nous devons installer ces packages localement, puis télécharger une archive zip sur Lambda. Dans un dossier vide sur votre ordinateur, créez le fichier index.js, puis créez un package npm et installez les dépendances en utilisant:

$ npm init
$ npm install aws-sdk axios s3-upload-stream twilio

Le répertoire résultant devrait ressembler à ceci:

You can then create a zip archive from these files, and create your lambda function by uploading a zip file.

J’utilise 512 Mo de mémoire et un délai d’attente de 5 minutes, mais vous pouvez l’ajuster en fonction de vos besoins.

3) Déclencher automatiquement à l’aide des événements Cloudwatch

La dernière étape consiste à ajouter un déclencheur à la fonction. Il est possible de déclencher la fonction une fois par heure en cliquant sur Add Trigger sur la page lambda et en entrant les paramètres suivants:

À chaque appel, la fonction lambda doit transférer les enregistrements Twilio vers le dossier S3 spécifié, puis supprimer l’enregistrement de Twilio. Le dossier s3 devrait contenir des fichiers comme ceci:

Félicitations. Vous disposez désormais d’une fonction AWS Lambda qui transfère automatiquement les enregistrements de Twilio vers S3. Vous pouvez maintenant définir des politiques de cycle de vie pour faire la transition et expirer vos enregistrements.