diff options
| -rw-r--r-- | server/src/geo/utm.cppm | 44 | ||||
| -rw-r--r-- | server/src/log.cpp | 30 | ||||
| -rw-r--r-- | server/src/log.cppm | 10 | ||||
| -rw-r--r-- | server/src/srv.cpp | 8 | ||||
| -rw-r--r-- | server/src/trace.cpp | 77 | ||||
| -rw-r--r-- | server/src/trace.cppm | 6 |
6 files changed, 98 insertions, 77 deletions
diff --git a/server/src/geo/utm.cppm b/server/src/geo/utm.cppm index c58ffb4..75bba6f 100644 --- a/server/src/geo/utm.cppm +++ b/server/src/geo/utm.cppm | |||
| @@ -110,6 +110,7 @@ using zonable_wgs84_linestring = | |||
| 110 | // and easting (so no Norway/Svalbard exceptions). | 110 | // and easting (so no Norway/Svalbard exceptions). |
| 111 | class zone | 111 | class zone |
| 112 | { | 112 | { |
| 113 | public: | ||
| 113 | // Note: calculations heavily depend on the values of the variants. | 114 | // Note: calculations heavily depend on the values of the variants. |
| 114 | enum class hemisphere : std::uint8_t | 115 | enum class hemisphere : std::uint8_t |
| 115 | { | 116 | { |
| @@ -117,23 +118,6 @@ class zone | |||
| 117 | southern = 1, | 118 | southern = 1, |
| 118 | }; | 119 | }; |
| 119 | 120 | ||
| 120 | // Negative if in the southern hemisphere | ||
| 121 | // Equal to (zone_no - 1) * 2 + hemisphere | ||
| 122 | // In range [0, 119] | ||
| 123 | std::uint8_t zone_; | ||
| 124 | |||
| 125 | static constexpr auto zone_no_valid(std::uint8_t zone_no) -> bool | ||
| 126 | { | ||
| 127 | return 0 < zone_no && zone_no <= 60; | ||
| 128 | } | ||
| 129 | |||
| 130 | static constexpr auto from(std::uint8_t zone_no, hemisphere h) -> std::uint8_t | ||
| 131 | { | ||
| 132 | if (!zone_no_valid(zone_no)) | ||
| 133 | throw std::invalid_argument{"invalid UTM zone number"}; | ||
| 134 | return (zone_no - 1) * 2 + static_cast<std::uint8_t>(h); | ||
| 135 | } | ||
| 136 | |||
| 137 | public: | 121 | public: |
| 138 | explicit constexpr zone(std::uint8_t zone_no, hemisphere h) | 122 | explicit constexpr zone(std::uint8_t zone_no, hemisphere h) |
| 139 | : zone_{from(zone_no, h)} | 123 | : zone_{from(zone_no, h)} |
| @@ -196,8 +180,34 @@ public: | |||
| 196 | { | 180 | { |
| 197 | return zone_ == rhs.zone_; | 181 | return zone_ == rhs.zone_; |
| 198 | } | 182 | } |
| 183 | |||
| 184 | private: | ||
| 185 | static constexpr auto zone_no_valid(std::uint8_t zone_no) -> bool | ||
| 186 | { | ||
| 187 | return 0 < zone_no && zone_no <= 60; | ||
| 188 | } | ||
| 189 | |||
| 190 | static constexpr auto from(std::uint8_t zone_no, enum hemisphere h) | ||
| 191 | -> std::uint8_t | ||
| 192 | { | ||
| 193 | if (!zone_no_valid(zone_no)) | ||
| 194 | throw std::invalid_argument{"invalid UTM zone number"}; | ||
| 195 | return (zone_no - 1) * 2 + static_cast<std::uint8_t>(h); | ||
| 196 | } | ||
| 197 | |||
| 198 | // Negative if in the southern hemisphere | ||
| 199 | // Equal to (zone_no - 1) * 2 + hemisphere | ||
| 200 | // In range [0, 119] | ||
| 201 | std::uint8_t zone_; | ||
| 199 | }; | 202 | }; |
| 200 | static_assert(zone::min().as_index() == 0); | 203 | static_assert(zone::min().as_index() == 0); |
| 201 | static_assert(zone::max().as_index() == 119); | 204 | static_assert(zone::max().as_index() == 119); |
| 202 | 205 | ||
| 206 | auto to_string(zone z) -> std::string | ||
| 207 | { | ||
| 208 | return std::format( | ||
| 209 | "{} {}", z.zone_no(), | ||
| 210 | z.hemisphere() == zone::hemisphere::northern ? "northern" : "southern"); | ||
| 211 | } | ||
| 212 | |||
| 203 | } // namespace routemon::geo::utm | 213 | } // namespace routemon::geo::utm |
diff --git a/server/src/log.cpp b/server/src/log.cpp index bb9fde2..5953c14 100644 --- a/server/src/log.cpp +++ b/server/src/log.cpp | |||
| @@ -30,17 +30,7 @@ auto sink::level() const -> enum level { return lvl_; } | |||
| 30 | 30 | ||
| 31 | auto sink::set_level(enum level lvl) -> void { lvl_ = lvl; } | 31 | auto sink::set_level(enum level lvl) -> void { lvl_ = lvl; } |
| 32 | 32 | ||
| 33 | auto sink::write(tmp_message msg) -> void | 33 | auto sink::write() -> std::osyncstream { return std::osyncstream{os_}; } |
| 34 | { | ||
| 35 | auto sos = std::osyncstream{os_}; | ||
| 36 | sos << "[" << msg.lvl; | ||
| 37 | if (!msg.component.empty()) | ||
| 38 | sos << " " << msg.component; | ||
| 39 | sos << "] " << msg.txt; | ||
| 40 | for (auto const& [k, v] : msg.attrs) | ||
| 41 | sos << " " << k << "=" << std::quoted(v); | ||
| 42 | sos << std::endl; // we want the flush! | ||
| 43 | } | ||
| 44 | 34 | ||
| 45 | auto make_sink(level lvl) -> std::shared_ptr<sink> | 35 | auto make_sink(level lvl) -> std::shared_ptr<sink> |
| 46 | { | 36 | { |
| @@ -51,13 +41,17 @@ auto logger::log_at(log::level lvl, std::string_view fmt, std::format_args args) | |||
| 51 | -> logger& | 41 | -> logger& |
| 52 | { | 42 | { |
| 53 | if (sink_->level() <= lvl) | 43 | if (sink_->level() <= lvl) |
| 54 | sink_->write( | 44 | { |
| 55 | sink::tmp_message{ | 45 | auto sos = sink_->write(); |
| 56 | .lvl = lvl, | 46 | sos << "[" << lvl; |
| 57 | .component = component_, | 47 | if (!component_.empty()) |
| 58 | .txt = std::vformat(fmt, args), | 48 | sos << " " << component_; |
| 59 | .attrs = attrs_, | 49 | sos << "] "; |
| 60 | }); | 50 | std::vprint_unicode(sos, fmt, args); |
| 51 | for (auto const& [k, v] : attrs_) | ||
| 52 | sos << " " << k << "=" << std::quoted(v); | ||
| 53 | sos << std::endl; // we want the flush! | ||
| 54 | } | ||
| 61 | return *this; | 55 | return *this; |
| 62 | } | 56 | } |
| 63 | 57 | ||
diff --git a/server/src/log.cppm b/server/src/log.cppm index dc8c2e1..87382f6 100644 --- a/server/src/log.cppm +++ b/server/src/log.cppm | |||
| @@ -21,18 +21,10 @@ export class sink | |||
| 21 | friend auto make_sink(level lvl) -> std::shared_ptr<sink>; | 21 | friend auto make_sink(level lvl) -> std::shared_ptr<sink>; |
| 22 | 22 | ||
| 23 | public: | 23 | public: |
| 24 | struct tmp_message | ||
| 25 | { | ||
| 26 | level lvl; | ||
| 27 | std::string_view component; | ||
| 28 | std::string_view txt; | ||
| 29 | std::map<std::string, std::string> const& attrs; | ||
| 30 | }; | ||
| 31 | |||
| 32 | [[nodiscard]] auto level() const -> enum level; | 24 | [[nodiscard]] auto level() const -> enum level; |
| 33 | auto set_level(enum level lvl) -> void; | 25 | auto set_level(enum level lvl) -> void; |
| 34 | 26 | ||
| 35 | auto write(tmp_message msg) -> void; | 27 | auto write() -> std::osyncstream; |
| 36 | }; | 28 | }; |
| 37 | 29 | ||
| 38 | export auto make_sink(level lvl) -> std::shared_ptr<sink>; | 30 | export auto make_sink(level lvl) -> std::shared_ptr<sink>; |
diff --git a/server/src/srv.cpp b/server/src/srv.cpp index a901f8e..dc9c814 100644 --- a/server/src/srv.cpp +++ b/server/src/srv.cpp | |||
| @@ -343,10 +343,10 @@ auto handler::handle_process_gpx(l0_ctx ctx, http::readable_request r) | |||
| 343 | auto const before_read_gpx = chrono::steady_clock::now(); | 343 | auto const before_read_gpx = chrono::steady_clock::now(); |
| 344 | auto parse_res = | 344 | auto parse_res = |
| 345 | r.p->get()[bhttp::field::content_encoding] == "x-deflate-raw" | 345 | r.p->get()[bhttp::field::content_encoding] == "x-deflate-raw" |
| 346 | ? std::move( | 346 | ? std::move((co_await http:: |
| 347 | (co_await http::read_request<raw_deflate_body<readable_gpx_body>>( | 347 | read_request<raw_deflate_body<readable_gpx_body>>( |
| 348 | ctx, std::move(r))) | 348 | ctx, std::move(r))) |
| 349 | .body()) | 349 | .body()) |
| 350 | : std::move((co_await http::read_request<readable_gpx_body>( | 350 | : std::move((co_await http::read_request<readable_gpx_body>( |
| 351 | ctx, std::move(r))) | 351 | ctx, std::move(r))) |
| 352 | .body()); | 352 | .body()); |
diff --git a/server/src/trace.cpp b/server/src/trace.cpp index e7c00d0..f2935a9 100644 --- a/server/src/trace.cpp +++ b/server/src/trace.cpp | |||
| @@ -10,6 +10,26 @@ import :trace; | |||
| 10 | 10 | ||
| 11 | namespace routemon::trace { | 11 | namespace routemon::trace { |
| 12 | 12 | ||
| 13 | class psrng | ||
| 14 | { | ||
| 15 | mutable std::default_random_engine e_ = {}; | ||
| 16 | mutable std::uniform_int_distribution<std::uint64_t> distr_ = {}; | ||
| 17 | mutable std::mutex mut_ = {}; | ||
| 18 | |||
| 19 | public: | ||
| 20 | auto next() const -> std::uint64_t | ||
| 21 | { | ||
| 22 | auto lock = std::lock_guard{mut_}; | ||
| 23 | return distr_(e_); | ||
| 24 | } | ||
| 25 | |||
| 26 | static auto instance() -> psrng const& | ||
| 27 | { | ||
| 28 | static auto const inst = psrng{}; | ||
| 29 | return inst; | ||
| 30 | } | ||
| 31 | }; | ||
| 32 | |||
| 13 | uuid7::uuid7() | 33 | uuid7::uuid7() |
| 14 | { | 34 | { |
| 15 | namespace chrono = std::chrono; | 35 | namespace chrono = std::chrono; |
| @@ -23,46 +43,51 @@ uuid7::uuid7() | |||
| 23 | if (std::countl_zero(unix_time_ms) < 16) | 43 | if (std::countl_zero(unix_time_ms) < 16) |
| 24 | throw std::runtime_error{"system time too great"}; | 44 | throw std::runtime_error{"system time too great"}; |
| 25 | 45 | ||
| 26 | auto rand = std::array<unsigned char, 10>{}; | 46 | auto const& rng = psrng::instance(); |
| 27 | int s = RAND_bytes(rand.data(), static_cast<int>(rand.size())); | 47 | auto const rand1 = rng.next(); |
| 28 | if (s != 1) | 48 | auto const rand2 = rng.next(); |
| 29 | { | ||
| 30 | unsigned long e = ERR_get_error(); | ||
| 31 | throw std::runtime_error{std::format( | ||
| 32 | "failed to generate UUID(v7): {} ({}, code {})", | ||
| 33 | ERR_reason_error_string(e), ERR_lib_error_string(e), e)}; | ||
| 34 | } | ||
| 35 | 49 | ||
| 36 | auto version = std::uint64_t{0b0111}; | 50 | auto version = std::uint64_t{0b0111}; |
| 37 | auto variant = std::uint64_t{0b10}; | 51 | auto variant = std::uint64_t{0b10}; |
| 38 | 52 | ||
| 39 | hi_ |= unix_time_ms << 16; | 53 | hi_ = unix_time_ms << 16; |
| 40 | hi_ |= version << 12; | 54 | hi_ |= version << 12; |
| 41 | hi_ |= std::uint64_t{rand[0]} << 4; | 55 | hi_ |= rand1 & 0x0000'0000'0000'0fff; |
| 42 | hi_ |= std::uint64_t{rand[1]}; | 56 | lo_ = variant << 62; |
| 43 | lo_ |= variant << 62; | 57 | lo_ |= rand2 >> 2; |
| 44 | lo_ |= std::uint64_t{rand[2]} << 54; | ||
| 45 | lo_ |= std::uint64_t{rand[3]} << 48; | ||
| 46 | lo_ |= std::uint64_t{rand[4]} << 40; | ||
| 47 | lo_ |= std::uint64_t{rand[5]} << 32; | ||
| 48 | lo_ |= std::uint64_t{rand[6]} << 24; | ||
| 49 | lo_ |= std::uint64_t{rand[7]} << 16; | ||
| 50 | lo_ |= std::uint64_t{rand[8]} << 8; | ||
| 51 | lo_ |= std::uint64_t{rand[9]}; | ||
| 52 | } | 58 | } |
| 53 | 59 | ||
| 54 | auto uuid7::format(std::array<char, 37>& target) -> void | 60 | auto uuid7::format(std::span<char, 37> target) -> void |
| 55 | { | 61 | { |
| 62 | auto hexnibs = | ||
| 63 | []<std::size_t n>(std::uint64_t v, std::span<char, n> s) -> void | ||
| 64 | { | ||
| 65 | for (auto i = 0uz; i < n; i++) | ||
| 66 | { | ||
| 67 | static char const hextab[16] = { | ||
| 68 | '0', '1', '2', '3', '4', '5', '6', '7', | ||
| 69 | '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', | ||
| 70 | }; | ||
| 71 | s[i] = hextab[(v >> 4 * (n - 1 - i)) & 0xf]; | ||
| 72 | } | ||
| 73 | }; | ||
| 74 | |||
| 56 | auto p____hi_hi = (hi_ & 0xffff'ffff'0000'0000) >> 32; | 75 | auto p____hi_hi = (hi_ & 0xffff'ffff'0000'0000) >> 32; |
| 57 | auto p_hi_lo_hi = (hi_ & 0x0000'0000'ffff'0000) >> 16; | 76 | auto p_hi_lo_hi = (hi_ & 0x0000'0000'ffff'0000) >> 16; |
| 58 | auto p_lo_lo_hi = (hi_ & 0x0000'0000'0000'ffff) >> 0; | 77 | auto p_lo_lo_hi = (hi_ & 0x0000'0000'0000'ffff) >> 0; |
| 59 | auto p____hi_lo = (lo_ & 0xffff'0000'0000'0000) >> 48; | 78 | auto p____hi_lo = (lo_ & 0xffff'0000'0000'0000) >> 48; |
| 60 | auto p____lo_lo = (lo_ & 0x0000'ffff'ffff'ffff) >> 0; | 79 | auto p____lo_lo = (lo_ & 0x0000'ffff'ffff'ffff) >> 0; |
| 61 | 80 | ||
| 62 | std::format_to( | 81 | hexnibs(p____hi_hi, target.subspan<0, 8>()); |
| 63 | target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}", p____hi_hi, | 82 | target[8] = '-'; |
| 64 | p_hi_lo_hi, p_lo_lo_hi, p____hi_lo, p____lo_lo); | 83 | hexnibs(p_hi_lo_hi, target.subspan<9, 4>()); |
| 65 | target.back() = '\0'; | 84 | target[13] = '-'; |
| 85 | hexnibs(p_lo_lo_hi, target.subspan<14, 4>()); | ||
| 86 | target[18] = '-'; | ||
| 87 | hexnibs(p____hi_lo, target.subspan<19, 4>()); | ||
| 88 | target[23] = '-'; | ||
| 89 | hexnibs(p____lo_lo, target.subspan<24, 12>()); | ||
| 90 | target[36] = '\0'; | ||
| 66 | } | 91 | } |
| 67 | 92 | ||
| 68 | id::id() { uuid7{}.format(chars_); } | 93 | id::id() { uuid7{}.format(chars_); } |
diff --git a/server/src/trace.cppm b/server/src/trace.cppm index deb84a0..fa743e1 100644 --- a/server/src/trace.cppm +++ b/server/src/trace.cppm | |||
| @@ -7,13 +7,13 @@ namespace routemon::trace { | |||
| 7 | 7 | ||
| 8 | class uuid7 | 8 | class uuid7 |
| 9 | { | 9 | { |
| 10 | std::uint64_t hi_ = 0; | 10 | std::uint64_t hi_; |
| 11 | std::uint64_t lo_ = 0; | 11 | std::uint64_t lo_; |
| 12 | 12 | ||
| 13 | public: | 13 | public: |
| 14 | uuid7(); | 14 | uuid7(); |
| 15 | 15 | ||
| 16 | auto format(std::array<char, 37>& target) -> void; | 16 | auto format(std::span<char, 37> target) -> void; |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | export class id | 19 | export class id |