diff options
-rw-r--r-- | spec/util_uuid_spec.lua | 22 | ||||
-rw-r--r-- | util/uuid.lua | 17 |
2 files changed, 39 insertions, 0 deletions
diff --git a/spec/util_uuid_spec.lua b/spec/util_uuid_spec.lua index 46400d00..7157d0ec 100644 --- a/spec/util_uuid_spec.lua +++ b/spec/util_uuid_spec.lua @@ -20,6 +20,28 @@ describe("util.uuid", function() for _ = 1, 100 do assert.is_string(uuid.generate():match(pattern)); end + + assert.truthy(uuid.generate() ~= uuid.generate(), "does not generate the same UUIDv4 twice") + end); + end); + describe("#v7", function() + it("should also follow the UUID pattern", function() + local pattern = "^" .. table.concat({ + string.rep("%x", 8), + string.rep("%x", 4), + "7" .. -- version + string.rep("%x", 3), + "[89ab]" .. -- reserved bits of 1 and 0 + string.rep("%x", 3), + string.rep("%x", 12), + }, "%-") .. "$"; + + local one = uuid.v7(); -- one before the loop to ensure some time passes + for _ = 1, 100 do + assert.is_string(uuid.v7():match(pattern)); + end + -- one after the loop when some time should have passed + assert.truthy(one < uuid.v7(), "should be ordererd") end); end); end); diff --git a/util/uuid.lua b/util/uuid.lua index 41c2e9cd..a70750bb 100644 --- a/util/uuid.lua +++ b/util/uuid.lua @@ -8,8 +8,10 @@ local random = require "prosody.util.random"; local random_bytes = random.bytes; +local time = require "prosody.util.time"; local hex = require "prosody.util.hex".encode; local m_ceil = math.ceil; +local m_floor = math.floor; local function get_nibbles(n) return hex(random_bytes(m_ceil(n/2))):sub(1, n); @@ -24,7 +26,22 @@ local function generate() return get_nibbles(8).."-"..get_nibbles(4).."-4"..get_nibbles(3).."-"..(get_twobits())..get_nibbles(3).."-"..get_nibbles(12); end +local function generate_v7() + -- Sortable based on time and random + -- https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-01#section-4.4 + local t = time.now(); + local unixts = m_floor(t); + local unixts_a = m_floor(unixts / 16); + local unixts_b = m_floor(unixts % 16); + local subsec = t % 1; + local subsec_a = m_floor(subsec * 0x1000); + local subsec_b = m_floor(subsec * 0x1000000) % 0x1000; + return ("%08x-%x%03x-7%03x-%4s-%12s"):format(unixts_a, unixts_b, subsec_a, subsec_b, get_twobits() .. get_nibbles(3), get_nibbles(12)); +end + return { + v4 = generate; + v7 = generate_v7; get_nibbles=get_nibbles; generate = generate ; -- COMPAT |