DéveloppeurWeb.Com
    DéveloppeurWeb.Com
    • Agile Zone
    • AI Zone
    • Cloud Zone
    • Database Zone
    • DevOps Zone
    • Integration Zone
    • Web Dev Zone
    DéveloppeurWeb.Com
    Home»Web Dev Zone»Comment utiliser WebSockets avec AWS Serverless
    Web Dev Zone

    Comment utiliser WebSockets avec AWS Serverless

    novembre 30, 2021
    Comment utiliser WebSockets avec AWS Serverless
    Share
    Facebook Twitter Pinterest Reddit WhatsApp Email

    Dans ce guide, nous allons voir comment utiliser WebSockets à l’aide d’un framework sans serveur AWS avec NodeJs. À la fin de ce guide, nous aurons une application où nous pourrons créer une salle de discussion et d’autres utilisateurs pourront rejoindre notre salle pour discuter entre eux dans une salle personnalisée. J’ai rendu la procédure très simple à suivre, et à la fin de cet article, vous obtiendrez également un lien vers le référentiel Github pour le code.

    Configuration du projet

    La première chose à faire est de configurer le dossier du projet et d’installer les dépendances du projet requises en créant un nouveau dossier et en exécutant les commandes ci-dessous à la racine du dossier du projet.

    npm init
    npm i aws-sdk --save

    Créer un dossier nommé src à la racine du projet et à l’intérieure src dossier, créez trois autres dossiers avec index.js fichiers dans chaque dossier :

    1. gestionnaire de connexion: ce dossier contiendra le fichier avec le code pour gérer les événements de connexion et de déconnexion de WebSockets.
    2. gérerChambre: Ce dossier contiendra le fichier avec le code pour créer/rejoindre la salle de discussion.
    3. envoyer le message: Ce dossier contiendra le fichier avec le code pour émettre le message à tous les utilisateurs connectés dans une salle particulière si un utilisateur de la salle envoie un message.

    À présent, la structure de notre projet devrait ressembler à ceci :

    Exemple de structure de projet.

    Nous avons maintenant terminé la configuration de base du projet et nous sommes prêts à passer à l’étape suivante, qui consiste à créer le sans serveur.yml déposer.

    Qu’est-ce qu’un fichier serverless.yml ?

    Dans un langage très simple, un sans serveur.yml est utilisé pour coder le modèle en fonction des ressources que nous souhaitons créer dans notre compte AWS. Nous pouvons définir différents types de ressources dans le sans serveur.yml fichier, et nous pouvons également définir les différentes autorisations pour différentes ressources.

    Dans ce projet, l’utilisation principale de sans serveur.yml sera de créer les fonctions Lambda et de configurer la table DynamoDB avec différentes autorisations.

    Définition du bloc de configuration et d’autorisations dans le fichier serverless.yml

    service: serverless-chat
    
    provider:
      name: aws
      runtime: nodejs12.x
      websocketsApiName: custom-websockets-api-name
      websocketsApiRouteSelectionExpression: $request.body.action
      environment:
        DYNAMO_TABLE_NAME: connections
      iamRoleStatements:
        - Effect: Allow
          Action:
            - dynamodb:Query
            - dynamodb:Scan
            - dynamodb:GetItem
            - dynamodb:PutItem
            - dynamodb:DeleteItem
            - dynamodb:UpdateItem
            - lambda:InvokeFunction
          Resource: "arn:aws:dynamodb:${opt:region, self:provider.region}:*:
          table/${self:provider.environment.DYNAMO_TABLE_NAME}"

    C’est la première partie de notre sans serveur.yml déposer. Décomposons-le en parties.

    • service: C’est le nom du modèle CloudFormation qui sera créé dans le compte AWS.
    • fournisseur: Nous définissons la configuration, les variables d’environnement, les différentes autorisations et les rôles dans ce bloc. Ici, dans ce code, nous définissons des éléments tels que la version de NodeJs que nous souhaitons utiliser dans notre environnement AWS.
    • WebsocketsApiRouteSelectionExpression: il s’agit de l’expression de sélection de route personnalisée, ce qui signifie que si nous voulons émettre des événements personnalisés à partir de notre client WebSocket, nous transmettrons le nom de l’événement dans la propriété action de la charge utile.
    • action: Ce bloc a toutes les autorisations que nous souhaitons donner à notre fonction Lambda pour effectuer différentes opérations sur la table DynamoDB.

    Définition du bloc de fonctions dans le fichier serverless.yml

    functions:
      connectionHandler:
        handler: src/connectionHandler/index.connectionHandler
        events:
          - websocket:
              route: $connect
          - websocket:
              route: $disconnect
    
      sendMessage:
        handler: src/sendMessage/index.sendMessage
        events:
          - websocket:
              route: sendmessage
    
      manageRoom:
        handler: src/manageRoom/index.manageRoom
        events:
          - websocket:
              route: manageroom

    C’est ici que nous définirons toutes nos fonctions Lambda à créer. Décomposons-le un peu pour une meilleure compréhension :

    • gestionnaire de connexion: Il s’agit de la fonction Lambda qui sera appelée lorsqu’un utilisateur se connectera ou se déconnectera de notre serveur WebSocket. Il existe trois événements ou itinéraires prédéfinis définis par Passerelle API :$connect, $disconnect et $default.
    • $connecter/$déconnecter: Lorsque l’utilisateur se connecte à notre serveur WebSocket, $connect est l’événement par défaut qui est appelé, et lorsque l’utilisateur se déconnecte, le $disconnect l’événement est appelé.
    • envoyer le message: Cette fonction sera appelée si l’utilisateur envoie envoyer le message comme valeur de la propriété action dans la charge utile de la demande. Il gère l’envoi de messages à tous les utilisateurs connectés dans une pièce particulière.
    • gérerChambre: Cette fonction permet de créer/rejoindre une salle en fonction de l’identifiant de la salle.

    Définition du bloc de ressources dans le fichier serverless.yml

    resources:
      Resources:
        UsersDynamoDbTable:
          Type: AWS::DynamoDB::Table
          DeletionPolicy: Retain
          Properties:
            AttributeDefinitions:
              - AttributeName: connectionId
                AttributeType: S
            KeySchema:
              - AttributeName: connectionId
                KeyType: HASH
            ProvisionedThroughput:
              ReadCapacityUnits: 1
              WriteCapacityUnits: 1
            TableName: ${self:provider.environment.DYNAMO_TABLE_NAME}

    C’est notre bloc de ressources dans le sans serveur.yml déposer. Nous définissons toutes les ressources que nous souhaitons créer automatiquement dans le compte AWS dans ce fichier. Ici, nous créons une nouvelle table DynamoDB avec un Touche dièse, ou dans une autre langue, Clé primaire, si vous venez d’un background SQL.

    Connexion et déconnexion des utilisateurs

    Commençons à travailler sur la fonction Lambda pour connecter ou déconnecter les clients WebSocket. Nous utilisons le gestionnaire de connexion fonction pour gérer cette fonctionnalité. Cela ressemblera à quelque chose comme ceci :

    const AWS = require('aws-sdk');
    
    const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION });
    
    exports.connectionHandler = async event => {
        const connectionId = event.requestContext.connectionId;
        const eventType = event.requestContext.eventType
        if (eventType === 'DISCONNECT') {
            try {
                await ddb.delete({ TableName: process.env.DYNAMO_TABLE_NAME, Key: { connectionId } }).promise();
                return { statusCode: 200, body: 'Disconnected' };
            }
            catch (e) {
                return { statusCode: 500, body: 'Could not clear the connection.' };
            }
        }
        else if (eventType === "CONNECT") {
            const putParams = {
                TableName: process.env.DYNAMO_TABLE_NAME,
                Item: {
                    connectionId
                }
            };
    
            try {
                await ddb.put(putParams).promise();
            } catch (err) {
                return { statusCode: 500, body: 'Failed to connect: ' + JSON.stringify(err) };
            }
    
            return { statusCode: 200, body: 'Connected.' };
        }
    };

    Nous allons détailler chaque partie de la fonction, commençons donc par la première partie : la gestion des utilisateurs connectés.

    Connexion des utilisateurs

    else if (eventType === "CONNECT") {
            const putParams = {
                TableName: process.env.DYNAMO_TABLE_NAME,
                Item: {
                    connectionId
                }
            };
    
            try {
                await ddb.put(putParams).promise();
            } catch (err) {
                return { statusCode: 500, body: 'Failed to connect: ' + JSON.stringify(err) };
            }
    
            return { statusCode: 200, body: 'Connected.' };
        }

    Ce que nous faisons ici, c’est vérifier si l’utilisateur était connecté à l’aide de l’URL WebSocket API Gateway. Si l’utilisateur était connecté, nous obtenons le connectionId du event.requestContextobjet et créer une nouvelle entrée dans la table DynamoDB avec le connectionId valeur. Ceci est juste une simple opération d’insertion sur la table DynamoDB avec connectionId.

    Qu’est-ce que .Promise() ?

    Si vous vous demandez pourquoi nous utilisons .promise() ici, il est utilisé parce que nous voulons écrire du code propre au mieux de nos capacités, nous voulons donc utiliser async/await au lieu de callbacks. Pour utiliser async/await, l’appel de fonction doit retourner une promesse Javascript, c’est pourquoi nous utilisons le .promise() appel. La plupart des fonctions d’AWS-SDK ont une option à utiliser .promise() , ce qui permet à la fonction de renvoyer le résultat dans une promesse au lieu d’un rappel.

    Déconnexion des utilisateurs

    if (eventType === 'DISCONNECT') {
            try {
                await ddb.delete({ TableName: process.env.DYNAMO_TABLE_NAME, Key: { connectionId } }).promise();
                return { statusCode: 200, body: 'Disconnected' };
            }
            catch (e) {
                return { statusCode: 500, body: 'Could not clear the connection.' };
            }
        }

    Ici, nous vérifions si l’utilisateur a été déconnecté du serveur WebSocket. Si l’utilisateur a été déconnecté, alors connectionId est utilisé pour supprimer cette entrée utilisateur de la table DynamoDB.

    Créer et rejoindre des salons de discussion

    L’étape suivante consiste à configurer une fonction Lambda pour permettre aux utilisateurs de créer ou de rejoindre une salle. Le code de la fonction ressemblera à ceci :

    const AWS = require('aws-sdk');
    
    const ddb = new AWS.DynamoDB.DocumentClient({ apiVersion: '2012-08-10', region: process.env.AWS_REGION });
    
    exports.manageRoom = async event => {
        const body = JSON.parse(event.body)
        if (!body.roomid) return { statusCode: 200, body: 'Room id is required.' };
    
        const params = {
            TableName: process.env.DYNAMO_TABLE_NAME,
            Key: {
                connectionId: event.requestContext.connectionId,
            },
            ExpressionAttributeValues: {
                ":roomid": body.roomid,
            },
            UpdateExpression: "SET roomid = :roomid",
            ReturnValues: "ALL_NEW"
        };
    
        const data = await ddb.update(params).promise();
        if (data.Attributes) {
            return { statusCode: 200, body: 'Room joined.' };
        } else {
            return { statusCode: 400, body: 'Some error has occured.' };
        }
    };

    Découpons le code en différentes parties pour une meilleure compréhension du code.

    Obtenir et vérifier l’ID de la salle

    const body = JSON.parse(event.body)
    if (!body.roomid) return { statusCode: 200, body: 'Room id is required.' };

    Ici, nous obtenons le corps de la demande et l’analysons en tant que données JSON, et nous vérifions également si roomid est présent dans l’objet corps, car roomid est requis si l’utilisateur essaie de créer/rejoindre une salle de discussion.

    Créer/rejoindre la salle de discussion

    const params = {
            TableName: process.env.DYNAMO_TABLE_NAME,
            Key: {
                connectionId: event.requestContext.connectionId,
            },
            ExpressionAttributeValues: {
                ":roomid": body.roomid,
            },
            UpdateExpression: "SET roomid = :roomid",
            ReturnValues: "ALL_NEW"
        };
    
        const data = await ddb.update(params).promise();
        if (data.Attributes) {
            return { statusCode: 200, body: 'Room joined.' };
        } else {
            return { statusCode: 400, body: 'Some error has occured.' };
        }

    Ici, nous mettons à jour une entrée dans la table DynamoDB selon le connectionId et régler la colonne roomid avec la valeur qui est passée par l’utilisateur dans le corps de la requête. Par exemple, si connectionId est #f!41fg et le roomid passé par l’utilisateur est test-chat-room, alors ce code mettra à jour le roomid colonne avec la valeur test-chat-room dans la rangée où connectionId est #f!41fg.

    Envoi d’un message à tous les utilisateurs connectés dans la salle de conversation

    La dernière partie de notre projet consiste à créer une fonction Lambda pour envoyer un message à…

    Share. Facebook Twitter Pinterest LinkedIn WhatsApp Reddit Email
    Add A Comment

    Leave A Reply Cancel Reply

    Catégories

    • Politique de cookies
    • Politique de confidentialité
    • CONTACT
    • Politique du DMCA
    • CONDITIONS D’UTILISATION
    • Avertissement
    © 2023 DéveloppeurWeb.Com.

    Type above and press Enter to search. Press Esc to cancel.