diff options
Diffstat (limited to 'server/src/trace.cpp')
| -rw-r--r-- | server/src/trace.cpp | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/server/src/trace.cpp b/server/src/trace.cpp new file mode 100644 index 0000000..e7c00d0 --- /dev/null +++ b/server/src/trace.cpp | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | module; | ||
| 2 | |||
| 3 | // Might as well since we're using OpenSSL | ||
| 4 | #include <openssl/err.h> | ||
| 5 | #include <openssl/rand.h> | ||
| 6 | |||
| 7 | module routemon:trace$impl; | ||
| 8 | |||
| 9 | import :trace; | ||
| 10 | |||
| 11 | namespace routemon::trace { | ||
| 12 | |||
| 13 | uuid7::uuid7() | ||
| 14 | { | ||
| 15 | namespace chrono = std::chrono; | ||
| 16 | auto const unix_time_ms_signed = static_cast<std::int64_t>( | ||
| 17 | chrono::duration_cast<chrono::milliseconds>( | ||
| 18 | chrono::system_clock::now().time_since_epoch()) | ||
| 19 | .count()); | ||
| 20 | if (unix_time_ms_signed < 0) | ||
| 21 | throw std::runtime_error{"system time before UNIX epoch"}; | ||
| 22 | auto const unix_time_ms = static_cast<std::uint64_t>(unix_time_ms_signed); | ||
| 23 | if (std::countl_zero(unix_time_ms) < 16) | ||
| 24 | throw std::runtime_error{"system time too great"}; | ||
| 25 | |||
| 26 | auto rand = std::array<unsigned char, 10>{}; | ||
| 27 | int s = RAND_bytes(rand.data(), static_cast<int>(rand.size())); | ||
| 28 | if (s != 1) | ||
| 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 | |||
| 36 | auto version = std::uint64_t{0b0111}; | ||
| 37 | auto variant = std::uint64_t{0b10}; | ||
| 38 | |||
| 39 | hi_ |= unix_time_ms << 16; | ||
| 40 | hi_ |= version << 12; | ||
| 41 | hi_ |= std::uint64_t{rand[0]} << 4; | ||
| 42 | hi_ |= std::uint64_t{rand[1]}; | ||
| 43 | lo_ |= variant << 62; | ||
| 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 | } | ||
| 53 | |||
| 54 | auto uuid7::format(std::array<char, 37>& target) -> void | ||
| 55 | { | ||
| 56 | auto p____hi_hi = (hi_ & 0xffff'ffff'0000'0000) >> 32; | ||
| 57 | auto p_hi_lo_hi = (hi_ & 0x0000'0000'ffff'0000) >> 16; | ||
| 58 | auto p_lo_lo_hi = (hi_ & 0x0000'0000'0000'ffff) >> 0; | ||
| 59 | auto p____hi_lo = (lo_ & 0xffff'0000'0000'0000) >> 48; | ||
| 60 | auto p____lo_lo = (lo_ & 0x0000'ffff'ffff'ffff) >> 0; | ||
| 61 | |||
| 62 | std::format_to( | ||
| 63 | target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}", p____hi_hi, | ||
| 64 | p_hi_lo_hi, p_lo_lo_hi, p____hi_lo, p____lo_lo); | ||
| 65 | target.back() = '\0'; | ||
| 66 | } | ||
| 67 | |||
| 68 | id::id() { uuid7{}.format(chars_); } | ||
| 69 | |||
| 70 | auto id::as_string() const -> util::zstring_view | ||
| 71 | { | ||
| 72 | return util::zstring_view{chars_.data(), chars_.size() - 1}; | ||
| 73 | } | ||
| 74 | |||
| 75 | } // namespace routemon::trace | ||