summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorRutger Broekhoff2026-09-22 22:28:10 +0200
committerRutger Broekhoff2026-09-22 22:28:10 +0200
commitecf1be3f834c7187312f8eee71f77e448c995388 (patch)
treeb7018285b815c356c49535c97ace67ac43deeb2d /server
parentae652cab3cf0541173b31273bcec5746a9a81e68 (diff)
downloadroutemon-ecf1be3f834c7187312f8eee71f77e448c995388.tar.gz
routemon-ecf1be3f834c7187312f8eee71f77e448c995388.zip
Check period selection
Diffstat (limited to 'server')
-rw-r--r--server/src/api.cpp11
-rw-r--r--server/src/api.cppm3
-rw-r--r--server/src/geo/wgs84.cppm3
-rw-r--r--server/src/http_server.cppm18
-rw-r--r--server/src/srv.cpp113
5 files changed, 126 insertions, 22 deletions
diff --git a/server/src/api.cpp b/server/src/api.cpp
index f1ca24e..9a51690 100644
--- a/server/src/api.cpp
+++ b/server/src/api.cpp
@@ -141,20 +141,15 @@ handler::handler(log::logger const& l, datex2::situation_publication pub)
141 auto const dur_build_s = chrono::duration<double>{after_build - before_build}; 141 auto const dur_build_s = chrono::duration<double>{after_build - before_build};
142 l_.info("Indexes built in {}", dur_build_s); 142 l_.info("Indexes built in {}", dur_build_s);
143 l_.info("BLSE index size: {}", blse_index_.size()); 143 l_.info("BLSE index size: {}", blse_index_.size());
144 l_.info("Point index size: {}", bpe_index_.size()); 144 l_.info("BPE index size: {}", bpe_index_.size());
145} 145}
146 146
147auto handler::process_gpx(trace::id trace_id, gpx::file&& gpx_file) 147auto handler::process_gpx(
148 trace::id trace_id, gpx::file&& gpx_file, time::period_seq check_periods)
148 -> std::optional<process_gpx_result> 149 -> std::optional<process_gpx_result>
149{ 150{
150 auto l = l_.with("trace_id", trace_id.as_string()); 151 auto l = l_.with("trace_id", trace_id.as_string());
151 152
152 auto const now = chrono::utc_clock::now();
153 auto const relevant = std::initializer_list<time::period>{
154 time::period{now - chrono::days(7), now + chrono::days(7)}
155 };
156 auto const check_periods = time::period_seq{relevant.begin(), relevant.end()};
157
158 // TODO: eliminate use of overlap segments 153 // TODO: eliminate use of overlap segments
159 auto segments = std::vector<geo::utm::zonable_wgs84_linestring>{}; 154 auto segments = std::vector<geo::utm::zonable_wgs84_linestring>{};
160 for (auto const& track : gpx_file.tracks) 155 for (auto const& track : gpx_file.tracks)
diff --git a/server/src/api.cppm b/server/src/api.cppm
index b2744cb..b14bbcf 100644
--- a/server/src/api.cppm
+++ b/server/src/api.cppm
@@ -93,7 +93,8 @@ class handler
93public: 93public:
94 explicit handler(log::logger const& l, datex2::situation_publication pub); 94 explicit handler(log::logger const& l, datex2::situation_publication pub);
95 95
96 auto process_gpx(trace::id trace_id, gpx::file&& gpx_file) 96 auto process_gpx(
97 trace::id trace_id, gpx::file&& gpx_file, time::period_seq check_periods)
97 -> std::optional<process_gpx_result>; 98 -> std::optional<process_gpx_result>;
98 auto sysinfo() -> sysinfo; 99 auto sysinfo() -> sysinfo;
99}; 100};
diff --git a/server/src/geo/wgs84.cppm b/server/src/geo/wgs84.cppm
index b53a963..2212a92 100644
--- a/server/src/geo/wgs84.cppm
+++ b/server/src/geo/wgs84.cppm
@@ -10,9 +10,6 @@ namespace routemon::geo::wgs84 {
10 10
11using cs = bgeo::cs::geographic<bgeo::degree>; 11using cs = bgeo::cs::geographic<bgeo::degree>;
12using point = bgeo::model::point<double, 2, cs>; 12using point = bgeo::model::point<double, 2, cs>;
13// TODO: guarantee that linestring provides non-static member
14// auto reserve(std::size_t) -> void
15// Perhaps better yet: guarantee that the backing container is a std::vector.
16using linestring = 13using linestring =
17 bgeo::model::linestring<point, std::vector /* the default */>; 14 bgeo::model::linestring<point, std::vector /* the default */>;
18using box = bgeo::model::box<point>; 15using box = bgeo::model::box<point>;
diff --git a/server/src/http_server.cppm b/server/src/http_server.cppm
index e70110e..c111118 100644
--- a/server/src/http_server.cppm
+++ b/server/src/http_server.cppm
@@ -300,6 +300,7 @@ template <class InnerCtx>
300struct routed_ctx : InnerCtx 300struct routed_ctx : InnerCtx
301{ 301{
302 verb_set route_methods; 302 verb_set route_methods;
303 boost::urls::url target;
303}; 304};
304 305
305template <class Ctx> 306template <class Ctx>
@@ -687,12 +688,12 @@ class router
687 co_return problem_rsp(ctx, problem, keep_alive{false}); 688 co_return problem_rsp(ctx, problem, keep_alive{false});
688 } 689 }
689 690
690 l_.with( 691 // l_.with(
691 "trace_id", 692 // "trace_id",
692 static_cast<base_ctx const&>(ctx).trace_id.as_string()) 693 // static_cast<base_ctx const&>(ctx).trace_id.as_string())
693 .debug( 694 // .debug(
694 "Request targets {} {}", req_base.method_string(), 695 // "Request targets {} {}", req_base.method_string(),
695 req_url.path()); 696 // req_url.path());
696 697
697 auto mres = match(req_url.segments()); 698 auto mres = match(req_url.segments());
698 if (!mres) 699 if (!mres)
@@ -720,8 +721,9 @@ class router
720 721
721 if (auto mhdl = mres->route_handlers->lookup(*mverb)) 722 if (auto mhdl = mres->route_handlers->lookup(*mverb))
722 { 723 {
723 auto new_ctx = 724 auto new_ctx = routed_ctx<PreRouteCtx>{
724 routed_ctx<PreRouteCtx>{std::move(ctx), mres->allowed_methods()}; 725 std::move(ctx), mres->allowed_methods(), std::move(req_url)
726 };
725 co_return co_await mhdl( 727 co_return co_await mhdl(
726 std::move(new_ctx), r, mres->wildcard_matches); 728 std::move(new_ctx), r, mres->wildcard_matches);
727 } 729 }
diff --git a/server/src/srv.cpp b/server/src/srv.cpp
index dc9c814..5de0fc5 100644
--- a/server/src/srv.cpp
+++ b/server/src/srv.cpp
@@ -30,7 +30,7 @@ namespace routemon::srv {
30class gpx_parse_error_category_impl : public std::error_category 30class gpx_parse_error_category_impl : public std::error_category
31{ 31{
32public: 32public:
33 char const* name() const noexcept override { return "gpx_parse"; } 33 auto name() const noexcept -> char const* override { return "gpx_parse"; }
34 34
35 auto message(int condition) const noexcept -> std::string override 35 auto message(int condition) const noexcept -> std::string override
36 { 36 {
@@ -330,12 +330,120 @@ struct raw_deflate_body
330 }; 330 };
331}; 331};
332 332
333auto parse_timestamp(std::string_view in) -> std::optional<time::timestamp>
334{
335 auto res = time::timestamp{};
336 auto is = std::istringstream{in};
337 is >> std::chrono::parse("%Y-%m-%dT%H:%MZ", res);
338 return is.fail() ? std::nullopt : std::make_optional(res);
339}
340
333auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) 341auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r)
334 -> net::awaitable<http::presponse> 342 -> net::awaitable<http::presponse>
335{ 343{
336 auto l = 344 auto l =
337 l_.sub("handle_process_gpx").with("trace_id", ctx.trace_id.as_string()); 345 l_.sub("handle_process_gpx").with("trace_id", ctx.trace_id.as_string());
338 346
347 auto cp_begin = time::timestamp{};
348 auto cp_end = time::timestamp{};
349
350 auto const params = ctx.target.params();
351 if (auto it = params.find("cpbegin"); it != params.end())
352 {
353 auto mts = parse_timestamp((*it).value);
354 if (!mts)
355 {
356 auto tpl = problem::tpl{
357 .status = bhttp::status::bad_request,
358 .title = translate("Query parameter has bad value"),
359 .type_uri =
360 "https://routemon.fautchen.eu/problems/query-param-bad-value",
361 };
362 co_return http::problem_rsp(
363 ctx, tpl.instantiate(), http::keep_alive{false});
364 }
365 cp_begin = *mts;
366
367 ++it;
368 if (it != params.end() && (*it).key == "cpbegin")
369 {
370 auto tpl = problem::tpl{
371 .status = bhttp::status::bad_request,
372 .title = translate("Query parameter provided too many times"),
373 .type_uri = "https://routemon.fautchen.eu/problems/"
374 "query-param-too-many-occurrences",
375 };
376 co_return http::problem_rsp(
377 ctx, tpl.instantiate(), http::keep_alive{false});
378 }
379 }
380 else
381 {
382 auto tpl = problem::tpl{
383 .status = bhttp::status::bad_request,
384 .title = translate("Required query parameter not provided"),
385 .type_uri = "https://routemon.fautchen.eu/problems/"
386 "required-query-param-not-provided",
387 };
388 co_return http::problem_rsp(
389 ctx, tpl.instantiate(), http::keep_alive{false});
390 }
391 if (auto it = params.find("cpend"); it != params.end())
392 {
393 auto mts = parse_timestamp((*it).value);
394 if (!mts)
395 {
396 auto tpl = problem::tpl{
397 .status = bhttp::status::bad_request,
398 .title = translate("Query parameter has bad value"),
399 .type_uri =
400 "https://routemon.fautchen.eu/problems/query-param-bad-value",
401 };
402 co_return http::problem_rsp(
403 ctx, tpl.instantiate(), http::keep_alive{false});
404 }
405 cp_end = *mts;
406
407 ++it;
408 if (it != params.end() && (*it).key == "cpend")
409 {
410 auto tpl = problem::tpl{
411 .status = bhttp::status::bad_request,
412 .title = translate("Query parameter provided too many times"),
413 .type_uri = "https://routemon.fautchen.eu/problems/"
414 "query-param-too-many-occurrences",
415 };
416 co_return http::problem_rsp(
417 ctx, tpl.instantiate(), http::keep_alive{false});
418 }
419 }
420 else
421 {
422 auto tpl = problem::tpl{
423 .status = bhttp::status::bad_request,
424 .title = translate("Required query parameter not provided"),
425 .type_uri = "https://routemon.fautchen.eu/problems/"
426 "required-query-param-not-provided",
427 };
428 co_return http::problem_rsp(
429 ctx, tpl.instantiate(), http::keep_alive{false});
430 }
431
432 if (cp_begin >= cp_end)
433 {
434 auto tpl = problem::tpl{
435 .status = bhttp::status::bad_request,
436 .title = translate("Invalid check period provided"),
437 .type_uri = "https://routemon.fautchen.eu/problems/invalid-check-period",
438 };
439 co_return http::problem_rsp(
440 ctx,
441 tpl.instantiate().set_detail(translate(
442 "Begin of check period must be before end of check period")),
443 http::keep_alive{false});
444 }
445 auto cp = time::period{cp_begin, cp_end};
446
339 auto gpx_file = gpx::file{}; 447 auto gpx_file = gpx::file{};
340 try 448 try
341 { 449 {
@@ -378,7 +486,8 @@ auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r)
378 486
379 // TODO: catch handler exceptions and return 500 when raised? 487 // TODO: catch handler exceptions and return 500 when raised?
380 // (keep-alive depends on whether whole request was read) 488 // (keep-alive depends on whether whole request was read)
381 auto mres = inner_.process_gpx(ctx.trace_id, std::move(gpx_file)); 489 auto mres = inner_.process_gpx(
490 ctx.trace_id, std::move(gpx_file), time::period_seq{cp});
382 if (!mres) 491 if (!mres)
383 { 492 {
384 auto tpl = problem::tpl{ 493 auto tpl = problem::tpl{