Dans ce tutoriel, nous allons créer une application de chat à l'aide de sockets Web. Les sockets Web sont vraiment utiles lorsque vous souhaitez créer des applications nécessitant un transfert de données en temps réel.
À la fin de ce didacticiel, vous serez en mesure de configurer votre propre serveur socket, d'envoyer et de recevoir des messages en temps réel, de stocker des données dans Redis et de déployer votre application lors du rendu et de l'exécution de Google Cloud.
Nous allons créer une application de chat. Pour faire court, nous allons uniquement configurer le serveur. Vous pouvez utiliser votre propre framework front-end et suivre.
Dans cette application de chat, il y aura des salles et les utilisateurs pourront rejoindre une salle et commencer à discuter. Pour que tout reste simple, nous supposerons que les noms d’utilisateur ne sont pas uniques. Cependant chaque salle ne peut avoir qu'un seul utilisateur avec un nom d'utilisateur spécifique.
Nous devons d'abord installer les dépendances requises.
npm i express cors socket.io -D @types/node
Nous utiliserons le module http pour configurer notre serveur socket. Puisque notre application fonctionnera dans le terminal, nous devrons autoriser toutes les origines.
import express from "express"; import cors from "cors" import { Server } from "socket.io"; import { createServer } from "http" const app = express(); const server = createServer(app); // create a socket server. const io = new Server(server, { cors: { origin: "*", credentials: true, } }); // listen to connections errors io.engine.on("connection_error", console.log) app.use(cors()) const PORT = 3000; server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Nous utiliserons Redis pour stocker nos messages ainsi que les informations sur la salle et les utilisateurs. Vous pouvez utiliser Upstash Redis (gratuit). Créez une nouvelle instance Redis dans votre tableau de bord Upstash. Après la création, vous recevrez une URL Redis que vous pourrez utiliser pour vous connecter à votre instance Redis.
Installez n'importe quel client Redis de votre choix. J'utiliserai ioredis.
npm i ioredis
Ensuite, nous allons initialiser notre client Redis et le connecter à notre serveur Redis en utilisant l'URL de connexion que nous avons obtenue.
/** /src/index.ts */ import { Redis } from "ioredis" if (!process.env.REDIS_URL) throw new Error("REDIS_URL env variable is not set"); const redis = new Redis(process.env.REDIS_URL); // listen to connection events. redis.on("connect", () => console.log("Redis connected")) redis.on("error", console.log)
Les utilisateurs peuvent créer des salles ou rejoindre des salles existantes. Les chambres sont identifiées par des identifiants de pièce uniques. Chaque membre possède un nom d'utilisateur qui est unique à l'intérieur d'une salle, et non globalement.
Nous pouvons garder une trace de toutes les salles actives sur notre serveur, en stockant leurs identifiants de salle dans un ensemble Redis.
Pour notre propos, les noms d'utilisateur ne sont uniques qu'à l'intérieur d'une pièce. Nous les stockons donc dans un ensemble avec l’identifiant de la pièce. Cela garantit que la combinaison de l'identifiant de la salle et de l'identifiant du membre est unique à l'échelle mondiale.
Nous pouvons configurer un événement socket pour créer une salle. Lorsque nous créons une salle, nous ajoutons également le membre qui a demandé sa création dans la salle.
io.on("connection", () => { // ... socket.on("create:room", async (message) => { console.log("create:room", message) const doesRoomExist = await redis.sismember("rooms", message.roomId) if (doesRoomExist === 1) return socket.emit("error", { message: "Room already exist."}) const roomStatus = await redis.sadd("rooms", message.roomId) const memStatus = await redis.sadd("members", message.roomId + "::" + message.username) if (roomStatus === 0 || memStatus === 0) return socket.emit("error", { message: "Room creation failed." }) socket.join(message.roomId) io.sockets.in(message.roomId).emit("create:room:success", message) io.sockets.in(message.roomId).emit("add:member:success", message) }) }
Pour ajouter un nouveau membre dans une salle existante, nous devons d'abord vérifier si le membre existe déjà dans cette salle.
io.on("connection", () => { // ... socket.on("add:member", async (message) => { console.log("add:member", message) const doesRoomExist = await redis.sismember("rooms", message.roomId) if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." }) const doesMemExist = await redis.sismember("members", message.roomId + "::" + message.username) if (doesMemExist === 1) return socket.emit("error", { message: "Username already exists, please choose another username." }) const memStatus = await redis.sadd("members", message.roomId + "::" + message.username) if (memStatus === 0) return socket.emit("error", { message: "User creation failed." }) socket.join(message.roomId) io.sockets.in(message.roomId).emit("add:member:success", message) }) socket.on("remove:member", async (message) => { console.log("remove:member", message) const doesRoomExist = await redis.sismember("rooms", message.roomId) if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." }) await redis.srem("members", message.roomId + "::" + message.username) socket.leave(message.roomId) io.sockets.in(message.roomId).emit("remove:member:success", message) }) }
Enfin, nous créons l'événement de chat.
io.on("connection", () => { socket.on("create:chat", (message) => { console.log("create:chat", message) redis.lpush("chat::" + message.roomId, message.username + "::" + message.message) io.sockets.in(message.roomId).emit("create:chat:success", message) }) }
Le serveur Socket nécessite des connexions persistantes, il ne fonctionnera pas dans des environnements sans serveur. Vous ne pouvez donc pas déployer votre serveur socket dans vercel.
Vous pouvez le déployer dans de nombreux endroits comme Render, fly.io ou Google Cloud Run.
Déploiement sur rendu simple. Si vous disposez d'un fichier docker, il construira automatiquement votre projet à partir de ce fichier docker. Le rendu a un niveau gratuit, mais gardez à l'esprit qu'il y aura un démarrage à froid dans le niveau gratuit.
Voici mon fichier docker.
# syntax=docker/dockerfile:1 ARG NODE_VERSION=20.13.1 ARG PNPM_VERSION=9.4.0 FROM node:${NODE_VERSION}-bookworm AS base ## set shell to bash SHELL [ "/usr/bin/bash", "-c" ] WORKDIR /usr/src/app ## install pnpm. RUN --mount=type=cache,target=/root/.npm \ npm install -g pnpm@${PNPM_VERSION} # ------------ FROM base AS deps # Download dependencies as a separate step to take advantage of Docker's caching. # Leverage a cache mount to /root/.local/share/pnpm/store to speed up subsequent builds. # Leverage bind mounts to package.json and pnpm-lock.yaml to avoid having to copy them # into this layer. RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \ --mount=type=cache,target=/root/.local/share/pnpm/store \ pnpm install --prod --frozen-lockfile # ----------- FROM deps AS build ## downloading dev dependencies. RUN --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \ --mount=type=cache,target=/root/.local/share/pnpm/store \ pnpm install --frozen-lockfile COPY . . RUN pnpm run build # ------------- FROM base AS final ENV NODE_ENV=production USER node COPY package.json . # Copy the production dependencies from the deps stage and also # the built application from the build stage into the image. COPY --from=deps /usr/src/app/node_modules ./node_modules COPY --from=build /usr/src/app/dist ./dist EXPOSE 3000 ENTRYPOINT [ "pnpm" ] CMD ["run", "start"]
Si vous souhaitez une alternative gratuite pour effectuer le rendu et éviter les démarrages à froid, vous devez utiliser Google Cloud Run. Les étapes de déploiement sur Cloud Run dépassent le cadre de cet article, mais voici une courte liste de choses que vous devez faire.
Créez votre image Docker à partir du fichier Docker fourni ci-dessous.
Créez un référentiel d'artefacts à l'aide du service Google Artifact Registry.
Renommez votre image Docker au format
Poussez votre image vers votre référentiel d'artefacts.
Déployez l'image sur Google Cloud Run. Assurez-vous de définir le nombre minimum d'instances actives sur une, pour éviter les démarrages à froid.
C'est tout pour ce tutoriel.
Merci d'avoir lu ❣️
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!