mirror of
https://github.com/rayaman/multi.git
synced 2026-09-04 23:17:35 -04:00
fixing issue with timestamp using lua 5.1/luajit (#72)
* fixing issue with timestamp using lua 5.1/luajit * fixed issues, testing * bumped up version number * updated docs
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# Changelog
|
||||
Table of contents
|
||||
---
|
||||
[Update 16.2.0 - TimeStamps and UUIDs](#update-1620---timestamps-and-uuids)</br>
|
||||
[Update 16.1.0 - The Flow State](#update-1610---the-flow-state)</br>
|
||||
[Update 16.0.1 - Bug fix](#update-1601---bug-fix)</br>
|
||||
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</br>
|
||||
@@ -60,6 +61,19 @@ Table of contents
|
||||
[Update: EventManager 1.0.0 - Error checking](#update-eventmanager-100---error-checking)</br>
|
||||
[Version: EventManager 0.0.1 - In The Beginning things were very different](#version-eventmanager-001---in-the-beginning-things-were-very-different)
|
||||
|
||||
# Update 16.2.0 - TimeStamps and UUIDs and bugfixes
|
||||
Added
|
||||
---
|
||||
- threadedfunctions, multiobjs and threads contain new method: `GetCreationTimestamp()` With will return a string formated date time using ISO 8601
|
||||
|
||||
Changed
|
||||
---
|
||||
- Internal uuid functions to not use bitwise operators
|
||||
|
||||
Fixed
|
||||
---
|
||||
- [Bitwise operations break lua 5.1/luajit](https://github.com/rayaman/multi/issues/73)
|
||||
|
||||
# Update 16.1.0 - The Flow State
|
||||
Added
|
||||
---
|
||||
|
||||
@@ -92,7 +92,7 @@ function multi.getTypes()
|
||||
return types
|
||||
end
|
||||
|
||||
multi.Version = "16.1.0"
|
||||
multi.Version = "16.2.0"
|
||||
multi.Name = "root"
|
||||
multi.NIL = {Type="NIL"}
|
||||
local NIL = multi.NIL
|
||||
@@ -702,49 +702,21 @@ local time = os.time
|
||||
local ok, chronos = pcall(require, "chronos") -- hpc
|
||||
|
||||
if ok then
|
||||
math.randomseed(chronos.nanotime()*1000000000)
|
||||
math.randomseed(chronos.nanotime()*100000000)
|
||||
else
|
||||
math.randomseed(time())
|
||||
end
|
||||
|
||||
function multi.UUID()
|
||||
|
||||
-- random bytes
|
||||
local value = {}
|
||||
for i = 1, 16 do
|
||||
value[i] = math.random(0, 255)
|
||||
end
|
||||
|
||||
-- current timestamp in ms
|
||||
local timestamp = time() * 1000
|
||||
|
||||
-- timestamp
|
||||
value[1] = (timestamp >> 40) & 0xFF
|
||||
value[2] = (timestamp >> 32) & 0xFF
|
||||
value[3] = (timestamp >> 24) & 0xFF
|
||||
value[4] = (timestamp >> 16) & 0xFF
|
||||
value[5] = (timestamp >> 8) & 0xFF
|
||||
value[6] = timestamp & 0xFF
|
||||
|
||||
-- version and variant
|
||||
value[7] = (value[7] & 0x0F) | 0x70
|
||||
value[9] = (value[9] & 0x3F) | 0x80
|
||||
res = ""
|
||||
for i = 1, #value do
|
||||
res = res .. string.format('%02x', value[i])
|
||||
if i == 4 or i == 6 or i == 8 or i == 10 then
|
||||
res = res .. "-"
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function multi:create(ref)
|
||||
ref.UID = self.UUID()
|
||||
ref.UID = multi.generate_uuid7()
|
||||
self.OnObjectCreated:Fire(ref, self)
|
||||
return self
|
||||
end
|
||||
|
||||
function multi:GetCreationTimestamp()
|
||||
return multi.extract_uuid7_timestamp(self.UID).iso8601
|
||||
end
|
||||
|
||||
function multi:setName(name)
|
||||
self.Name = name
|
||||
return self
|
||||
@@ -1602,7 +1574,10 @@ end
|
||||
|
||||
function thread:newFunctionBase(generator, holdme, TYPE)
|
||||
return function()
|
||||
local tfunc = {}
|
||||
local UID = multi.generate_uuid7()
|
||||
local tfunc = {
|
||||
GetCreationTimestamp = function() return multi.extract_uuid7_timestamp(UID).iso8601 end,
|
||||
}
|
||||
tfunc.Active = true
|
||||
function tfunc:Pause()
|
||||
self.Active = false
|
||||
@@ -1810,6 +1785,10 @@ function thread:newThread(name, func, ...)
|
||||
return self._isPaused
|
||||
end
|
||||
|
||||
function c:GetCreationTimestamp()
|
||||
return multi.extract_uuid7_timestamp(self.UID).iso8601
|
||||
end
|
||||
|
||||
local resumed = false
|
||||
function c:Pause()
|
||||
if not self._isPaused then
|
||||
@@ -2677,6 +2656,144 @@ function multi.success(...)
|
||||
io.write("\x1b[92mSUCCESS:\x1b[0m " .. table.concat(t," ") .. "\n")
|
||||
end
|
||||
|
||||
-- UUID Handling
|
||||
local function get_timestamp_ms()
|
||||
-- os.time() gives seconds, we need milliseconds
|
||||
-- For sub-second precision, we'd need a C extension in real use
|
||||
-- Here we'll use seconds * 1000 + a pseudo-random millisecond component
|
||||
local sec = os.time()
|
||||
return sec * 1000
|
||||
end
|
||||
|
||||
-- Convert number to hex string with specified length
|
||||
local function to_hex(num, len)
|
||||
local hex = string.format("%x", num)
|
||||
return string.rep("0", len - #hex) .. hex
|
||||
end
|
||||
|
||||
-- Generate random hex string of specified length
|
||||
local function random_hex(len)
|
||||
local result = ""
|
||||
for i = 1, len do
|
||||
result = result .. string.format("%x", math.random(0, 15))
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
multi.generate_uuid7 = function()
|
||||
-- Seed random number generator with current time
|
||||
math.randomseed(os.time() * os.clock() * 1000000)
|
||||
|
||||
-- Get timestamp in milliseconds
|
||||
local timestamp_ms = get_timestamp_ms()
|
||||
|
||||
-- Convert timestamp to 12 hex characters (48 bits)
|
||||
-- Split into high and low parts
|
||||
local high = math.floor(timestamp_ms / 16777216) -- Upper 24 bits
|
||||
local low = timestamp_ms % 16777216 -- Lower 24 bits
|
||||
|
||||
local time_high = to_hex(high, 6)
|
||||
local time_low = to_hex(low, 6)
|
||||
|
||||
-- Version and random bits (4 bits version + 12 bits random = 16 bits = 4 hex)
|
||||
local ver_rand = random_hex(3)
|
||||
local version_field = "7" .. ver_rand -- Version 7
|
||||
|
||||
-- Variant and random bits (2 bits variant + 14 bits random = 16 bits = 4 hex)
|
||||
local rand_val = math.random(0, 16383) -- 14 bits of random
|
||||
local variant_field = to_hex(0x8000 + rand_val, 4) -- Set variant bits to 10
|
||||
|
||||
-- Remaining random bits (48 bits = 12 hex)
|
||||
local random_field = random_hex(12)
|
||||
|
||||
-- Assemble UUID: xxxxxxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx
|
||||
local uuid = string.format("%s%s-%s-%s-%s-%s",
|
||||
time_high:sub(1, 2),
|
||||
time_high:sub(3, 6) .. time_low:sub(1, 2),
|
||||
time_low:sub(3, 6),
|
||||
version_field,
|
||||
variant_field,
|
||||
random_field
|
||||
)
|
||||
return uuid
|
||||
end
|
||||
|
||||
local function is_leap(y)
|
||||
return (y % 4 == 0 and y % 100 ~= 0) or (y % 400 == 0)
|
||||
end
|
||||
|
||||
local function format_date(seconds)
|
||||
local days = math.floor(seconds / 86400)
|
||||
local remainder = seconds % 86400
|
||||
local hours = math.floor(remainder / 3600)
|
||||
remainder = remainder % 3600
|
||||
local minutes = math.floor(remainder / 60)
|
||||
local secs = remainder % 60
|
||||
|
||||
-- Calculate year, month, day from days since epoch (1970-01-01)
|
||||
local year = 1970
|
||||
local month = 1
|
||||
local day = 1 + days
|
||||
|
||||
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
|
||||
while true do
|
||||
local days_in_year = is_leap(year) and 366 or 365
|
||||
if day <= days_in_year then break end
|
||||
day = day - days_in_year
|
||||
year = year + 1
|
||||
end
|
||||
|
||||
while true do
|
||||
local dim = days_in_month[month]
|
||||
if month == 2 and is_leap(year) then dim = 29 end
|
||||
if day <= dim then break end
|
||||
day = day - dim
|
||||
month = month + 1
|
||||
end
|
||||
|
||||
return string.format("%04d-%02d-%02d %02d:%02d:%02d",
|
||||
year, month, day, hours, minutes, secs)
|
||||
end
|
||||
|
||||
multi.extract_uuid7_timestamp = function(uuid_str)
|
||||
-- Remove hyphens from UUID
|
||||
local hex = uuid_str:gsub("-", "")
|
||||
|
||||
-- Validate length
|
||||
if #hex ~= 32 then
|
||||
return nil, "Invalid UUID length"
|
||||
end
|
||||
|
||||
-- Extract first 12 hex characters (48 bits = timestamp in ms)
|
||||
local timestamp_hex = hex:sub(1, 12)
|
||||
|
||||
-- Convert hex to decimal - need to handle large numbers
|
||||
-- Break into two parts to avoid overflow
|
||||
local high = tonumber(timestamp_hex:sub(1, 6), 16)
|
||||
local low = tonumber(timestamp_hex:sub(7, 12), 16)
|
||||
local timestamp_ms = high * 16777216 + low -- 16^6 = 16777216
|
||||
|
||||
if not timestamp_ms then
|
||||
return nil, "Failed to parse timestamp"
|
||||
end
|
||||
|
||||
-- Convert milliseconds to seconds
|
||||
local timestamp_sec = math.floor(timestamp_ms / 1000)
|
||||
local ms_remainder = timestamp_ms % 1000
|
||||
|
||||
-- Manual date calculation for large timestamps
|
||||
|
||||
local date_str = format_date(timestamp_sec)
|
||||
|
||||
return {
|
||||
milliseconds = timestamp_ms,
|
||||
seconds = timestamp_sec,
|
||||
date = date_str,
|
||||
iso8601 = date_str:gsub(" ", "T") .. string.format(".%03dZ", ms_remainder)
|
||||
}
|
||||
end
|
||||
|
||||
-- Old things for compatability
|
||||
multi.GetType = multi.getType
|
||||
multi.IsPaused = multi.isPaused
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package = "multi"
|
||||
version = "16.2-0"
|
||||
source = {
|
||||
url = "git://github.com/rayaman/multi.git",
|
||||
tag = "v16.2.0",
|
||||
}
|
||||
description = {
|
||||
summary = "Lua Multi tasking library",
|
||||
detailed = [[
|
||||
This library contains many methods for multi tasking. Features non coroutine based multi-tasking, coroutine based multi-tasking, and system threading (Requires use of an integration).
|
||||
Check github for documentation.
|
||||
]],
|
||||
homepage = "https://github.com/rayaman/multi",
|
||||
license = "MIT"
|
||||
}
|
||||
dependencies = {
|
||||
"lua >= 5.1"
|
||||
}
|
||||
build = {
|
||||
type = "builtin",
|
||||
modules = {
|
||||
["multi"] = "init.lua",
|
||||
["multi.integration.lanesManager"] = "integration/lanesManager/init.lua",
|
||||
["multi.integration.lanesManager.extensions"] = "integration/lanesManager/extensions.lua",
|
||||
["multi.integration.lanesManager.threads"] = "integration/lanesManager/threads.lua",
|
||||
["multi.integration.loveManager"] = "integration/loveManager/init.lua",
|
||||
["multi.integration.loveManager.extensions"] = "integration/loveManager/extensions.lua",
|
||||
["multi.integration.loveManager.threads"] = "integration/loveManager/threads.lua",
|
||||
["multi.integration.loveManager.utils"] = "integration/loveManager/threads.lua",
|
||||
--["multi.integration.lovrManager"] = "integration/lovrManager/init.lua",
|
||||
--["multi.integration.lovrManager.extensions"] = "integration/lovrManager/extensions.lua",
|
||||
--["multi.integration.lovrManager.threads"] = "integration/lovrManager/threads.lua",
|
||||
["multi.integration.pseudoManager"] = "integration/pseudoManager/init.lua",
|
||||
["multi.integration.pseudoManager.extensions"] = "integration/pseudoManager/extensions.lua",
|
||||
["multi.integration.pseudoManager.threads"] = "integration/pseudoManager/threads.lua",
|
||||
["multi.integration.luvitManager"] = "integration/luvitManager.lua",
|
||||
["multi.integration.threading"] = "integration/threading.lua",
|
||||
["multi.integration.sharedExtensions"] = "integration/sharedExtensions/init.lua",
|
||||
["multi.integration.priorityManager"] = "integration/priorityManager/init.lua",
|
||||
--["multi.integration.networkManager"] = "integration/networkManager.lua",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user