summaryrefslogtreecommitdiffstats
path: root/server/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/main.cpp')
-rw-r--r--server/src/main.cpp109
1 files changed, 109 insertions, 0 deletions
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 @@
1#include <malloc.h> // for malloc_trim(3)
2#include <boost/asio.hpp>
3
4import std;
5import routemon;
6
7namespace chrono = std::chrono;
8namespace net = boost::asio;
9
10enum class exit_status {
11 failure,
12 bad_usage,
13};
14
15auto real_main(std::span<char const*> args) -> exit_status {
16 auto sink = routemon::log::make_sink(routemon::log::level::info);
17 auto l = routemon::log::logger{sink};
18
19 if (args.size() != 2) {
20 l.error("Fatal: expected exactly one argument (the configuration file location), got {}", args.size() - 1);
21 return exit_status::bad_usage;
22 }
23 auto const* config_filename = args[1];
24
25 auto lgen = routemon::locale::make_generator();
26 auto default_locale = lgen->generate("en_US.UTF-8");
27 auto locales = {
28 default_locale,
29 lgen->generate("nl_NL.UTF-8"),
30 lgen->generate("de_DE.UTF-8"),
31 lgen->generate("en_GB.UTF-8"),
32 };
33 auto lsel = routemon::locale::selector{locales, default_locale, lgen};
34
35 auto ioc = net::io_context{1 /* concurrency hint */};
36
37 auto config = routemon::config::app{};
38 try {
39 config = routemon::config::load_file(config_filename);
40 } catch (std::exception const& e) {
41 l.with("filename", std::string_view{config_filename}).
42 error("Failed to load configuration: {}", e.what());
43 return exit_status::failure;
44 }
45 sink->set_level(config.logger.level);
46 // auto rwgps_client = routemon::rwgps::client{ioc, l, config.rwgps.api_key, config.rwgps.auth_token};
47 // for (auto route : rwgps_client.get_all_routes()) {
48 // l.info("Route {} (user {}): {} @ {}", route.id, route.user_id, route.name, route.url);
49 // }
50
51 auto dbc = std::shared_ptr<routemon::database::connection>{};
52 try {
53 dbc = routemon::database::open(config.database.sqlite3_filename);
54 } catch (std::exception const& e) {
55 l.with("filename", config.database.sqlite3_filename).
56 error("Failed to open database: {}", e.what());
57 return exit_status::failure;
58 }
59
60 l.with("filename", config.situations.datex2_filename).
61 info("Loading situations");
62 auto const before_load = chrono::steady_clock::now();
63 auto d2loader = routemon::datex2::loader{};
64 auto pub = routemon::datex2::situation_publication{};
65 try {
66 pub = d2loader.load_situation_publication(config.situations.datex2_filename);
67 } catch (std::exception const& e) {
68 l.error("Failed to load DATEX II situations publication: {}", e.what());
69 return exit_status::failure;
70 }
71 if (!d2loader.warnings().empty()) {
72 auto const& warns = d2loader.warnings();
73 l.warn("Encountered {} unique warnings while loading DATEX II situations publication", warns.size());
74 auto i = 0uz;
75 for (auto it = warns.begin(); it != warns.end(); it = warns.upper_bound(*it)) {
76 l.warn("Warning {} (appeared {}×): {}", ++i, warns.count(*it), *it);
77 }
78 }
79 // Processing the feed is by far the most memory-intensive operation
80 // during the run time of this application (at the moment), the
81 // resident set will likely never be this big again. So we ask libc
82 // to return as much memory as possible to the OS.
83 malloc_trim(0);
84 auto const after_load = chrono::steady_clock::now();
85 auto const dur_load = chrono::duration_cast<chrono::milliseconds>(after_load - before_load);
86 l.info("Loading situations finished in {}", dur_load);
87
88 auto handler = routemon::api::handler{l, std::move(pub)};
89 auto http_server = routemon::srv::server{l, std::move(lsel), std::move(handler)};
90 http_server.spawn(ioc);
91 ioc.run();
92
93 l.error("I/O context stopped");
94 return exit_status::failure;
95}
96
97auto main(int argc, char* argv[]) -> int {
98 if (argc < 0) {
99 std::cout << "Fatal: argument count below zero" << std::endl;
100 return EXIT_FAILURE;
101 }
102 auto res = real_main(std::span{const_cast<char const**>(argv), static_cast<std::size_t>(argc)});
103 switch (res) {
104 case exit_status::failure:
105 return EXIT_FAILURE;
106 case exit_status::bad_usage:
107 return 2;
108 }
109}