Line data Source code
1 : #include "server_standalone.hpp"
2 : #include "../../util/logger.hpp"
3 : #include <future>
4 :
5 : namespace thinger::http {
6 :
7 8871 : server::server() {
8 8871 : LOG_DEBUG("Created standalone HTTP server (single-threaded)");
9 : // The end of a shutdown stops the io_context, without calling stop() (see
10 : // set_shutdown_stop())
11 9521 : set_shutdown_stop([this] { stop_running(); });
12 8871 : }
13 :
14 8883 : server::~server() {
15 8871 : LOG_DEBUG("Destroying standalone HTTP server");
16 8871 : stop();
17 8883 : }
18 :
19 720 : boost::asio::io_context* server::shutdown_context() {
20 720 : return running_ && serving_ ? &io_context_ : nullptr;
21 : }
22 :
23 267 : bool server::in_server_thread() {
24 267 : return io_context_.get_executor().running_in_this_thread();
25 : }
26 :
27 :
28 8619 : std::unique_ptr<asio::listener> server::create_listener(asio::listener_options options) {
29 : // Both accepting and the connections on our io_context
30 38587 : auto executor = [this]() -> boost::asio::any_io_executor { return io_context_.get_executor(); };
31 17238 : return std::make_unique<asio::listener>(std::move(options), executor, executor);
32 : }
33 :
34 8601 : void server::listening() {
35 8601 : if (running_) return;
36 : // Restart io_context if it was previously stopped
37 8409 : io_context_.restart();
38 : // Create work guard to keep io_context running
39 8409 : work_guard_ = std::make_unique<work_guard_type>(io_context_.get_executor());
40 : // Note: io_context_.run() will be called in wait() method
41 8409 : running_ = true;
42 : }
43 :
44 8068 : void server::wait() {
45 8068 : if (!running_) {
46 3 : return;
47 : }
48 :
49 : // Run io_context in the current thread
50 : // This blocks until the server is stopped
51 8065 : LOG_DEBUG("Running io_context in current thread");
52 8065 : serving_ = true;
53 8065 : io_context_.run();
54 8065 : serving_ = false;
55 8065 : LOG_DEBUG("io_context stopped");
56 : }
57 :
58 17725 : void server::stop() {
59 : // (a shutdown in progress ends first)
60 17725 : end_shutdown();
61 17725 : stop_running();
62 17725 : }
63 :
64 18375 : void server::stop_running() {
65 : // One exchange, so of the stop() calls made at once only one goes on
66 18375 : if (!running_.exchange(false)) {
67 9966 : return;
68 : }
69 :
70 8409 : LOG_DEBUG("Stopping standalone HTTP server");
71 :
72 : // Stop accepting new connections first (this is always safe to call)
73 8409 : server_base::stop();
74 :
75 : // Reset work guard to allow io_context to stop when it's running
76 8409 : work_guard_.reset();
77 :
78 : // Stop the io_context if it's running
79 : // Note: io_context_.stop() is safe to call even if not running
80 8409 : io_context_.stop();
81 :
82 8409 : LOG_DEBUG("Standalone HTTP server stopped");
83 : }
84 :
85 : } // namespace thinger::http
|