#pragma once
#include <chrono>
#include <cstddef>
#include <memory>
#include <mutex>
#include <stop_token>
#include <vector>
#include <type_traits>
#include <mw/http_client_async.hpp>
#include "detail/blocking_pool.hpp"
#include "detail/started_task.hpp"
namespace agent_smith::internal
{
class TimerService;
struct BackgroundTasks;
}
namespace agent_smith
{
/// Configuration shared by Agent Smith's runtime services.
struct RuntimeConfig
{
/// Number of workers reserved for future non-HTTP blocking work.
std::size_t blocking_pool_size = 4;
/// Maximum time allowed to establish an HTTP connection.
std::chrono::seconds connection_timeout{60};
/// Maximum time allowed for an HTTP transfer.
std::chrono::seconds transfer_timeout{60};
};
/// Owns the shared asynchronous HTTP session used by Agent Smith clients.
class Runtime
{
public:
/// Construct a runtime using the supplied shared-service configuration.
explicit Runtime(RuntimeConfig cfg = {});
/// Drain retained tool work, then release runtime resources.
/// A non-cooperative timed-out tool can delay shutdown until it finishes.
~Runtime();
Runtime(const Runtime&) = delete;
Runtime& operator=(const Runtime&) = delete;
Runtime(Runtime&&) = delete;
Runtime& operator=(Runtime&&) = delete;
/// Return the shared asynchronous HTTP session.
mw::HTTPSessionAsync& http();
/// Run non-HTTP work on the internal worker pool.
template <typename F>
auto runOnWorker(F&& function)
-> mw::Task<internal::ExpectedResult<std::invoke_result_t<F&>>>;
/// Suspend without blocking the caller's coroutine thread.
mw::Task<mw::E<void>> sleepFor(std::chrono::milliseconds duration);
/// Suspend until the duration elapses or stop is requested.
/// An early wake is successful; inspect the token to distinguish it.
mw::Task<mw::E<void>> sleepFor(std::chrono::milliseconds duration,
std::stop_token stop);
private:
friend struct internal::BackgroundTasks;
void retain(internal::StartedTask<void> task);
RuntimeConfig cfg_;
std::unique_ptr<mw::HTTPSessionAsync> http_;
std::unique_ptr<internal::BlockingPool> blocking_pool_;
std::unique_ptr<internal::TimerService> timer_service_;
std::mutex background_mutex_;
std::vector<internal::StartedTask<void>> background_tasks_;
};
template <typename F>
auto Runtime::runOnWorker(F&& function)
-> mw::Task<internal::ExpectedResult<std::invoke_result_t<F&>>>
{
co_return co_await blocking_pool_->run(std::forward<F>(function));
}
} // namespace agent_smith