#pragma once #include #include "common.hpp" #include "components/logger.hpp" LEMONBUDDY_NS namespace throttle_util { using timewindow = chrono::duration; using timepoint_clock = chrono::high_resolution_clock; using timepoint = timepoint_clock::time_point; using queue = std::deque; using limit = size_t; namespace strategy { struct try_once_or_leave_yolo { bool operator()(queue& q, limit l, timewindow); }; struct wait_patiently_by_the_door { bool operator()(queue& q, limit l, timewindow); }; } /** * Throttle events within a set window of time * * Example usage: * @code cpp * auto t = throttle_util::make_throttler(2, 1s); * if (t->passthrough()) * ... * @endcode */ class event_throttler { public: /** * Construct throttler */ explicit event_throttler(int limit, timewindow timewindow) : m_limit(limit), m_timewindow(timewindow) {} /** * Check if event is allowed to pass * using specified strategy */ template bool passthrough(Strategy wait_strategy) { expire_timestamps(); return wait_strategy(m_queue, m_limit, m_timewindow); } /** * Check if event is allowed to pass * using default strategy */ bool passthrough() { return passthrough(strategy::try_once_or_leave_yolo{}); } protected: /** * Expire old timestamps */ void expire_timestamps() { auto now = timepoint_clock::now(); while (m_queue.size() > 0) { if ((now - m_queue.front()) < m_timewindow) break; m_queue.pop_front(); } } private: queue m_queue; limit m_limit; timewindow m_timewindow; }; using throttle_t = unique_ptr; template throttle_t make_throttler(Args&&... args) { return make_unique(forward(args)...); } } LEMONBUDDY_NS_END