Rumah >hujung hadapan web >tutorial js >Bina dan gunakan aplikasi sembang menggunakan Socket.io dan Redis.

Bina dan gunakan aplikasi sembang menggunakan Socket.io dan Redis.

王林
王林asal
2024-08-26 21:40:32538semak imbas

Build and deploy a chat application using Socket.io and Redis.

Dalam tutorial ini, kami akan membina aplikasi sembang menggunakan soket web. Soket web sangat berguna apabila anda ingin membina aplikasi yang memerlukan pemindahan data masa nyata.

Menjelang akhir tutorial ini, anda akan dapat menyediakan pelayan soket anda sendiri, menghantar dan menerima mesej dalam masa nyata, menyimpan data dalam Redis dan menggunakan aplikasi anda pada render dan google cloud run.

Apa yang akan kita bina?

Kami akan membina aplikasi sembang. Untuk memastikan ia pendek, kami hanya akan menyediakan pelayan. Anda boleh menggunakan rangka kerja bahagian hadapan anda sendiri dan ikut serta.

Dalam aplikasi sembang ini, akan ada bilik dan pengguna boleh menyertai bilik dan mula bersembang. Untuk memastikan semuanya mudah, kami akan menganggap nama pengguna tidak unik. Walau bagaimanapun, setiap bilik hanya boleh mempunyai seorang pengguna dengan nama pengguna tertentu.

Sediakan pelayan soket.

Mula-mula kita perlu memasang kebergantungan yang diperlukan.

npm i express cors socket.io -D @types/node

Kami akan menggunakan modul http untuk menyediakan pelayan soket kami. Memandangkan apl kami akan dijalankan di terminal, kami perlu membenarkan semua asal.

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}`));

Menyediakan Redis.

Kami akan menggunakan redis untuk menyimpan mesej kami bersama-sama dengan bilik dan maklumat pengguna. Anda boleh menggunakan upstash redis (percuma). Buat contoh redis baharu dalam papan pemuka atas anda. Selepas penciptaan anda akan menerima url redis yang boleh anda gunakan untuk menyambung ke tika redis anda.

Pasang mana-mana pelanggan redis pilihan anda. Saya akan menggunakan ioredis.

npm i ioredis

Seterusnya, kami akan memulakan klien redis kami dan menyambungkannya ke pelayan redis kami menggunakan url sambungan yang kami dapat.

/** /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)

Mengendalikan acara.

Pengguna boleh membuat bilik atau menyertai bilik sedia ada. Bilik dikenal pasti dengan id bilik unik. Setiap ahli mempunyai nama pengguna yang unik di dalam bilik, dan bukan secara global.

Kami boleh menjejaki semua bilik aktif dalam pelayan kami, dengan menyimpan id bilik mereka di dalam set redis.

Untuk tujuan kami, nama pengguna hanya unik di dalam bilik. Jadi, kami menyimpannya dalam satu set bersama id bilik. Ini memastikan gabungan id bilik bersama id ahli adalah unik di seluruh dunia.

Kami boleh menyediakan acara soket untuk mencipta bilik. Apabila kami membuat bilik, kami turut menambahkan ahli yang meminta penciptaannya ke dalam bilik.

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)
  })
}

Untuk menambah ahli baharu ke dalam bilik sedia ada, kami perlu menyemak dahulu sama ada ahli itu sudah wujud dalam bilik itu.

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)
      })
}

Akhir sekali, kami mencipta acara sembang.

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)
  })
}

Kerahan.

Pelayan soket memerlukan sambungan berterusan, ia tidak akan berfungsi dalam persekitaran tanpa pelayan. Jadi anda tidak boleh menggunakan pelayan soket anda dalam vercel.

Anda boleh mengaturkannya di banyak tempat seperti Render, fly.io atau Google Cloud Run.

Render

Menggunakan pada pemaparan mudah. Jika anda mempunyai fail docker, ia akan membina projek anda secara automatik daripada fail docker itu. Render mempunyai peringkat percuma, tetapi perlu diingat bahawa akan ada permulaan sejuk dalam peringkat percuma.

Inilah fail docker saya.

# 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"]

Google Cloud Run

Jika anda mahukan alternatif percuma untuk dipaparkan dan mengelakkan permulaan sejuk, anda harus menggunakan Google Cloud Run. Langkah-langkah untuk menggunakan cloud run adalah di luar skop artikel ini, tetapi berikut ialah senarai pendek perkara yang perlu anda lakukan.

  1. Bina imej docker anda daripada fail docker yang disediakan di bawah.

  2. Buat repositori artifak menggunakan perkhidmatan Google Artifact Registry.

  3. Namakan semula imej docker anda ke dalam format -docker.pkg.dev//:

  4. Tolak imej anda ke repositori artifak anda.

  5. Letakkan imej ke Google Cloud Run. Pastikan untuk menetapkan kejadian aktif minimum kepada satu, untuk mengelakkan permulaan sejuk.

Itu sahaja untuk tutorial ini.

Terima kasih kerana membaca ❣️

Atas ialah kandungan terperinci Bina dan gunakan aplikasi sembang menggunakan Socket.io dan Redis.. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn