503. Уведомления

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

Марк разрабатывает свой мессенджер.

Сейчас он хочет добавить новую фичу — саммари уведомлений. Вместо того чтобы получать уведомление каждый раз, когда приходит сообщение — можно будет переключить в настройках режим «Уведомления: саммари» и получать один пуш раз в какое-то время. В нём будет информация об уведомлениях за последнее время: количество уведомлений или просто все сообщения вместе — Марк пока не решил. Также он задумывается, что пользователям, которые купили платную подписку, можно будет отправлять краткую выжимку из всех новых сообщений, прогнав их через нейросеть.

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

Таким образом, если он установит таймаут в 4000мс на чат со своим другом Джеффом и тот отправит Марку 4 сообщения с интервалом в одну секунду (вероятно что-то срочное, возможно он просит Марка установить приложение своего маркетплейса на телефон) — Марк ожидает получить одно уведомление через 7 секунд после первого сообщения Джеффа.

Вместе с этим ещё нужно уметь работать с несколькими чатами: Марк ставит таймаут в 10 секунд на чат с Илоном — ещё одним хорошим его другом. И в случае, если Илон отправит сообщение, а через 8 секунд после этого напишет Джефф, Марк ожидает получить уведомление через 12 секунд после сообщения Илона.

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

Марк просит вас помочь написать ему функцию, которая будет реализовывать эту функциональность в таком виде:

type OnMessage<T> = (message: T) => void;
type AddTimeout<T> = (chatName: string, timeoutMs: number) => OnMessage<T>;
type RemoveTimeout = (chatName: string) => void;
type SummaryFn<T> = (data: Record<string, T>) => void;

function solution<T>(
    sendNotification: SummaryFn<T>
): [AddTimeout<T>, RemoveTimeout<T>] {
    // your code here
}

Ваша функция получает колбэк sendNotification, который будет вызван по истечении всех таймаутов, и возвращает массив с двумя элементами: функциями установки и удаления таймаута на чат.

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

Функция удаления таймаута принимает просто название чата и ничего не возвращает.

Обратите внимание, что в колбэк, с которым мы проинициализировали решение (sendNotification), должен передаваться объект, ключами которого будут названия чатов, а соответствующим значением для каждого ключа будет сообщение, которое передавалось в последний раз в колбэк onMessage для этого чата.

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

Если мы удаляем таймаут с какого-то из чатов, информация о нём не должна попасть в итоговый вызов sendNotification, даже если для этого чата уже запущен таймер.

Пример использования функции:

const [add, remove] = solution((data) => console.log(data));
const onMessageJeff = add("Jeff", 4000);
const onMessageElon = add("Elon", 10000);

/* time (ms)    */
/* 0            */ onMessageJeff("hello from Jeff");
/* 2000         */ onMessageElon("hello from Elon");
/* 4000         */ // Закончился таймер от Джеффа, но ещё идёт таймер от Илона, ждём
/* 10000        */ onMessageJeff("pls dont ignore me");
/* 12000        */ // Закончился таймер Илона, но ещё идёт второй таймер Джеффа, ждём
/* 14000        */ // Закончились все таймеры, выводим в консоль 
                   // { Jeff: 'pls dont ignore me', Elon: 'hello from Elon' }

/* 20000        */ onMessageJeff("hello again from Jeff");
/* 22000        */ onMessageElon("hello again from Elon");
/* 23000        */ remove("Elon"); // Удалили таймер с чата Илона
/* 24000        */ // Закончился таймер Джеффа, выводим в консоль 
                   // { Jeff: 'hello again from Jeff' }
/* 32000        */ // Закончился бы таймер Илона, но мы его удалили, ничего не происходит

Для отладки кода вы можете скачать песочницу:

https://disk.yandex.ru/d/Gdl0qn2y2U4I3w

Отправлять решение следует в таком формате на языке JavaScript:

function solution(callback) {
    // your code here
}

module.exports = solution;

(не отправляйте код песочницы!)

Ограничения

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

1 с

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

64 МБ

Теги

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