У меня есть функция, которая упоминалась в одном из моих предыдущих вопросов: Функция для расчета того, как часто пользователи нажимают кнопку
void onNewButtonPress(int64_t nanoseconds_timestamp, int32_t user_id);
Эта функция будет вызываться каждый раз пользователь с user_id нажимает кнопку. Где параметр nanoseconds_timestamp - это время в наносекундах с начала эпохи.
Моя задача - выполнить проверку ограничения скорости для каждого пользователя. У каждого пользователя свой лимит кликов. Предел скорости для каждого пользователя может быть получен с помощью следующей функции:
const struct rate_limit* getLimit(uint32_t userId);
getlimit вернет указатель на структуру Rate_limit
struct rate_limit
{
uint32_t max;
uint32_t milliseconds;
};
Где max - максимальное количество кликов, сделанных пользователем может составлять в интервале миллисекунд значение. Например, если max = 400 и миллисекунды = 200, то пользователь может сделать только 400 кликов в интервале 200 мс.
Когда пользователь нарушает ограничение, функция должна сообщить об этом, используя функцию отчета с прототипом следующим образом.
void report(uint32_t user_id);
Как бы вы, ребята, определяли, когда пользователь нарушает свой лимит. Ниже мое решение с комментариями. Я по-прежнему считаю, что может быть гораздо более умное и лучшее решение, и хотел бы услышать ваше мнение.
Детали моей реализации следующие
Я создал структуру, которая будет содержать информацию о каждой истории пользователя .
struct UserTrackingInfo
{
/* Limit which is returned when a user clicks for the first time */
const rate_limit* limit;
/* Variable which will get incremented each time a user is making a click */
uint32_t breachCount{0};
/* Timestamp in nanoseconds of when breachPeriod started. Whenever a user clicks for the first time
* this timestamp will be initialized
* Time will be sliced in breach periods whose duration is equal to the max of the rate_limit */
uint64_t breachPeriodStartTs{0};
};
Я создал карту, где ключом является user_id, а значением - UserTrackingInfo
std::map<int32_t, struct UserTrackingInfo > tInfo;
Это моя предлагаемая реализация функции onNewButtonPress.
void onNewButtonPress(uint64_t& nanoseconds_timestamp, int32_t user_id)
{
auto &tref = tInfo[user_id];
if (tref.breachPeriodStartTs == 0){
/* if a user hasnt clicked before, get the limit for the user and initialize a breach period start time stamp */
tref.limit = getLimit(user_id);
tref.breachPeriodStartTs = nanoseconds_timestamp;
}
else
{
/* Increment how many times used clicked a button */
tref.breachCount++;
/* Get number of ns passed since the time when last period started */
int64_t passed = nanoseconds_timestamp - tref.breachPeriodStartTs;
/* If we reached a limit, report it */
if (passed < (tref.limit->milliseconds * 1000)){
if (tref.breachCount > tref.limit->max){
report(user_id);
}
/* we dont start a new period yet */
}
else{
/* If the limit hasnt been reached yet */
/* User may have pressed after the end of the breach period. Or he didnt make any clicks for the duration of a couple of breach periods */
/* Find number of breach measure periods that may have been missed */
uint64_t num_periods = passed / (tref.limit->milliseconds * 1000);
/* Get duration of the passed periods in nanoseconds */
uint64_t num_periods_ns = num_periods * (tref.limit->milliseconds * 1000);
/* Set the the start time of the current breach measure period */
/* and reset breachCount */
tref.breachPeriodStartTs = tref.breachPeriodStartTs + num_periods_ns;
tref.breachCount = 1;
}
}
}