#include #include #include #include #include "config.hpp" #include "spdlog/spdlog.h" #include #include #include #include #include #include #include #include #include namespace ranczo { struct SingleShootTimer::Impl { private: std::chrono::milliseconds _timeout; boost::asio::steady_timer _timer; std::function< void() > _callback; public: Impl(boost::asio::any_io_executor & io_context, std::chrono::milliseconds timeout, std::function< void() > cb) : _timeout{timeout}, _timer(io_context, _timeout), _callback{std::move(cb)} {} // Coroutine function to handle the timer expiration boost::asio::awaitable< void > timerCoroutine() { assert(_callback); try { while(true) { // call my callback _callback(); // Wait for the timer to expire co_await _timer.async_wait(boost::asio::use_awaitable); } } catch(const std::exception & e) { spdlog::error("Error: {}", e.what()); } } awaitable_expected< void > start() { spdlog::trace("co_spawn timer"); // Start the coroutine by invoking the timerCoroutine() with boost::asio::co_spawn boost::asio::co_spawn(_timer.get_executor(), timerCoroutine(), boost::asio::detached); co_return expected< void, boost::system::error_code >{}; } }; SingleShootTimer::SingleShootTimer(executor & executor, std::chrono::milliseconds timeout, std::function< void() > cb) : _impl{std::make_unique< Impl >(executor, timeout, std::move(cb))} {} SingleShootTimer::~SingleShootTimer() = default; awaitable_expected SingleShootTimer::start() const { assert(_impl); ASYNC_CHECK(_impl->start()); co_return expected< void, boost::system::error_code >{}; } struct PeriodicTimer::Impl { private: std::chrono::milliseconds _interval; boost::asio::steady_timer _timer; std::function< void() > _callback; public: Impl(boost::asio::any_io_executor & io_context, std::chrono::milliseconds interval, std::function< void() > cb) : _interval{interval}, _timer(io_context, _interval), _callback{std::move(cb)} {} // Coroutine function to handle the timer expiration boost::asio::awaitable< void > timerCoroutine() { assert(_callback); try { while(true) { // call my callback _callback(); // Wait for the timer to expire co_await _timer.async_wait(boost::asio::use_awaitable); // Reset the timer for the next interval _timer.expires_after(_interval); } } catch(const std::exception & e) { spdlog::error("Error: {}", e.what()); } } awaitable_expected< void > start() { spdlog::trace("co_spawn timer"); // Start the coroutine by invoking the timerCoroutine() with boost::asio::co_spawn boost::asio::co_spawn(_timer.get_executor(), timerCoroutine(), boost::asio::detached); co_return expected< void, boost::system::error_code >{}; } }; PeriodicTimer::PeriodicTimer(executor & executor, std::chrono::milliseconds period, std::function< void() > cb) : _impl{std::make_unique< Impl >(executor, period, std::move(cb))} {} awaitable_expected PeriodicTimer::start() const { BOOST_ASSERT(_impl); ASYNC_CHECK(_impl->start()); co_return expected< void, boost::system::error_code >{}; } PeriodicTimer::~PeriodicTimer() = default; } // namespace ranczo