From 973aec43ea54bbf95b64fbcb636403401d1ca60e Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Fri, 28 Aug 2026 18:03:05 +0200 Subject: Import from e4b104792206ee7ea64bf39c6b7d2c0c230f9d14 --- server/src/main.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 server/src/main.cpp (limited to 'server/src/main.cpp') diff --git a/server/src/main.cpp b/server/src/main.cpp new file mode 100644 index 0000000..a40b0b0 --- /dev/null +++ b/server/src/main.cpp @@ -0,0 +1,109 @@ +#include // for malloc_trim(3) +#include + +import std; +import routemon; + +namespace chrono = std::chrono; +namespace net = boost::asio; + +enum class exit_status { + failure, + bad_usage, +}; + +auto real_main(std::span args) -> exit_status { + auto sink = routemon::log::make_sink(routemon::log::level::info); + auto l = routemon::log::logger{sink}; + + if (args.size() != 2) { + l.error("Fatal: expected exactly one argument (the configuration file location), got {}", args.size() - 1); + return exit_status::bad_usage; + } + auto const* config_filename = args[1]; + + auto lgen = routemon::locale::make_generator(); + auto default_locale = lgen->generate("en_US.UTF-8"); + auto locales = { + default_locale, + lgen->generate("nl_NL.UTF-8"), + lgen->generate("de_DE.UTF-8"), + lgen->generate("en_GB.UTF-8"), + }; + auto lsel = routemon::locale::selector{locales, default_locale, lgen}; + + auto ioc = net::io_context{1 /* concurrency hint */}; + + auto config = routemon::config::app{}; + try { + config = routemon::config::load_file(config_filename); + } catch (std::exception const& e) { + l.with("filename", std::string_view{config_filename}). + error("Failed to load configuration: {}", e.what()); + return exit_status::failure; + } + sink->set_level(config.logger.level); + // auto rwgps_client = routemon::rwgps::client{ioc, l, config.rwgps.api_key, config.rwgps.auth_token}; + // for (auto route : rwgps_client.get_all_routes()) { + // l.info("Route {} (user {}): {} @ {}", route.id, route.user_id, route.name, route.url); + // } + + auto dbc = std::shared_ptr{}; + try { + dbc = routemon::database::open(config.database.sqlite3_filename); + } catch (std::exception const& e) { + l.with("filename", config.database.sqlite3_filename). + error("Failed to open database: {}", e.what()); + return exit_status::failure; + } + + l.with("filename", config.situations.datex2_filename). + info("Loading situations"); + auto const before_load = chrono::steady_clock::now(); + auto d2loader = routemon::datex2::loader{}; + auto pub = routemon::datex2::situation_publication{}; + try { + pub = d2loader.load_situation_publication(config.situations.datex2_filename); + } catch (std::exception const& e) { + l.error("Failed to load DATEX II situations publication: {}", e.what()); + return exit_status::failure; + } + if (!d2loader.warnings().empty()) { + auto const& warns = d2loader.warnings(); + l.warn("Encountered {} unique warnings while loading DATEX II situations publication", warns.size()); + auto i = 0uz; + for (auto it = warns.begin(); it != warns.end(); it = warns.upper_bound(*it)) { + l.warn("Warning {} (appeared {}×): {}", ++i, warns.count(*it), *it); + } + } + // Processing the feed is by far the most memory-intensive operation + // during the run time of this application (at the moment), the + // resident set will likely never be this big again. So we ask libc + // to return as much memory as possible to the OS. + malloc_trim(0); + auto const after_load = chrono::steady_clock::now(); + auto const dur_load = chrono::duration_cast(after_load - before_load); + l.info("Loading situations finished in {}", dur_load); + + auto handler = routemon::api::handler{l, std::move(pub)}; + auto http_server = routemon::srv::server{l, std::move(lsel), std::move(handler)}; + http_server.spawn(ioc); + ioc.run(); + + l.error("I/O context stopped"); + return exit_status::failure; +} + +auto main(int argc, char* argv[]) -> int { + if (argc < 0) { + std::cout << "Fatal: argument count below zero" << std::endl; + return EXIT_FAILURE; + } + auto res = real_main(std::span{const_cast(argv), static_cast(argc)}); + switch (res) { + case exit_status::failure: + return EXIT_FAILURE; + case exit_status::bad_usage: + return 2; + } +} -- cgit v1.3