Class: Protobuf::Nats::UUIDv7Helper
- Inherits:
-
Object
- Object
- Protobuf::Nats::UUIDv7Helper
- Defined in:
- lib/protobuf/nats/uuidv7_helper.rb
Constant Summary collapse
- UUIDV7_REGEX =
Strict RFC 9562 UUIDv7 shape, matching what .generate produces. The strictness matters to callers like the server's stale-request shedding: extract_timestamp is permissive, and treating a non-UUID token (e.g. from a foreign client) as a timestamp would compute a garbage age.
/\A\h{8}-\h{4}-7\h{3}-\h{4}-\h{12}\z/
Class Method Summary collapse
-
.age_in_seconds(uuid, current_time: Time.now) ⇒ Float?
Calculate the age of a UUIDv7 in seconds Returns nil if the UUID cannot be parsed.
-
.age_ms(token) ⇒ Object
Age (integer ms) of a strictly-validated UUIDv7 token, or nil for a non-UUIDv7 token.
-
.extract_timestamp(uuid) ⇒ Time?
Extract the Unix timestamp (in seconds) from a UUIDv7 string Returns nil if the UUID cannot be parsed.
-
.generate ⇒ String
Generate a UUIDv7 string without a CSPRNG.
Class Method Details
.age_in_seconds(uuid, current_time: Time.now) ⇒ Float?
Calculate the age of a UUIDv7 in seconds Returns nil if the UUID cannot be parsed
52 53 54 55 56 57 |
# File 'lib/protobuf/nats/uuidv7_helper.rb', line 52 def self.age_in_seconds(uuid, current_time: Time.now) = (uuid) return nil unless current_time - end |
.age_ms(token) ⇒ Object
Age (integer ms) of a strictly-validated UUIDv7 token, or nil for a non-UUIDv7 token. Allocation-light: runs per message on the server's intake path.
68 69 70 71 72 |
# File 'lib/protobuf/nats/uuidv7_helper.rb', line 68 def self.age_ms(token) return nil unless token.is_a?(String) && token.match?(UUIDV7_REGEX) unix_ts_ms = (token[0, 8].to_i(16) << 16) | token[9, 4].to_i(16) ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) - unix_ts_ms end |
.extract_timestamp(uuid) ⇒ Time?
Extract the Unix timestamp (in seconds) from a UUIDv7 string Returns nil if the UUID cannot be parsed
32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/protobuf/nats/uuidv7_helper.rb', line 32 def self.(uuid) return nil unless uuid.is_a?(String) # UUIDv7 format: first 48 bits (12 hex chars) are Unix timestamp in milliseconds # Remove dashes and extract the timestamp portion uuid_bytes = uuid.gsub('-', '') return nil if uuid_bytes.length < 12 = uuid_bytes[0...12].to_i(16) Time.at( / 1000.0) rescue => e nil end |
.generate ⇒ String
Generate a UUIDv7 string without a CSPRNG. Callers that only need a 48-bit millisecond timestamp prefix (so #age_in_seconds can report a value) plus enough randomness to stay unique among concurrent generators don't need SecureRandom: its gen_random call dominated per-request CPU and garbage (measured ~6.8us/op and 4 GC-triggering allocations). A per-thread non-cryptographic Random halves both. The layout still matches RFC 9562 UUIDv7 (version 7 + RFC 4122 variant bits).
13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/protobuf/nats/uuidv7_helper.rb', line 13 def self.generate unix_ts_ms = ::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond) & 0xffffffffffff rng = (::Thread.current[:pb_nats_uuid_rng] ||= ::Random.new) format( "%08x-%04x-%04x-%04x-%04x%08x", (unix_ts_ms >> 16) & 0xffffffff, # 32 high bits of the ms timestamp unix_ts_ms & 0xffff, # 16 low bits of the ms timestamp (0x7000 | rng.rand(0x1000)), # version 7 + 12 random bits (0x8000 | rng.rand(0x4000)), # RFC 4122 variant + 14 random bits rng.rand(0x10000), # 16 random bits rng.rand(0x100000000) # 32 random bits ) end |