#include "agent_smith/runtime.hpp"
#include "detail/timer_service.hpp"
#include "agent_smith/detail/gather_all.hpp"
#include "agent_smith/sync_wait.hpp"
#include <algorithm>
namespace agent_smith
{
Runtime::Runtime(RuntimeConfig cfg)
: cfg_(cfg), http_(std::make_unique<mw::HTTPSessionAsync>()),
blocking_pool_(std::make_unique<internal::BlockingPool>(
cfg_.blocking_pool_size)),
timer_service_(std::make_unique<internal::TimerService>())
{
auto& http = static_cast<mw::HTTPSessionAsyncInterface&>(*http_);
[[maybe_unused]] auto connection_timeout =
http.connectionTimeout(cfg_.connection_timeout);
[[maybe_unused]] auto transfer_timeout =
http.transferTimeout(cfg_.transfer_timeout);
}
Runtime::~Runtime()
{
// Keep HTTP, workers, and timers alive until timed-out work finishes.
// A background operation may itself register additional work.
for(;;)
{
std::vector<internal::StartedTask<void>> pending;
{
std::lock_guard lock(background_mutex_);
pending.swap(background_tasks_);
}
if(pending.empty())
{
break;
}
[[maybe_unused]] auto results =
syncWait(internal::gatherAllStarted(std::move(pending)));
}
http_.reset();
}
void Runtime::retain(internal::StartedTask<void> task)
{
std::lock_guard lock(background_mutex_);
std::erase_if(background_tasks_,
[](const auto& item) { return item.complete(); });
background_tasks_.push_back(std::move(task));
}
mw::HTTPSessionAsync& Runtime::http()
{
return *http_;
}
mw::Task<mw::E<void>> Runtime::sleepFor(std::chrono::milliseconds duration)
{
co_return co_await sleepFor(duration, {});
}
mw::Task<mw::E<void>> Runtime::sleepFor(std::chrono::milliseconds duration,
std::stop_token stop)
{
if(duration < std::chrono::milliseconds::zero())
{
co_return std::unexpected(
mw::runtimeError("sleep duration cannot be negative"));
}
co_await timer_service_->sleepFor(duration, stop);
co_return mw::E<void>{};
}
} // namespace agent_smith