https://d226lax1qjow5r.cloudfront.net/blog/blogposts/video-with-text-chat/Blog_Vonage-Video-API_Chat_1200x600.png

Texting-Funktionalität zu einem Video-Chat mit Vonage Video API hinzufügen

Zuletzt aktualisiert am April 29, 2021

Lesedauer: 9 Minuten

In dieser Reihe von Tutorials werden wir die Vonage Video API (ehemals TokBox OpenTok) und was Sie damit bauen können. Die Video API ist sehr robust und in hohem Maße anpassbar. In jedem Beitrag zeigen wir, wie man eine bestimmte Funktion mithilfe der API implementiert. Dieses Mal sehen wir uns an, wie man einem einfachen Audio-Video-Chat Text hinzufügen kann.

Da diese Anwendung etwas serverseitigen Code erfordert, werden wir Glitch um die Einrichtung zu erleichtern. Sie können den Code aus diesem Glitch-Projekt auch herunterladen und auf einem eigenen Server oder einer Hosting-Plattform Ihrer Wahl bereitstellen (möglicherweise müssen Sie die Konfiguration je nach den Anforderungen Ihrer Plattform etwas anpassen).

In dieser Reihe werden wir keine Front-End-Frameworks verwenden, sondern nur Vanilla Javascript, um den Fokus auf die Video API selbst zu legen. Am Ende dieses Tutorials sollten Sie in der Lage sein, eine Audio-Video-Chat-Anwendung mit Text-Chat-Funktionalität zu erstellen. Der Text-Chat wird mit der Signalisierungs-API.

Screenshot of video chat with text chatScreenshot of video chat with text chat

Der endgültige Code für diese Anwendung finden Sie in diesem GitHub-Repository oder neu gemischt auf Glitch.

Voraussetzungen

Bevor wir loslegen, benötigen Sie einen Vonage Video API Account, den Sie kostenlos erstellen können hier. Sie benötigen außerdem Node.js installiert haben (wenn Sie nicht Glitch verwenden).

Dieses Tutorial baut auf dem ersten einführenden Beitrag der Serie auf: Aufbau eines einfachen Video-Chats. Wenn Sie die Video API zum ersten Mal verwenden, empfehlen wir Ihnen dringend, diesen Beitrag durchzuarbeiten, da er die folgenden grundlegenden Einstellungen abdeckt:

  • Erstellen eines Vonage Video API-Projekts

  • Einrichten auf Glitch

  • Grundlegende Projektstruktur

  • Initialisierung einer Sitzung

  • Verbinden mit der Sitzung, Abonnieren und Veröffentlichen

  • Grundlegende Layout-Stile für einen Video-Chat

Grundlagen des Textchats mit Vonage Video API

Die Implementierung von Text-Chat mit der Video API erfolgt über die Signalisierungs-API. Dieser Signalisierungsmechanismus ermöglicht es den mit einer Sitzung verbundenen Clients, sich gegenseitig Text und Daten zu senden. Wir werden uns vorerst nur auf Text konzentrieren.

Das Video API Client SDK sendet ein Ereignis, wenn der Client ein Signal empfängt. Für einen einfachen Text-Chat, bei dem die Nachrichten für alle verbundenen Clients sichtbar sind, verwenden wir die signal() Methode der Sitzung Objekts. Die teilnehmenden Clients empfangen das Signal, indem sie auf das Signalereignis hören, das von dem Session Objekt gesendet wird.

Für einen detaillierten Einblick in die Möglichkeiten, die über die Sitzung Objekt, seine Eigenschaften, Methoden und Ereignisse zugänglich ist, finden Sie in der SDK-Referenz für das Session-Objekt.

Erstmalige Einrichtung

Da wir auf einem grundlegenden Video-Chat aufbauen, beginnen Sie damit, das Projekt für den grundlegenden Video-Chat aus dem vorherigen Tutorial zu remixen. Klicken Sie dazu auf die große Schaltfläche Remix unten. 👇

remix this

Ihre Ordnerstruktur sollte in etwa so aussehen:

Folder structure of the projectFolder structure of the project

Wie eingangs erwähnt, ist TokBox OpenTok jetzt Vonage Video API. Wir haben keine Änderungen an unseren Paketnamen vorgenommen, so dass Sie in Ihrem Code weiterhin auf OpenTok verweisen werden.

Wenn Sie das Glitch-Projekt neu gemischt haben, sollte Ihre server.js Datei bereits wie folgt aussehen:

const express = require("express");
const app = express();
const OpenTok = require("opentok");
const OT = new OpenTok(process.env.API_KEY, process.env.API_SECRET);

let sessions = {};

app.use(express.static("public"));

app.get("/", (request, response) => {
  response.sendFile(__dirname + "/views/landing.html");
});

app.get("/session/:room", (request, response) => {
  response.sendFile(__dirname + "/views/index.html");
});

app.post("/session/:room", (request, response) => {
  const roomName = request.params.room;
  // Check if the session already exists
  if (sessions[roomName]) {
    // Generate the token
    generateToken(roomName, response);
  } else {
    // If the session does not exist, create one
    OT.createSession((error, session) => {
      if (error) {
        console.log("Error creating session:", error);
      } else {
        // Store the session in the sessions object
        sessions[roomName] = session.sessionId;
        // Generate the token
        generateToken(roomName, response);
      }
    });
  }
});

function generateToken(roomName, response) {
  // Configure token options
  const tokenOptions = {
    role: "publisher",
    data: `roomname=${roomName}`
  };
  // Generate token with the Video API Client SDK
  let token = OT.generateToken(
    sessions[roomName],
    tokenOptions
  );
  // Send the required credentials back to to the client
  // as a response from the fetch request
  response.status(200);
  response.send({
    sessionId: sessions[roomName],
    token: token,
    apiKey: process.env.API_KEY
  });
}

const listener = app.listen(process.env.PORT, () => {
  console.log("Your app is listening on port " + listener.address().port);
});

Um den Video-Chat zum Laufen zu bringen, gehen Sie zur .env und geben Sie den API-Schlüssel und das Geheimnis für Ihr Projekt ein, die Sie im Dashboard finden können. Sobald das erledigt ist, werden wir am clientseitigen Code arbeiten, um den Text-Chat zum Laufen zu bringen, bevor wir uns die server.js Datei wieder besuchen.

Fügen Sie das erforderliche Markup hinzu

Unsere Anwendung wird aus 2 Seiten bestehen. Eine Landing Page mit zwei Texteingaben. Auf der einen können die Benutzer eine Sitzung erstellen, die wir als "Raum" bezeichnen werden, damit spätere Teilnehmer demselben "Raum" beitreten können. Die andere Texteingabe dient dazu, dass die Benutzer einen Anzeigenamen eingeben können, mit dem sie sich identifizieren können.

Die Seite wird ein einfaches Formularelement mit zwei Eingabefeldern enthalten, in die die Benutzer ihren Raumnamen und ihren Benutzernamen eingeben können. Fügen wir das Feld für den Benutzernamen zum Formular hinzu.

<form class="registration" id="registration">
  <label>
    <span>Room</span>
    <input
      type="text"
      name="room-name"
      placeholder="Enter room name"
      required
    />
  </label>

  <!-- Add the user name input field and label -->
  <label>
    <span>User name</span>
    <input
      type="text"
      name="user-name"
      placeholder="Enter your name"
      required
    />
  </label>
  <button>Enter</button>
</form>

Wir müssen auch eine Chatbox auf der index.html Seite hinzufügen. Fügen wir das Markup für ein Chat-Fenster mit einer Kopfzeile, einem Bereich zur Anzeige von Nachrichten und einer Eingabe am unteren Rand zum Eingeben und Senden von Nachrichten hinzu. Um den Platz auf dem Bildschirm zu maximieren, wird das Chat-Fenster standardmäßig ausgeblendet und nur aktiviert, wenn Sie auf die Chat-Schaltfläche in der rechten unteren Ecke der Seite klicken.

Chat button to trigger chat windowChat button to trigger chat window

Fügen Sie das folgende Markup zu Ihrer Seite hinzu. Im nächsten Abschnitt werden wir die Stile hinzufügen, damit die Schaltfläche wie das obige Design aussieht.

<button class="btn-chat" id="showChat" aria-label="Show chat">
  <svg viewBox="0 0 512 512">
    <path
      fill="white"
      d="m512 346.5c0-63.535156-36.449219-120.238281-91.039062-147.820312-1.695313 121.820312-100.460938 220.585937-222.28125 222.28125 27.582031 54.589843 84.285156 91.039062 147.820312 91.039062 29.789062 0 58.757812-7.933594 84.210938-23.007812l80.566406 22.285156-22.285156-80.566406c15.074218-25.453126 23.007812-54.421876 23.007812-84.210938zm0 0"
    />
    <path
      fill="white"
      d="m391 195.5c0-107.800781-87.699219-195.5-195.5-195.5s-195.5 87.699219-195.5 195.5c0 35.132812 9.351562 69.339844 27.109375 99.371094l-26.390625 95.40625 95.410156-26.386719c30.03125 17.757813 64.238282 27.109375 99.371094 27.109375 107.800781 0 195.5-87.699219 195.5-195.5zm-225.5-45.5h-30c0-33.085938 26.914062-60 60-60s60 26.914062 60 60c0 16.792969-7.109375 32.933594-19.511719 44.277344l-25.488281 23.328125v23.394531h-30v-36.605469l35.234375-32.25c6.296875-5.761719 9.765625-13.625 9.765625-22.144531 0-16.542969-13.457031-30-30-30s-30 13.457031-30 30zm15 121h30v30h-30zm0 0"
    />
  </svg>
</button>

Wir wollen auch das Markup für das Chat-Fenster in die index.html Datei hinzufügen.

Bare bones chat window which will slide in from the rightBare bones chat window which will slide in from the right

<aside id="chatWindow">
  <header class="chat-header">
    <h1><span id="roomName"></span>Chat</h1>
    <button class="btn-close" id="closeChat" aria-label="Close chat">
      <svg viewBox="0 0 47.971 47.971" role="img">
        <path
          d="M28.228 23.986L47.092 5.122a2.998 2.998 0 000-4.242 2.998 2.998 0 00-4.242 0L23.986 19.744 5.121.88a2.998 2.998 0 00-4.242 0 2.998 2.998 0 000 4.242l18.865 18.864L.879 42.85a2.998 2.998 0 104.242 4.241l18.865-18.864L42.85 47.091c.586.586 1.354.879 2.121.879s1.535-.293 2.121-.879a2.998 2.998 0 000-4.242L28.228 23.986z"
        />
      </svg>
    </button>
  </header>

  <section id="messageArea" class="messages"></section>

  <form class="chat-form" id="chatForm">
    <input id="chatInput" type="text" />
    <input type="submit" value="Send" />
  </form>
</aside>

Gestalten Sie die Chat-bezogenen Elemente

Unsere Chat-Oberfläche wird so lange ausgeblendet, bis sie benötigt wird, da die Hauptfunktion dieser Anwendung der Video-Chat ist. Um das Chat-Interface einzuschalten, klicken die Benutzer auf die Chat-Schaltfläche in der unteren rechten Ecke der Seite. Diese Schaltfläche hat ein SVG-Symbol, um anzuzeigen, dass sie den Chat auslöst.

.btn-chat {
  height: 3.5em;
  width: 3.5em;
  background-color: black;
  border-radius: 50%;
  box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.2), 0 3px 6px 0 rgba(0, 0, 0, 0.19);
  position: fixed;
  right: 1em;
  bottom: 1em;
}

.btn-chat svg {
  height: 1.5em;
  width: 1.5em;
}

Wir verwenden CSS, um das Chat-Fenster standardmäßig außerhalb des Viewports zu platzieren. Wenn jemand auf das Chatsymbol klickt, wird eine CSS-Klasse umgeschaltet, die den translateX Wert so ändert, dass das Fenster von der rechten Seite des Bildschirms in die Ansicht gleitet.

aside {
  position: fixed;
  top: 0;
  right: 0;
  transform: translateX(100%);
  display: flex;
  flex-direction: column;
  min-width: 20em;
  width: 25%;
  height: 100%;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
  transition: transform 0.5s ease;
}

aside.active {
  transform: translateX(0);
}

Fügen wir noch einige Stile für die Kopfzeile, den Nachrichtenbereich und das Nachrichteneingabeformular hinzu.

.chat-header {
  background-color: white;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
  display: flex;
  align-items: center;
}

.btn-close {
  margin-left: auto;
  height: 2em;
  width: 2em;
  background: transparent;
  border: none;
  cursor: pointer;
}

.btn-close svg {
  height: 1em;
  width: 1em;
}

.messages {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow-y: scroll;
  padding: 0.5em;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.24);
  background-color: rgba(255, 255, 255, 0.75);
}

.messages p {
  margin-bottom: 0.5em;
  display: flex;
  word-break: break-word;
}

.chat-form {
  padding: 0.5em;
  background-color: white;
  display: flex;
  align-items: center;
}

.chat-form input[type="text"] {
  flex: 1;
}

.chat-form input[type="submit"] {
  margin-left: 0.5em;
  align-self: stretch;
}

Mit diesen Stilen sollten Sie in der Lage sein, ein Chat-Symbol in der unteren rechten Ecke der index.html Datei sehen, nachdem Sie den Raum betreten haben. Aber wenn Sie darauf klicken, tut sich noch nichts.

Fügen wir einen Event-Handler hinzu, um eine CSS-Klasse zu aktivieren, die das Chat-Fenster in die Ansicht in der client.js Datei. Sowie eine auf das Schließen-Symbol des Chat-Fensters, um es wieder herauszuschieben.

const showChatBtn = document.getElementById("showChat");
showChatBtn.addEventListener(
  "click",
  event => {
    const chatWindow = document.getElementById("chatWindow");
    chatWindow.classList.toggle("active");
  },
  false
);

const closeChatBtn = document.getElementById("closeChat");
closeChatBtn.addEventListener(
  "click",
  event => {
    const chatWindow = document.getElementById("chatWindow");
    chatWindow.classList.remove("active");
  },
  false
);

Dies ist nicht die einzige Möglichkeit, eine Chat-Oberfläche zu gestalten, Sie können sie also nach Belieben verändern.

Verwendung der Signal-API für Text-Chat

Lassen Sie uns noch ein paar Änderungen am Basisprojekt vornehmen und den grundlegenden Text-Chat zum Laufen bringen.

Wir verschieben die session Variable aus der initializeSession Funktion und deklarieren sie global am Anfang der client.js Datei.

let session;

function initializeSession(apiKey, sessionId, token) {
  // Create a session object with the sessionId
  session = OT.initSession(apiKey, sessionId);

  // All the rest of the code
}

Fügen Sie dem Chat-Formular einen Ereignislistener hinzu, der ein Signal an alle mit der Sitzung verbundenen Clients sendet, wenn das Formular abgeschickt wird.

const chat = document.getElementById("chatForm");
const msgTxt = document.getElementById("chatInput");
chat.addEventListener(
  "submit",
  event => {
    event.preventDefault();
    session.signal(
      {
        type: "msg",
        data: `${msgTxt.value}`
      },
      () => {
        msgTxt.value = "";
      }
    );
  },
  false
);

Wir benötigen außerdem einen weiteren Ereignis-Listener, der diese Nachricht empfängt, indem er auf das signal Ereignis, das vom Session-Objekt ausgelöst wird. Die Nutzdaten dieses Ereignisses werden verwendet, um die Nachricht in den Nachrichtenbereich des Chat-Fensters zu drucken.

function initializeSession(apiKey, sessionId, token) {
  // Create a session object with the sessionId
  session = OT.initSession(apiKey, sessionId);

  // All the rest of the code

  // Event listener for the msg signal
  session.on("signal:msg", event => {
    const content = event.data;
    updateChat(content);
  });
}

function updateChat(content) {
  const msgHistory = document.getElementById("messageArea");
  const msg = document.createElement("p");
  msg.textContent = content;
  msgHistory.appendChild(msg);
  msgHistory.scroll({
    top: msgHistory.scrollHeight,
    behavior: "smooth"
  });
}

Dies ist der grundlegende Mechanismus des Textchats mit der Video API. Wenn Sie etwas in das Chat-Fenster eingeben und abschicken, sollte es auf dem Bildschirm angezeigt werden.

Identifizieren Sie die Teilnehmer des Chats

Um den Chat jedoch benutzerfreundlicher zu gestalten, wollen wir auch eine Möglichkeit hinzufügen, um zu erkennen, wer was im Chat gesagt hat. Wir werden die Eingabe des Benutzernamens auf der Landing Page nutzen, um diese Informationen zu erhalten, und sie als Abfrage-String in der URL an den Server weitergeben.

Das folgende Skript auf der Seite landing.html Seite übergibt den eingegebenen Raumnamen und Benutzernamen an die index.html Seite weiter.

const form = document.getElementById("registration");
form.addEventListener("submit", event => {
  event.preventDefault();
  location.href = `/session/${form.elements["room-name"].value}?username=${form.elements["user-name"].value}`;
});

Wenn die index.html Seite lädt, löst sie eine POST Anfrage an die session/:name aus, die den übermittelten Benutzernamen aus der URL extrahiert und an den Server weiterleitet.

const url = new URL(window.location.href);
const roomName = url.pathname.split("/")[2];
const userName = url.searchParams.get("username");

fetch(location.pathname, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ username: userName })
})
  .then(res => {
    return res.json();
  })
  .then(res => {
    const apiKey = res.apiKey;
    const sessionId = res.sessionId;
    const token = res.token;
    const streamName = res.streamName;
    initializeSession(apiKey, sessionId, token, streamName);
  })
  .catch(handleCallback);

Nun müssen wir diese Route in der Datei server.js so ändern, dass sie den Raumnamen und den Benutzernamen verarbeitet und die erforderlichen Informationen für die initializeSession Funktion zurückgibt. Außerdem müssen wir eine Middleware einbinden, die die Nutzdaten der Anfrage verarbeitet.

// Middleware to read the body of the request
app.use(express.json());

app.post("/session/:room", (request, response) => {
  const roomName = request.params.room;
  const streamName = request.body.username;
  // Check if the session already exists
  if (sessions[roomName]) {
    // Generate the token
    generateToken(roomName, streamName, response);
  } else {
    // If the session does not exist, create one
    OT.createSession((error, session) => {
      if (error) {
        console.log("Error creating session:", error);
      } else {
        // Store the session in the sessions object
        sessions[roomName] = session.sessionId;
        // Generate the token
        generateToken(roomName, streamName, response);
      }
    });
  }
});

function generateToken(roomName, streamName, response) {
  // Configure token options
  const tokenOptions = {
    role: "publisher",
    data: `roomname=${roomName}?streamname=${streamName}`
  };
  // Generate token with the Video API Client SDK
  let token = OT.generateToken(sessions[roomName], tokenOptions);
  // Send the required credentials back to to the client
  // as a response from the fetch request
  response.status(200);
  response.send({
    sessionId: sessions[roomName],
    token: token,
    apiKey: process.env.API_KEY
  });
}

Auf der Seite client.jskönnen wir nun den Benutzernamen des Teilnehmers anzeigen, der die Nachricht geschrieben hat, indem wir die data Eigenschaft der session.signal() Methode.

session.signal(
  {
    type: "msg",
    data: `${session.connection.data.split("=")[2]}: ${msgTxt.value}`
  },
  () => {
    msgTxt.value = "";
  }
);

Wenn Sie jetzt eine Textnachricht senden, wird ihr der Benutzername vorangestellt, den Sie beim Betreten des Raums verwendet haben.

PouchDB als Datenspeicher einrichten

Wenn Sie die Seite jedoch aktualisieren, sind alle vorherigen Chat-Nachrichten verschwunden. Das liegt daran, dass wir die Nachrichten nicht gespeichert, sondern nur auf dem Bildschirm angezeigt haben. Lassen Sie uns eine Art Datenspeicher für die Nachrichten einführen.

Wir verwenden PouchDB auf dem Server, aber es steht Ihnen frei, diesen durch einen beliebigen Datenspeicher Ihrer Wahl zu ersetzen.

Installieren Sie pouchdb-node mit dem folgenden Befehl (beachten Sie, dass die Verwendung von pnpm eine Glitch-Sache ist):

pnpm install pouchdb-node --save

pouchdb-node installation on Glitchpouchdb-node installation on Glitch

Überprüfen wir, ob die Dinge wie erwartet laufen.

const PouchDB = require("pouchdb-node");
const sessionDb = new PouchDB("sessionDb");

sessionDb.info().then(info => console.log(info));

In den Störungsprotokollen sollten Sie folgendes sehen.

Database information printed to consoleDatabase information printed to console

PouchDB bietet ein vollständig asynchrones API, obwohl es auch die Möglichkeit bietet, zwischen dem Callback-Format und dem Promise-Format zu wählen. Für dieses Tutorial werden wir das Promise-Format verwenden, und der Code wird dies widerspiegeln.

Anstatt die Sitzungsinformationen in einer Objektvariablen zu speichern, werden wir sie in unserer neuen Datenbank speichern. Entfernen Sie die folgende Zeile aus der server.js Datei.

// We no longer need this object
let sessions = {};

Lassen Sie uns weitere Optimierungen an der /session/:name Route. Zunächst überprüfen wir in der Datenbank, ob eine Sitzung existiert. Ist dies der Fall, rufen wir die zugehörigen Informationen ab und erzeugen daraus das Token. Wenn die Sitzung nicht existiert, erstellen wir eine neue Sitzung, speichern sie in der Datenbank und generieren dann das Token entsprechend.

app.post("/session/:room", (request, response) => {
  const roomName = request.params.room;
  const streamName = request.body.username;
  const isExistingSession = checkSession(roomName);

  isExistingSession.then(sessionExists => {
    if (sessionExists) {
      sessionDb
        .get(roomName)
        .then(sessionInfo => {
          generateToken(roomName, streamName, sessionInfo, response);
        })
        .catch(error => error);
    } else {
      OT.createSession((error, session) => {
        if (error) {
          console.log("Error creating session:", error);
        } else {
          const sessionInfo = {
            _id: roomName,
            sessionId: session.sessionId,
            messages: []
          };
          sessionDb.put(sessionInfo);
          generateToken(roomName, streamName, sessionInfo, response);
        }
      });
    }
  });
});

function checkSession(roomName) {
  return sessionDb
    .get(roomName)
    .then(() => {
      console.log(roomName + "exists");
      return Promise.resolve(true);
    })
    .catch(() => {
      console.log("Room does not exist");
      return Promise.resolve(false);
    });
}

function generateToken(roomName, streamName, sessionInfo, response) {
  const tokenOptions = {
    role: "publisher",
    data: `roomname=${roomName}?streamname=${streamName}`
  };
  let token = OT.generateToken(sessionInfo.sessionId, tokenOptions);
  response.status(200);
  response.send({
    sessionId: sessionInfo.sessionId,
    token: token,
    apiKey: process.env.API_KEY,
    streamName: streamName
  });
}

Stream-Namen zur UI hinzufügen

Wir können den Stream-Namen in der Antwort verwenden, um die Streams zu kennzeichnen, so dass die Teilnehmer mit dem Mauszeiger über den Videostream eines jeden Teilnehmers fahren können, um einen Namen zu sehen. Sowohl die initPublisher() Methode als auch die subscribe() Methode akzeptieren ein optionales properties Argument, mit dem wir Anpassungsoptionen für den Stream übergeben können.

function initializeSession(apiKey, sessionId, token, streamName) {
  // Create a session object with the sessionId
  session = OT.initSession(apiKey, sessionId);

  // Create a publisher
  const publisher = OT.initPublisher(
    "publisher",
    {
      insertMode: "append",
      width: "100%",
      height: "100%",
      name: streamName
    },
    handleCallback
  );

  // Subscribe to a newly created stream
  session.on("streamCreated", event => {
    session.subscribe(
      event.stream,
      "subscriber",
      {
        insertMode: "append",
        width: "100%",
        height: "100%",
        name: event.stream.name
      },
      handleCallback
    );
  });
}

Hover over a video stream to see the stream nameHover over a video stream to see the stream name

Nachrichten in der Datenbank speichern

Wenn die Teilnehmer Textnachrichten senden, wollen wir sie an den Server senden, damit sie in der Datenbank gespeichert werden. Lassen Sie uns eine saveMessage() Funktion, die das erledigt.

function saveMessage(content) {
  const message = {
    _id: Date.now().toString(),
    content: content,
    roomname: name,
    user: username
  };

  fetch("/message", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(message)
  }).catch(handleCallback);
}

Ändern Sie den Ereignis-Listener auf dem Chat-Formular, um diese Funktion auszulösen, sobald ein Teilnehmer eine Textnachricht absendet.

chat.addEventListener(
  "submit",
  event => {
    event.preventDefault();
    session.signal(
      {
        type: "msg",
        data: `${session.connection.data.split("=")[2]}: ${msgTxt.value}`
      },
      () => {
        saveMessage(msgTxt.value);
        msgTxt.value = "";
      }
    );
  },
  false
);

In der server.js Datei müssen wir einen Handler für diese POST Anfrage hinzufügen.

app.post("/message", (request, response) => {
  const roomName = request.body.roomName;
  const message = {
    timeStamp: request.body._id,
    content: request.body.content,
    user: request.body.user
  };
  sessionDb
    .get(roomName)
    .then(result => {
      result.messages = [...result.messages, message];
      return sessionDb.put(result);
    })
    .then(() => {
      return sessionDb.get(roomName);
    })
    .then(result => {
      response.status(200);
      response.send({
        latestMessage: result.messages[result.messages.length - 1]
      });
    })
    .catch(error => console.log(error));
});

Da unsere Nachrichten nun gespeichert sind, wollen wir sie beim Laden der Seite anzeigen. Wir fügen eine getChatHistory() Funktion auf der Client-Seite hinzufügen, die eine GET Anfrage auslöst, um alle gespeicherten Nachrichten für diese Sitzung abzurufen und sie im Chatfenster anzuzeigen.

function getChatHistory() {
  fetch(`/messages/${roomName}`)
    .then(res => {
      return res.json();
    })
    .then(res => {
      const messageArea = document.getElementById("messageArea");
      res.messagesArray.forEach(message => {
        const msg = document.createElement("p");
        msg.textContent = `${message.user}: ${message.content}`;
        messageArea.appendChild(msg);
      });
      messageArea.scroll({
        top: messageArea.scrollHeight,
        behavior: "smooth"
      });
    })
    .catch(handleCallback);
}

Und die entsprechende Route auf der Serverseite, um die Nachrichten als Array an den Client zurückzugeben.

app.get("/messages/:room", (request, response) => {
  const roomName = request.params.room;
  sessionDb
    .get(roomName)
    .then(result => {
      response.status(200);
      response.send({
        messagesArray: result.messages
      });
    })
    .catch(error => console.log(error));
});

Wenn Sie also die Seite aktualisieren, während die Sitzung noch läuft, sind die Nachrichten immer noch da. Wenn Sie außerdem denselben Raumnamen wie bei einer früheren Sitzung mit gespeichertem Chatverlauf eingeben, wird dieser Chatverlauf angezeigt.

Was kommt als Nächstes?

Der endgültige Code für Glitch und GitHub enthält alles, was wir in diesem ziemlich langen Beitrag behandelt haben, aber neu organisiert, so dass der Code sauberer und besser wartbar ist. Fühlen Sie sich frei, den Code zu remixen oder zu klonen und selbst damit herumzuspielen.

Es gibt noch weitere Funktionen, die wir mit der Video API von Vonage erstellen können und die in zukünftigen Tutorials behandelt werden, aber in der Zwischenzeit können Sie mehr auf unserer umfassenden Dokumentationsseite. Wenn Sie auf Probleme stoßen oder Fragen haben, wenden Sie sich an uns auf unserem Gemeinschaft Slack. Vielen Dank fürs Lesen!

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/46621147f0/huijing.png
Hui Jing ChenVonage Ehemalige

Hui Jing ist Developer Advocate bei Nexmo. Sie hat eine übermäßige Liebe zu CSS und Typografie und ist allgemein leidenschaftlich über alle Dinge im Web.