LCOV - code coverage report
Current view: top level - http/client - executor_client.hpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 5 5
Test Date: 2026-11-10 10:38:07 Functions: 100.0 % 3 3

            Line data    Source code
       1              : #ifndef THINGER_HTTP_CLIENT_EXECUTOR_CLIENT_HPP
       2              : #define THINGER_HTTP_CLIENT_EXECUTOR_CLIENT_HPP
       3              : 
       4              : #include "http_client_base.hpp"
       5              : #include "request_builder.hpp"
       6              : #include "../../asio/io_context_of.hpp"
       7              : #include <boost/asio/io_context.hpp>
       8              : #include <memory>
       9              : #include <optional>
      10              : #include <string>
      11              : 
      12              : namespace thinger::http {
      13              : 
      14              : /**
      15              :  * An HTTP client running on an io_context the caller already runs, e.g. the IO thread of the
      16              :  * coroutine using it (see for_current_coroutine()): no threads of its own, no idle timers, and
      17              :  * its connections are closed when it is destroyed. Requests are awaited (as with async_client),
      18              :  * and run on that io_context: no hop to another thread.
      19              :  *
      20              :  * Meant for occasional calls from server coroutines (a token refresh, a webhook, an order),
      21              :  * far apart: it keeps no idle connection by default, so each request opens its own. For many
      22              :  * calls to the same host, use a pooled client (async_client); max_idle_connections_per_host()
      23              :  * enables keep-alive here too, closing expired connections when the next request comes.
      24              :  *
      25              :  * Use it on the threads running the io_context, as its sockets (e.g. from a coroutine on it or
      26              :  * on a strand of it), and destroy it there, before the io_context. Cancelling the coroutine
      27              :  * awaiting a request (a cancellation slot, or `||` with a timer) cancels the request.
      28              :  *
      29              :  * WebSockets opened through it run on the executor of the caller, its strand included: their
      30              :  * keepalive and closing handshake never run at the same time as the caller.
      31              :  *
      32              :  * Usage:
      33              :  *   server.get("/weather", [](http::response& res) -> thinger::awaitable<void> {
      34              :  *       auto client = co_await http::executor_client::for_current_coroutine();
      35              :  *       auto forecast = co_await client->get("https://api.example.com/forecast");
      36              :  *       res.json(forecast.json());
      37              :  *   });
      38              :  */
      39              : class executor_client : public http_client_base {
      40              : public:
      41              :     explicit executor_client(boost::asio::io_context& io_context);
      42              :     // The idle connections (if any) are closed while their io_context exists
      43              :     ~executor_client() override;
      44              : 
      45              :     executor_client(const executor_client&) = delete;
      46              :     executor_client& operator=(const executor_client&) = delete;
      47              : 
      48              :     // A client on the io_context of the calling coroutine (see asio::io_context_of()): its
      49              :     // worker's in a coroutine of async_client::run(). Throws std::logic_error if the
      50              :     // coroutine runs on another kind of executor (e.g. a thread_pool)
      51              :     static awaitable<std::unique_ptr<executor_client>> for_current_coroutine();
      52              : 
      53              :     /**
      54              :      * Create a request builder for fluent API.
      55              :      *
      56              :      * Usage:
      57              :      *   auto res = co_await client.request("https://api.com/data")
      58              :      *       .header("Authorization", "Bearer xxx")
      59              :      *       .get();
      60              :      */
      61            3 :     request_builder<executor_client> request(const std::string& url) {
      62            3 :         return request_builder<executor_client>(this, url);
      63              :     }
      64              : 
      65              :     // Connect to a WebSocket server (its socket runs on the same io_context)
      66           87 :     awaitable<std::optional<websocket_client>> websocket(const std::string& url,
      67              :                                                          const std::string& subprotocol = "") {
      68           87 :         return upgrade_websocket(url, subprotocol);
      69              :     }
      70              : 
      71              :     // With a request of its own (for the request builder)
      72              :     awaitable<std::optional<websocket_client>> websocket(std::shared_ptr<http_request> request,
      73              :                                                          const std::string& subprotocol = "") {
      74              :         return upgrade_websocket(std::move(request), subprotocol);
      75              :     }
      76              : 
      77              : protected:
      78          231 :     boost::asio::io_context& get_io_context() override { return io_context_; }
      79              : 
      80              : private:
      81              :     boost::asio::io_context& io_context_;
      82              : };
      83              : 
      84              : } // namespace thinger::http
      85              : 
      86              : #endif // THINGER_HTTP_CLIENT_EXECUTOR_CLIENT_HPP
        

Generated by: LCOV version 2.0-1