Le Blog Amazon Web Services

Développer une extension Twitch avec un service AWS Serverless

Qu’ils diffusent le dernier morceau de leur groupe ou codent en direct une application web, la communauté des diffuseurs crée et partage du contenu regardé par des spectateurs du monde entier. La communauté des développeurs révolutionne cette expérience de visionnage avec la création de fonctionnalités interactives permettant aux spectateurs d’interagir directement avec leurs diffuseurs favoris au travers d’extensions Twitch.

Ces extensions permettent la création d’applications interagissant avec le flux, en se superposant au lecteur vidéo, en ajoutant un panneau sur la page de la chaîne, ou sous la forme de conversations; comme par exemple une carte des points chauds, la superposition de données en temps réel, des mini-jeux, des demandes de musiques, ou des classements.

De la même manière que les développeurs ont transformé nos interactions avec nos téléphones en créant des applications qui améliorent l’expérience et les fonctionnalités, les extensions Twitch transforment notre manière d’interagir avec ces expériences vidéo. Dans les premiers mois de 2019 uniquement, ce sont plus de 1,8 milliards d’interactions au travers des extensions qui ont générées, et plus de 67% de partenaires et diffuseurs affiliés sur Twitch ont installé une extension.

La création d’une extension Twitch peut apparaître comme une tâche décourageante, mais nous sommes là pour vous aider au long de ce périple. Nicki Klein, Senior Technical Evangelist chez AWS et Matt Auerbach, Developer Advocate chez Twitch ont enregistré une série en 8 épisodes de vidéo pour vous accompagner dans le développement d’une extension Twitch au sein des ressources Twitch Dev.

Ce billet reprend les étapes que Matt et Nicki ont suivies pour construire leur extension Twitch en utilisant AWS pour tous les services nécessaires au développement. Il explique comment construire un service pour les extensions EBS (ou extension Backend Service) à l’aide d’AWS Lambda, Amazon DynamoDB, et Amazon API Gateway, et comment s’assurer que votre service et ses clients communiquent de manière correcte et sécurisée afin de soumettre cette extension à l’approbation de Twitch.

Les extensions Twitch se décomposent en deux parties: la partie cliente sous forme de panneau ou de surimpression sur le site, et un service optionnel EBS. L’extension Twitch ne requiert pas un fonctionnement en continu, puisque les flux ne sont pas diffusés tout le temps, l’extension n’est pas constamment utilisée, ou alors le client Twitch effectue tout le travail, la meilleure option pour un EBS dans ce cas, est une solution serverless. Suivant les extensions, l’architecture sera à définir et il faudra s’assurer si le serverless convient ou pas.

Pré-requis

Pour suivre ces étapes, vous aurez besoin d’un compte AWS, d’un compte Developer Twitch ainsi que savoir développer des applications web avec NodeJS et Javascript.

Démarrons par le design et la planification de l’extension

Commençons par le commencement — le design de l’extension. Le premier épisode démarre, comme pour toute application, avec la définition des besoins fonctionnels, une maquette de l’interface utilisateur, et un planning.

Posons d’abord le problème: Comme nous le savons tous, les chat Twitch peuvent rapidement être surchargés, l’idéal pour une diffusion amusante, mais cela rend le suivi des questions des spectateurs compliqué, en particulier lors de la diffusion de clips “Just Chatting” ou d’un flux technique comme du live coding.

Figma est un outil de prototypage hébergé sur le cloud, permettant facilement et rapidement la création de maquettes de l’interface utilisateur de votre application. Sur la vidéo, l’équipe esquisse les deux vues requises: Live Config et Panel. Voici ce à quoi cela ressemble :

Découpons les fonctionnalités de chaque composant :

  • Le composant Panel (à droite ci-dessus) permet au spectateur de :
    • Soumettre des questions au diffuseur,
    • Voir les questions posées ainsi que les réponses, si elles ont été fournies par le diffuseur.
  • Le composant Live Config (à gauche ci-dessus) permet au diffuseur de :
    • Visualiser la liste des questions,
    • Répondre aux questions.

Une fois les composants définis, poursuivons avec un diagramme d’architecture.

Ce diagramme est divisé en trois piliers :

  1. Les services propriétaires Twitch
  2. Le client
  3. Les services hébergés sur AWS

Les services en violet sont gérés par Twitch, tandis que les services en bleu sont de la responsabilité du développeur.

Analysons la partie Twitch. Twitch fournit aux développeurs des fonctionnalités additionnelles qui permettent de développer et mettre à l’échelle leur application sans avoir à se soucier de problématiques techniques supplémentaires. PubSub permet l’envoi de messages directement depuis les services à toutes les instances de l’extension côté client. En outre, l’helper de l’extension Twitch est livrée avec le client de l’extension, et fournit aux développeurs les services indispensables pour mettre à disposition un identifiant de chaîne, un identifiant utilisateur, ou même savoir si un utilisateur donné est un abonné du diffuseur.

Ensuite, on a le client. Celui-ci consiste en du code Javascript, HTML et CSS et est vu par tous les spectateurs de la chaîne du diffuseur. Lorsque le code client est prêt à être mis en production, le contenu correspondant est hébergé sur le CDN Twitch, géré par Twitch, afin d’assurer aux spectateurs une expérience consistante et à faible latence.

Un service d’extension, bien qu’optionnel, permet une intégration plus poussée avec les autres services, ainsi qu’à l’application de traiter la logiques métier. Dans notre cas, ce service sera écrit en Javascript avec Node.js comme framework. Il agira comme une couche entre les spectateurs, les diffuseurs et DynamoDB. Il fournira au client les données concernant les questions d’une chaîne spécifique, et il traitera les nouvelles questions posées. Comme précisé, Lambda s’occupera de la logique métier, une fois les données reçues au travers d’un point d’entrée API Gateway, et les stockera dans DynamoDB.

Développement des services

La première étape consiste à créer une table DynamoDB nommée “Twitch_Questions” et une clef primaire “id”, contenant un “GUID“ (Global Unique Identifier) arbitraire créé au moment de l’insertion d’une ligne. Nous ajoutons ensuite deux Global Secondary Indexes pour deux requêtes : un index sur le champ “user_id” et un index sur le champ “channel_id”, afin de récupérer les questions par utilisateur ou chaîne de diffusion.

A l’étape suivante, nous avons besoin de créer le squelette de notre application Node.js Express.js, et pour cela nous utilisons la librairie AWS aws-serverless-express/middleware disponible sur Github et installable avec l’outil npm pour créer notre projet de service.

Une fois le projet créé, nous pouvons définir les points d’entrée requis. Voici ceux que nous avons décidé de définir pour récupérer les questions pour le diffuser, ainsi que pour ajouter une question et y répondre :

GET /questions/?user_id={insert a twitch user id}
GET /channelquestions/?channel_id={insert a twitch channel user id to pull questions for the broadcaster}
POST /question body = {user_id, channel_id, question, postedToForum, displayName}
PUT /answer body = {id (of the question), answer (text of the answer)}

Ces points d’entrées définis, nous pouvons coder les fonctions JavaScript qui effectuent les requêtes DynamoDB, insèrent les données dans la table, les effacent, etc… Nous installons le aws-sdk via la commande, npm install aws-sdk, et initialisons le client DynamoDB avec le code const dynamodb = new AWS.DynamoDB.DocumentClient({region: 'us-west-2'}). Nous sommes maintenant capables d’utiliser le client pour effectuer des appels à la table de la base de données.

Nous utilisons une requête DynamoDB et notre Global Secondary Index pour récupérer toutes les questions d’un utilisateur de la manière suivante :

const getQuestionsByUser = async (userid) => {
    var params = {
        ExpressionAttributeValues: { ":userId": userid},
        KeyConditionExpression: "user_id = :userId",
        IndexName: "user_id-index",
        TableName: tableName
    };

    try{
        let data = await dynamodb.query(params).promise();
        console.log(data);
        return data.Items;
    }
    catch(err){
        console.log(err);
    }
}

Pour voir les autres appels effectués sur la base de données, vous pouvez parcourir notre application Node.js Express ici.

Afin de tester notre application, nous utilisons SAM (Serverless Application Model), le modèle d’application serverless, pour lancer notre fonction Lambda localement. SAM consiste à la fois en un template YAML, inclus pour nous lors de la création de l’application avec aws-serverless-express/middleware, et en un outil en ligne de commande (SAM CLI). Si vous avez installé l’outil SAM CLI et Docker, la commande sam local start-api va rechercher le template YAML nommé “template.yaml”, et SAM lancera un container Docker pour vous qui reproduit l’environnement Lambda et exécute votre application dans ce container pour vous permettre de la débugguer avant d’envoyer le code dans le cloud.

Une fois les points d’entrée créés et minutieusement testés grâce à SAM local, nous pouvons déployer notre service pour l’utiliser au sein de notre extension Twitch! Le paquet aws-serverless-express/middleware nous fournit aussi des scripts npm facile à utiliser pour construire notre paquet applicatif et le déployer. Trois de ces commandes sont pertinentes pour notre déploiement :

"package": "aws cloudformation package --template ./template.yaml 
--s3-bucket $npm_package_config_s3BucketName
--output-template packaged-sam.yaml —region $npm_package_config_region"
"deploy": "aws cloudformation deploy --template-file packaged-sam.yaml
--stack-name $npm_package_config_cloudFormationStackName 
--capabilities CAPABILITY_IAM —region $npm_package_config_region“
"package-deploy": "npm run package && npm run deploy“

Nous pouvons choisir entre créer le paquet puis le déployer ou simplement lancer npm run package-deploy qui crée le paquet en le zippant et en le plaçant dans un compartiment S3, met à jour notre fichier template.yaml pour indiquer à Lambda l’endroit où trouver ce paquet une fois déployé, et enfin le déploie. Lorsque npm run deploy est exécuté, notre template.yaml est envoyé à CloudFormation qui se charge de créer pour nous dans le cloud les ressources nécessaires à notre application, comme la fonction Lambda, un point d’entrée API Gateway et possiblement quelques rôles IAM. Une fois l’application déployée, elle peut être à nouveau testée à l’aide de l’URL de production qui est donnée par les informations en sortie de la pile CloudFormation, et nous sommes en mesure de revenir à notre application cliente pour l’appeler comme n’importe quelle API classique !

Développement de l’application cliente

Bien qu’ayant une expérience avec JavaScript, nous n’étions pas certain d’être prêt à développer le client avec Vue.js, étant donné que nous n’avions pas utilisé ce framework auparavant. Si vous n’êtes pas familier, Vue.js est un framework permettant de construire rapidement des interfaces utilisateur et des application “single page” similaire à React. Nous avons tenté l’expérience car il est moins complexe que React et nous permettrait donc de démarrer rapidement.

Avec Vue, un bon point de départ consiste à utiliser la Vue CLI pour générer la base du code. A partir de là, nous ajoutons deux composants: Panel.vue et LiveConfig.vue. Ces composants ont des logiques très similaires et ne diffèrent que par les données affichées à l’utilisateur. Une fois le composant Vue affiché, l’helper de Twitch extension nous fournit des informations contextuelles. Nous utilisons la méthode de cycle de vie des composant Vue mounted(), qui vous donne un accès exhaustif aux composants, templates et au DOM affiché. Dans le morceau de code ci-dessous, nous récupérons le userID, channelID, clientID et token (des constantes déclaré au début de notre fichier Vue) depuis l’extension helper.

async mounted() {
    await twitch.onAuthorized((auth) => {
        userID = auth.userId;
        channelID = auth.channelId;
        clientID = auth.clientId
        token = auth.token;
    this.pullQuestions();
});

Finalement, nous appelons pullQuestions() pour charger les questions qu’un utilisateur pourrait avoir posées précédemment.

pullQuestions(){
    fetch(`${ROOT_URL}questions?user_id=${userID}`,{
        method: 'GET',
        headers: new Headers({
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`})
        })
    .then(data => data.json())
    .then(result => this.questions = result);
});

Ici, nous effectuons une requête GET sur l’adresse /pullQuestions, à laquelle nous passons le userID. Nous avons décidé que les utilisateurs ne pourraient voir que les questions qu’ils ont précédemment posées. La réponse du GET fournit au composant Vue les questions à afficher à l’utilisateur.

Qu’en est-il de la soumission de questions? Lorsqu’une question est tapée dans la case correspondante, le bouton de soumission est attachée à un évènement onClick. Avec Vue, nous pouvons utiliser un raccourci élégant pour faire correspondre une fonction à un bouton :

<button class="askQuestionBtn" @click="askAQuestion" variant="primary">Submit</button>

Ensuite, dans la fonction askAQuestion(), nous effectuons une requête POST sur /question

askAQuestion(){
    fetch(`${ROOT_URL}question`, {
        method: 'POST',
        headers: new Headers({
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${token}`}),
            body: JSON.stringify({
            user_id: `${userID}`,
            channel_id: `${channelID}`,
            question: this.questionText,
            postedToForum: false,
            displayName: displayName
    })
})

Le corps de la requête contient les données nécessaires au service pour traiter l’ajout de la question. Nous envoyons le user_id, channel_id, et la question. Il est aussi important de noter que nous envoyons un jeton Bearer dans l’entête de la requête. Cela nous permet d’authentifier la requête sur notre service.

Utilisation de la plate-forme développeur

La plate forme développeur Twitch (Twitch Developer rig) facilite le développement d’extensions Twitch. Elle permet d’exécuter le client et le service localement, tout en reproduisant l’environnement natif des extensions. Le développeur peut définir plusieurs vues de l’extension qui sont corrélées aux différentes vues possibles (Vue du direct, configuration, et vue du spectateur) ainsi qu’aux différents statuts de l’utilisateur (connecté, non connecté). Dans notre cas, nous voulons exécuter la vue du diffuseur (Live View) avec notre composant LiveView.vue. Sur la droite, nous affichons la vue Panel.vue et simulons un utilisateur connecté. La plate forme aide aussi à simuler d’autre situations avec l’onglet “Edit Context” – comme, par exemple, couper le son, mettre le flux en pause ou encore les modes dark et light.

Test de l’extension

Maintenant que nous avons vérifié le fonctionnement de l’extension sur la plate forme, nous devons effectuer un test hébergé (Hosted Test) — ce qui correspond à charger les éléments de l’extension cliente sur le CDN Twitch et tester dans le contexte d’une chaîne sur Twitch.tv. Il est recommandé de la tester sur votre propre chaîne de diffusion. Pour cela, nous créons notre paquet pour la production à l’aide de la commande npm run build qui assemble nos éléments dans un répertoire nommé dist/ . Puis nous zippons les fichiers dans une archive qui ressemble à :

-- Dist
— live_config.html
— panel.html
— /static
-- /css
-- /js

et la téléchargeons sur Twitch via la console développeur (Developer Dashboard). Nous pouvons maintenant faire la bascule entre test local et test hébergé. Enfin, nous devons cliquer sur le bouton “View and Install on Twitch” qui active l’extension sous la forme d’un panneau sur votre chaîne. Nous pouvons vérifier que tout fonctionne correctement sur notre chaîne, et si c’est le cas, nous sommes prêt à soumettre notre extension pour validation !

Les étapes à suivre

Parcourez le code du projet sur GitHub, et compilez AskACaster localement avec la plate forme développeur. N’hésitez pas à créer des Issues, des Pull Requests ou à poser vos questions..

Dépôt GitHub : https://github.com/twitchdev/AskACaster

Twitch extensions Show

Vous voulez en savoir plus sur ces développements? Suivez les vidéos précédentes de notre Build a Twitch Extension Show, en anglais.

 

Ce billet a été co-rédigé par :

  • Matthew Auerbach – Developer Advocate, Twitch, Twitter: @mauerbac
  • Nicki Klein – Senior Technical Evangelist, AWS, Twitter: @kneekey23
  • et traduit en Français par Olivier Chappe, Architecte Solutions AWS Game Tech, LinkedIn.