summaryrefslogtreecommitdiffstats
path: root/server/src/trace.cppm
diff options
context:
space:
mode:
authorRutger Broekhoff2026-08-28 18:03:05 +0200
committerRutger Broekhoff2026-08-28 18:03:05 +0200
commit973aec43ea54bbf95b64fbcb636403401d1ca60e (patch)
tree41b7911c420766a9b463245b9296f44c5bf35258 /server/src/trace.cppm
downloadroutemon-973aec43ea54bbf95b64fbcb636403401d1ca60e.tar.gz
routemon-973aec43ea54bbf95b64fbcb636403401d1ca60e.zip
Import from e4b104792206ee7ea64bf39c6b7d2c0c230f9d14
Diffstat (limited to 'server/src/trace.cppm')
-rw-r--r--server/src/trace.cppm79
1 files changed, 79 insertions, 0 deletions
diff --git a/server/src/trace.cppm b/server/src/trace.cppm
new file mode 100644
index 0000000..00ecd05
--- /dev/null
+++ b/server/src/trace.cppm
@@ -0,0 +1,79 @@
1module;
2
3// Might as well since we're using OpenSSL
4#include <openssl/err.h>
5#include <openssl/rand.h>
6
7export module routemon:trace;
8
9import std;
10import :util;
11
12namespace routemon::trace {
13
14 class uuid7 {
15 std::uint64_t high_ = 0;
16 std::uint64_t low_ = 0;
17
18 public:
19 uuid7() {
20 namespace chrono = std::chrono;
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 if (unix_time_ms_signed < 0)
23 throw std::runtime_error{"system time before UNIX epoch"};
24 auto const unix_time_ms = static_cast<std::uint64_t>(unix_time_ms_signed);
25 if (std::countl_zero(unix_time_ms) < 16)
26 throw std::runtime_error{"system time too great"};
27
28 auto rand = std::array<unsigned char, 10>{};
29 int s = RAND_bytes(rand.data(), static_cast<int>(rand.size()));
30 if (s != 1) {
31 unsigned long e = ERR_get_error();
32 throw std::runtime_error{std::format("failed to generate UUID(v7): {} ({}, code {})", ERR_reason_error_string(e), ERR_lib_error_string(e), e)};
33 }
34
35 auto version = std::uint64_t{0b0111};
36 auto variant = std::uint64_t{0b10};
37
38 high_ |= unix_time_ms << 16;
39 high_ |= version << 12;
40 high_ |= std::uint64_t{rand[0]} << 4;
41 high_ |= std::uint64_t{rand[1]};
42 low_ |= variant << 62;
43 low_ |= std::uint64_t{rand[2]} << 54;
44 low_ |= std::uint64_t{rand[3]} << 48;
45 low_ |= std::uint64_t{rand[4]} << 40;
46 low_ |= std::uint64_t{rand[5]} << 32;
47 low_ |= std::uint64_t{rand[6]} << 24;
48 low_ |= std::uint64_t{rand[7]} << 16;
49 low_ |= std::uint64_t{rand[8]} << 8;
50 low_ |= std::uint64_t{rand[9]};
51 }
52
53 auto format(std::array<char, 37>& target) -> void {
54 auto high_high = (high_ & 0xffff'ffff'0000'0000) >> 32;
55 auto high_low_high = (high_ & 0x0000'0000'ffff'0000) >> 16;
56 auto low_low_high = (high_ & 0x0000'0000'0000'ffff) >> 0;
57 auto high_low = (low_ & 0xffff'0000'0000'0000) >> 48;
58 auto low_low = (low_ & 0x0000'ffff'ffff'ffff) >> 0;
59
60 std::format_to(target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}",
61 high_high, high_low_high, low_low_high, high_low, low_low);
62 target.back() = '\0';
63 }
64 };
65
66 export class id {
67 std::array<char, 37> chars_;
68
69 public:
70 id() {
71 uuid7{}.format(chars_);
72 }
73
74 auto as_string() const -> util::zstring_view {
75 return util::zstring_view{chars_.data(), chars_.size() - 1};
76 }
77 };
78
79} // namespace routemon::trace