ホームページ >ウェブフロントエンド >jsチュートリアル >Socket.io と Redis を使用してチャット アプリケーションを構築し、デプロイします。

Socket.io と Redis を使用してチャット アプリケーションを構築し、デプロイします。

王林
王林オリジナル
2024-08-26 21:40:32540ブラウズ

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

このチュートリアルでは、Web ソケットを使用してチャット アプリケーションを構築します。 Web ソケットは、リアルタイムのデータ転送が必要なアプリケーションを構築する場合に非常に役立ちます。

このチュートリアルが終わるまでに、独自のソケット サーバーをセットアップし、リアルタイムでメッセージを送受信し、Redis にデータを保存し、レンダリングと Google Cloud 実行でアプリケーションをデプロイできるようになります。

何を構築するのでしょうか?

チャット アプリケーションを構築します。簡潔にするために、サーバーのセットアップのみを行います。独自のフロントエンド フレームワークを使用して、これに従うことができます。

このチャット アプリケーションにはルームがあり、ユーザーはルームに参加してチャットを開始できます。すべてを単純にするために、ユーザー名は一意ではないと仮定します。ただし、各ルームに特定のユーザー名を持つユーザーは 1 人だけです。

ソケットサーバーをセットアップします。

まず、必要な依存関係をインストールする必要があります。

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

http モジュールを使用してソケット サーバーをセットアップします。アプリはターミナルで実行されるため、すべてのオリジンを許可する必要があります。

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

Redis のセットアップ。

ルームとユーザーの情報とともにメッセージを保存するために Redis を使用します。 upstash redis (無料) を使用できます。 Upstash ダッシュボードで新しい Redis インスタンスを作成します。作成後、Redis インスタンスへの接続に使用できる Redis URL を受け取ります。

選択した Redis クライアントをインストールします。 ioredis を使用します。

npm i ioredis

次に、Redis クライアントを初期化し、取得した接続 URL を使用して Redis サーバーに接続します。

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

イベントの処理。

ユーザーはルームを作成したり、既存のルームに参加したりできます。ルームは一意のルーム ID によって識別されます。各メンバーには、グローバルではなくルーム内で一意のユーザー名があります。

ルーム ID を Redis セット内に保存することで、サーバー内のすべてのアクティブなルームを追跡できます。

私たちの目的上、ユーザー名はルーム内でのみ一意です。したがって、それらをルーム ID とセットで保存します。これにより、ルーム ID とメンバー ID の組み合わせがグローバルに一意になることが保証されます。

ルームを作成するためのソケットイベントを設定できます。ルームを作成すると、その作成をリクエストしたメンバーもルームに追加されます。

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

既存のルームに新しいメンバーを追加するには、まずメンバーがそのルームに既に存在するかどうかを確認する必要があります。

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

最後に、チャット イベントを作成します。

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

展開。

ソケットサーバーには永続的な接続が必要です。サーバーレス環境では機能しません。したがって、vercel にソケット サーバーをデプロイすることはできません。

Render、fly.io、Google Cloud Run などのさまざまな場所にデプロイできます。

与える

レンダーシンプルでのデプロイ。 dockerfile がある場合は、その dockerfile からプロジェクトが自動的にビルドされます。 Render には無料利用枠がありますが、無料利用枠ではコールド スタートが行われることに注意してください。

これが私の dockerfile です。

# 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クラウドラン

レンダリングしてコールド スタートを回避するための無料の代替手段が必要な場合は、Google Cloud Run を使用する必要があります。 Cloud Run にデプロイする手順はこの記事の範囲を超えていますが、行う必要があることの短いリストを次に示します。

  1. 以下に提供される dockerfile から docker イメージを構築します。

  2. Google Artifact Registry サービスを使用してアーティファクト リポジトリを作成します。

  3. Docker イメージの名前を -docker.pkg.dev//:

  4. 画像をアーティファクト リポジトリにプッシュします。

  5. イメージを Google Cloud Run にデプロイします。コールド スタートを避けるために、アクティブなインスタンスの最小数を 1 に設定してください。

このチュートリアルは以上です。

読んでいただきありがとうございます❣️

以上がSocket.io と Redis を使用してチャット アプリケーションを構築し、デプロイします。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。