Line data Source code
1 : #include "server_standalone.hpp"
2 : #include "../../util/logger.hpp"
3 : #include "../../asio/ssl/certificate_manager.hpp"
4 : #include <future>
5 :
6 : namespace thinger::http {
7 :
8 671 : server::server() {
9 671 : LOG_DEBUG("Created standalone HTTP server (single-threaded)");
10 671 : }
11 :
12 671 : server::~server() {
13 671 : LOG_DEBUG("Destroying standalone HTTP server");
14 671 : if (running_) {
15 12 : stop();
16 : }
17 671 : }
18 :
19 :
20 559 : std::unique_ptr<asio::socket_server> server::create_socket_server(
21 : const std::string& host, const std::string& port) {
22 :
23 : // Both acceptor and connections use our io_context
24 1910 : auto context_provider = [this]() -> boost::asio::io_context& {
25 1910 : return io_context_;
26 559 : };
27 :
28 : auto server = std::make_unique<asio::socket_server>(
29 : host, port,
30 : context_provider, // acceptor context
31 : context_provider // connection context
32 559 : );
33 :
34 : // Configure SSL if enabled
35 559 : if (ssl_enabled_) {
36 52 : server->enable_ssl(true);
37 :
38 52 : auto& cert_mgr = asio::certificate_manager::instance();
39 52 : auto default_ctx = cert_mgr.get_default_certificate();
40 :
41 52 : if (!default_ctx) {
42 0 : LOG_ERROR("No default SSL certificate configured");
43 0 : return nullptr;
44 : }
45 :
46 52 : server->set_ssl_context(default_ctx);
47 52 : server->set_sni_callback(asio::certificate_manager::sni_callback);
48 52 : }
49 :
50 559 : return server;
51 559 : }
52 :
53 39 : std::unique_ptr<asio::unix_socket_server> server::create_unix_socket_server(
54 : const std::string& unix_path) {
55 :
56 : // Both acceptor and connections use our io_context
57 39 : auto context_provider = [this]() -> boost::asio::io_context& {
58 39 : return io_context_;
59 39 : };
60 :
61 : auto server = std::make_unique<asio::unix_socket_server>(
62 : unix_path,
63 : context_provider, // acceptor context
64 : context_provider // connection context
65 39 : );
66 :
67 78 : return server;
68 : }
69 :
70 562 : bool server::listen(const std::string& host, uint16_t port) {
71 562 : if (running_) {
72 3 : LOG_WARNING("Server already running");
73 3 : return false;
74 : }
75 :
76 : // Restart io_context if it was previously stopped
77 559 : io_context_.restart();
78 :
79 : // Call base implementation to setup socket server
80 559 : if (!http_server_base::listen(host, port)) {
81 6 : return false;
82 : }
83 :
84 : // Create work guard to keep io_context running
85 553 : work_guard_ = std::make_unique<work_guard_type>(io_context_.get_executor());
86 :
87 : // Mark as running
88 553 : running_ = true;
89 553 : LOG_INFO("Standalone server listening on {}:{} (single-threaded)", host, port);
90 :
91 : // Note: io_context_.run() will be called in wait() method
92 :
93 553 : return true;
94 : }
95 :
96 39 : bool server::listen_unix(const std::string& unix_path) {
97 39 : if (running_) {
98 0 : LOG_WARNING("Server already running");
99 0 : return false;
100 : }
101 :
102 : // Restart io_context if it was previously stopped
103 39 : io_context_.restart();
104 :
105 : // Call base implementation to setup unix socket server
106 39 : if (!http_server_base::listen_unix(unix_path)) {
107 0 : return false;
108 : }
109 :
110 : // Create work guard to keep io_context running
111 39 : work_guard_ = std::make_unique<work_guard_type>(io_context_.get_executor());
112 :
113 : // Mark as running
114 39 : running_ = true;
115 39 : LOG_INFO("Standalone server listening on unix:{} (single-threaded)", unix_path);
116 :
117 39 : return true;
118 : }
119 :
120 571 : void server::wait() {
121 571 : if (!running_) {
122 0 : return;
123 : }
124 :
125 : // Run io_context in the current thread
126 : // This blocks until the server is stopped
127 571 : LOG_DEBUG("Running io_context in current thread");
128 571 : io_context_.run();
129 571 : LOG_DEBUG("io_context stopped");
130 : }
131 :
132 597 : bool server::stop() {
133 597 : if (!running_) {
134 5 : return false;
135 : }
136 :
137 592 : LOG_DEBUG("Stopping standalone HTTP server");
138 592 : running_ = false;
139 :
140 : // Stop accepting new connections first (this is always safe to call)
141 592 : http_server_base::stop();
142 :
143 : // Reset work guard to allow io_context to stop when it's running
144 592 : work_guard_.reset();
145 :
146 : // Stop the io_context if it's running
147 : // Note: io_context_.stop() is safe to call even if not running
148 592 : io_context_.stop();
149 :
150 592 : LOG_DEBUG("Standalone HTTP server stopped");
151 592 : return true;
152 : }
153 :
154 : } // namespace thinger::http
|