// Project Includes #include "client.hpp" #include "error.hpp" #include "file_descriptor.hpp" #include "server.hpp" #include "uring_context.hpp" // Standard Library Includes #include #include #include #include #include // Third-Party Library Includes #include #include #include #include #include std::expected parse_port(int argc, char *argv[]) { if (argc < 2) { return std::unexpected(Error("Port number not provided")); } try { int port = std::stoi(argv[1]); if (port < 1 || port > 65535) { return std::unexpected(Error("Port number must be between 1 and 65535")); } return static_cast(port); } catch (std::exception const &ex) { auto message = std::string("Invalid port number: ") + ex.what(); return std::unexpected(Error(message)); } } kev::task listen(Server &server, UringContext &uring_ctx) { exec::async_scope scope{}; while (true) { RawFileDescriptor fd{-1}; try { fd = co_await uring_ctx.async_accept(server.m_server_fd.get()); } catch (const std::exception &e) { std::println(std::cerr, "Error accepting connection: {}", e.what()); break; } auto client_pipeline = handle_connection_coroutine(FileDescriptor(fd), server.m_context, uring_ctx) | stdexec::upon_error([](std::exception_ptr ptr) { try { if (ptr) { std::rethrow_exception(ptr); } } catch (const std::exception &e) { std::println(std::cerr, "Error in client connection: {}", e.what()); } }); scope.spawn(std::move(client_pipeline)); } } int main(int argc, char *argv[]) { argparse::ArgumentParser program("webserver"); uint16_t port{}; std::string root; program.add_argument("--port", "-p") .default_value(8080) .help("Port number to listen on") .store_into(port); program.add_argument("--root", "-r") .default_value(std::string(".")) .help("Root directory for serving files") .store_into(root); try { program.parse_args(argc, argv); } catch (const std::exception &e) { std::println(std::cerr, "Error parsing arguments: {}", e.what()); return 1; } // Validate that the root directory exists if (!std::filesystem::exists(root) || !std::filesystem::is_directory(root)) { std::println(std::cerr, "Error: Root directory '{}' does not exist or is not a directory.", root); return 1; } UringContext uring_ctx = UringContext(1024); auto server = Server(port, root); uring_ctx.run(listen(server, uring_ctx)); }