diff options
Diffstat (limited to 'server/src/trace.cppm')
| -rw-r--r-- | server/src/trace.cppm | 120 |
1 files changed, 65 insertions, 55 deletions
diff --git a/server/src/trace.cppm b/server/src/trace.cppm index 00ecd05..35d32f3 100644 --- a/server/src/trace.cppm +++ b/server/src/trace.cppm | |||
| @@ -11,69 +11,79 @@ import :util; | |||
| 11 | 11 | ||
| 12 | namespace routemon::trace { | 12 | namespace routemon::trace { |
| 13 | 13 | ||
| 14 | class uuid7 { | 14 | class uuid7 |
| 15 | std::uint64_t high_ = 0; | 15 | { |
| 16 | std::uint64_t low_ = 0; | 16 | std::uint64_t high_ = 0; |
| 17 | std::uint64_t low_ = 0; | ||
| 17 | 18 | ||
| 18 | public: | 19 | public: |
| 19 | uuid7() { | 20 | uuid7() |
| 20 | namespace chrono = std::chrono; | 21 | { |
| 21 | auto const unix_time_ms_signed = static_cast<std::int64_t>(chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count()); | 22 | namespace chrono = std::chrono; |
| 22 | if (unix_time_ms_signed < 0) | 23 | auto const unix_time_ms_signed = static_cast<std::int64_t>( |
| 23 | throw std::runtime_error{"system time before UNIX epoch"}; | 24 | chrono::duration_cast<chrono::milliseconds>( |
| 24 | auto const unix_time_ms = static_cast<std::uint64_t>(unix_time_ms_signed); | 25 | chrono::system_clock::now().time_since_epoch()) |
| 25 | if (std::countl_zero(unix_time_ms) < 16) | 26 | .count()); |
| 26 | throw std::runtime_error{"system time too great"}; | 27 | if (unix_time_ms_signed < 0) |
| 28 | throw std::runtime_error{"system time before UNIX epoch"}; | ||
| 29 | auto const unix_time_ms = static_cast<std::uint64_t>(unix_time_ms_signed); | ||
| 30 | if (std::countl_zero(unix_time_ms) < 16) | ||
| 31 | throw std::runtime_error{"system time too great"}; | ||
| 27 | 32 | ||
| 28 | auto rand = std::array<unsigned char, 10>{}; | 33 | auto rand = std::array<unsigned char, 10>{}; |
| 29 | int s = RAND_bytes(rand.data(), static_cast<int>(rand.size())); | 34 | int s = RAND_bytes(rand.data(), static_cast<int>(rand.size())); |
| 30 | if (s != 1) { | 35 | if (s != 1) |
| 31 | unsigned long e = ERR_get_error(); | 36 | { |
| 32 | throw std::runtime_error{std::format("failed to generate UUID(v7): {} ({}, code {})", ERR_reason_error_string(e), ERR_lib_error_string(e), e)}; | 37 | unsigned long e = ERR_get_error(); |
| 33 | } | 38 | throw std::runtime_error{std::format( |
| 39 | "failed to generate UUID(v7): {} ({}, code {})", | ||
| 40 | ERR_reason_error_string(e), ERR_lib_error_string(e), e)}; | ||
| 41 | } | ||
| 34 | 42 | ||
| 35 | auto version = std::uint64_t{0b0111}; | 43 | auto version = std::uint64_t{0b0111}; |
| 36 | auto variant = std::uint64_t{0b10}; | 44 | auto variant = std::uint64_t{0b10}; |
| 37 | 45 | ||
| 38 | high_ |= unix_time_ms << 16; | 46 | high_ |= unix_time_ms << 16; |
| 39 | high_ |= version << 12; | 47 | high_ |= version << 12; |
| 40 | high_ |= std::uint64_t{rand[0]} << 4; | 48 | high_ |= std::uint64_t{rand[0]} << 4; |
| 41 | high_ |= std::uint64_t{rand[1]}; | 49 | high_ |= std::uint64_t{rand[1]}; |
| 42 | low_ |= variant << 62; | 50 | low_ |= variant << 62; |
| 43 | low_ |= std::uint64_t{rand[2]} << 54; | 51 | low_ |= std::uint64_t{rand[2]} << 54; |
| 44 | low_ |= std::uint64_t{rand[3]} << 48; | 52 | low_ |= std::uint64_t{rand[3]} << 48; |
| 45 | low_ |= std::uint64_t{rand[4]} << 40; | 53 | low_ |= std::uint64_t{rand[4]} << 40; |
| 46 | low_ |= std::uint64_t{rand[5]} << 32; | 54 | low_ |= std::uint64_t{rand[5]} << 32; |
| 47 | low_ |= std::uint64_t{rand[6]} << 24; | 55 | low_ |= std::uint64_t{rand[6]} << 24; |
| 48 | low_ |= std::uint64_t{rand[7]} << 16; | 56 | low_ |= std::uint64_t{rand[7]} << 16; |
| 49 | low_ |= std::uint64_t{rand[8]} << 8; | 57 | low_ |= std::uint64_t{rand[8]} << 8; |
| 50 | low_ |= std::uint64_t{rand[9]}; | 58 | low_ |= std::uint64_t{rand[9]}; |
| 51 | } | 59 | } |
| 52 | 60 | ||
| 53 | auto format(std::array<char, 37>& target) -> void { | 61 | auto format(std::array<char, 37>& target) -> void |
| 54 | auto high_high = (high_ & 0xffff'ffff'0000'0000) >> 32; | 62 | { |
| 55 | auto high_low_high = (high_ & 0x0000'0000'ffff'0000) >> 16; | 63 | auto high_high = (high_ & 0xffff'ffff'0000'0000) >> 32; |
| 56 | auto low_low_high = (high_ & 0x0000'0000'0000'ffff) >> 0; | 64 | auto high_low_high = (high_ & 0x0000'0000'ffff'0000) >> 16; |
| 57 | auto high_low = (low_ & 0xffff'0000'0000'0000) >> 48; | 65 | auto low_low_high = (high_ & 0x0000'0000'0000'ffff) >> 0; |
| 58 | auto low_low = (low_ & 0x0000'ffff'ffff'ffff) >> 0; | 66 | auto high_low = (low_ & 0xffff'0000'0000'0000) >> 48; |
| 67 | auto low_low = (low_ & 0x0000'ffff'ffff'ffff) >> 0; | ||
| 59 | 68 | ||
| 60 | std::format_to(target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}", | 69 | std::format_to( |
| 61 | high_high, high_low_high, low_low_high, high_low, low_low); | 70 | target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}", high_high, |
| 62 | target.back() = '\0'; | 71 | high_low_high, low_low_high, high_low, low_low); |
| 63 | } | 72 | target.back() = '\0'; |
| 64 | }; | 73 | } |
| 74 | }; | ||
| 65 | 75 | ||
| 66 | export class id { | 76 | export class id |
| 67 | std::array<char, 37> chars_; | 77 | { |
| 78 | std::array<char, 37> chars_; | ||
| 68 | 79 | ||
| 69 | public: | 80 | public: |
| 70 | id() { | 81 | id() { uuid7{}.format(chars_); } |
| 71 | uuid7{}.format(chars_); | ||
| 72 | } | ||
| 73 | 82 | ||
| 74 | auto as_string() const -> util::zstring_view { | 83 | auto as_string() const -> util::zstring_view |
| 75 | return util::zstring_view{chars_.data(), chars_.size() - 1}; | 84 | { |
| 76 | } | 85 | return util::zstring_view{chars_.data(), chars_.size() - 1}; |
| 77 | }; | 86 | } |
| 87 | }; | ||
| 78 | 88 | ||
| 79 | } // namespace routemon::trace | 89 | } // namespace routemon::trace |