«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Создайте и разверните приложение чата с помощью Socket.io и Redis.

Создайте и разверните приложение чата с помощью Socket.io и Redis.

Опубликовано 7 ноября 2024 г.
Просматривать:475

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

В этом уроке мы создадим приложение чата с использованием веб-сокетов. Веб-сокеты действительно полезны, когда вы хотите создавать приложения, требующие передачи данных в реальном времени.

К концу этого руководства вы сможете настроить свой собственный сервер сокетов, отправлять и получать сообщения в режиме реального времени, хранить данные в Redis, а также развертывать свое приложение при рендеринге и запуске в облаке Google.

Что мы будем строить?

Мы будем создавать приложение для чата. Короче говоря, мы настроим только сервер. Вы можете использовать свою собственную интерфейсную структуру и следовать инструкциям.

В этом приложении чата будут комнаты, и пользователи смогут присоединиться к комнате и начать общаться. Для простоты будем считать, что имена пользователей не уникальны. Однако в каждой комнате может быть только один пользователь с определенным именем пользователя.

Настройте сервер сокетов.

Сначала нам нужно установить необходимые зависимости.

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 для хранения наших сообщений, а также информации о комнате и пользователях. Вы можете использовать Upstash Redis (бесплатно). Создайте новый экземпляр Redis на панели управления upstash. После создания вы получите URL-адрес Redis, который можно использовать для подключения к вашему экземпляру Redis.

Установите любой клиент Redis по вашему выбору. Я буду использовать ioredis.

npm i ioredis

Далее мы инициализируем наш клиент Redis и подключим его к нашему серверу Redis, используя полученный URL-адрес подключения.

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

Обработка событий.

Пользователи могут создавать комнаты или присоединяться к существующим комнатам. Комнаты идентифицируются по уникальным идентификаторам комнат. У каждого участника есть имя пользователя, уникальное внутри комнаты, а не глобально.

Мы можем отслеживать все активные комнаты на нашем сервере, сохраняя их идентификаторы комнат в наборе Redis.

Для нашей цели имена пользователей уникальны только внутри комнаты. Итак, мы сохраняем их в наборе вместе с идентификатором комнаты. Это гарантирует, что комбинация идентификатора комнаты и идентификатора участника будет уникальной во всем мире.

Мы можем настроить событие сокета для создания комнаты. Когда мы создаем комнату, мы также добавляем в комнату участника, запросившего ее создание.

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

Развертывание.

Сервер сокетов требует постоянных подключений, он не будет работать в бессерверных средах. Таким образом, вы не можете развернуть свой сокет-сервер в Верселе.

Вы можете развернуть его во многих местах, таких как Render, Fly.io или Google Cloud Run.

Оказывать

Простое развертывание при рендеринге. Если у вас есть файл докеров, он автоматически создаст ваш проект на основе этого файла докеров. У Render есть уровень бесплатного пользования, но имейте в виду, что на бесплатном уровне будет холодный запуск.

Вот мой файл докеров.

# 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"]
РАБОЧИЙ ДИАПАЗОН /usr/src/приложение ## установить pnpm. RUN --mount=type=cache,target=/root/.npm \ npm install -g pnpm@${PNPM_VERSION} # ------------ ИЗ базы данных AS # Загрузите зависимости как отдельный шаг, чтобы воспользоваться преимуществами кэширования Docker. # Используйте монтирование кеша в /root/.local/share/pnpm/store, чтобы ускорить последующие сборки. # Используйте привязку к package.json и pnpm-lock.yaml, чтобы избежать их копирования. # в этот слой. 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 # ----------- ИЗ deps AS сборки ## загрузка зависимостей разработчиков. 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 КОПИРОВАТЬ. . RUN pnpm запустить сборку # ------------- ИЗ базы AS окончательный ENV NODE_ENV=производство Узел ПОЛЬЗОВАТЕЛЬ КОПИРУЙТЕ пакет.json. # Скопируйте производственные зависимости со стадии deps, а также # встроенное приложение из этапа сборки в образ. КОПИЯ --from=deps /usr/src/app/node_modules ./node_modules КОПИЯ --from=build /usr/src/app/dist ./dist ЭКСПОЗИЦИЯ 3000 ТОЧКА ВХОДА

CMD ["запустить", "запустить"]

Google Cloud Run

    Если вам нужна бесплатная альтернатива для рендеринга и предотвращения холодного запуска, вам следует использовать Google Cloud Run. Действия по развертыванию в облаке выходят за рамки этой статьи, но вот краткий список того, что вам нужно сделать.
  1. Создайте образ Docker из файла Docker, представленного ниже.
  2. Создайте хранилище артефактов с помощью службы реестра артефактов Google.
  3. Переименуйте образ docker в формате -docker.pkg.dev//:
  4. Отправьте изображение в хранилище артефактов.
  5. Разверните образ в Google Cloud Run. Обязательно установите минимальное количество активных экземпляров равным одному, чтобы избежать холодного запуска.

Вот и все, что касается этого урока.

Спасибо, что прочитали ❣️

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

Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/sammaji/build-and-deploy-a-chat-application-using-socketio-and-redis-438f?1 Если есть какие-либо нарушения, пожалуйста, свяжитесь с Study_golang@163. .com, чтобы удалить его
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3