481. В потоке

Не решаласьСредняя

Однажды один талантливый программист написал чат-бота. И всё было прекрасно, пока чат-ботом пользовался только он. Но когда он поделился ссылкой с друзьями — начался кошмар. Сообщения летели беспорядочно. Отправка сообщения не гарантировала, что оно отправится нужному человеку. Друзья стали получать чужие сообщения и начали догадываться: что-то тут не так. У вас ещё есть время! Помогите навести порядок, чтобы сообщения нашли своих получателей.

  • Нужно написать клиент, который бы отображал полученные в чатах сообщения.
  • Код будет выполняться в браузерной вкладке.
  • Код должен уметь работать в нескольких вкладках, и все данные должны быть синхронизированы между вкладками.
  • Новые сообщения приходят с сервера в виде апдейтов. Апдейт содержит информацию о новом, отредактированном или удалённом сообщении.
  • Для неактивной вкладки callback не вызывается, но все сообщения должны быть отображены на всех вкладках.
  • Для отображения сообщений используйте функцию renderMessages, передавая ей все сообщения чата (вызывать можно в любой момент, так как функция перерендерит список).
  • Каждый апдейт имеет уникальный ID, начиная с 1 для первого апдейта и с последующим увеличением на 1 для каждого следующего апдейта.
  • Сервер не гарантирует правильного порядка апдейтов, но клиент должен применять их в порядке возрастания номера ID.

Формат ввода

Апдейты идут потоком с сервера:

type Update = {
    id: number; // ID апдейта. Нужно применять в порядке увеличения ID.
    type: 'new' | 'updated' | 'deleted'; // Тип апдейта.
    message: Message; // Сообщение.
}

type Message = {
    id: number; // ID сообщения.
    chatId: number; // ID чата, в который пришло сообщение.
    body?: string; // Тело сообщения. Поле body отсутствует в update'ах, где type: 'deleted'.
};

У апдейтов разный статус:

  • new — пришло новое сообщение;
  • updated — обновить текущее сообщение;
  • deleted — удалить сообщение.

Вам дан класс Chat:

  • напишите функцию, которая будет передана как callback в класс;
  • функция должна вызывать renderMessages.
class Chat {
    #socket = new WebSocket("ws://localhost:8081");

    constructor(callback) {
        this.#socket.onmessage = (event) => {
            const incomingMessage = JSON.parse(event.data);

            // Update
            callback(incomingMessage)
        };
    }

    // {[chatId: number]: Message[]}
    renderMessages(messages) {
        console.log(JSON.stringify(messages))
    }
}

Ваше решение должно быть выполнено на JavaScript и должно выглядеть следующим образом (копировать класс Chat в решение не нужно, оставьте только инициализацию):

// Вспомогательный код (если нужен).

function callback() {
    // Ваше решение.
}

// Инициализация класса чата с вашим колбэком.
const chat = new Chat(callback)

Запускаться ваше решение будет в браузере с Chromium.

Формат вывода

Функция renderMessage ожидает: {[chatId: number]: Message[]}

Сгруппированные по chatId сообщения:

{
  ...
  chatId: [
     {id, chatId, body},
     {id, chatId, body}
  ]
}

Пример:

Сервер отправляет сообщения:

{"data":[
    {"id":3,"type":"deleted","message":{"id":2,"chatId":1}},
    {"id":1,"type":"new","message":{"id":1,"chatId":1,"body":"Text-1"}},
    {"id":4,"type":"updated","message":{"id":1,"chatId":1,"body":"Text-1 updated"}},
    {"id":2,"type":"new","message":{"id":2,"chatId":1,"body":"Text-10"}}
]}

Клиент получает их и рендерит (фиксируется последний отрендеренный результат):

{
"1": [
      {
        "id": 1,
        "chatId": 1,
        "body": "Text-1 updated"
      }
    ]
}

Примечание

  • Ваше решение будет запускаться в браузере под Chromium.
  • По ссылке находится playground (чтоб упростить дебаг).

Ограничения

Ограничение времени

15 с

Ограничение памяти

640 МБ

Теги

JavaScript Node.js 20.14 + Chrome 125
Нужно войти, чтобы отправить решение.Войти