5 Commits
Author SHA1 Message Date
server 873e47d42b new actions 2026-03-23 21:59:26 -07:00
server f8265fbb3b Update changes.md (#75)
Fixed bad console output
2026-01-11 15:25:53 -08:00
server b995b1c0a7 Update changes.md
fixed hyperlink
2026-01-11 14:24:01 -08:00
server 66e922a971 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
2026-01-11 14:18:43 -08:00
server 92659c7eaf Update README.md (#71) 2026-01-03 22:36:17 -08:00
5 changed files with 235 additions and 69 deletions
+20 -29
View File
@@ -1,41 +1,32 @@
name: Build & Run tests Ubuntu name: Lua Unit Tests (Matrix)
on: on:
push: push:
branches: [ master ] branches: [ main ]
pull_request: pull_request:
branches: [ master ] branches: [ main ]
jobs: jobs:
build: test:
runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false
matrix: matrix:
build-type: [Release] # Debug luaVersion: ["5.1", "5.2", "5.3", "5.4", "luajit-2.1.0-beta3"]
lua: ["lua 5.1", "lua 5.2", "lua 5.3", "lua 5.4", "luajit 2.1.0-beta3"]
os: ["ubuntu-latest"]
runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - name: Checkout repository
with: uses: actions/checkout@v4
submodules: recursive
- uses: actions/setup-python@v2 - name: Setup Lua
with: uses: leafo/gh-actions-lua@v10
python-version: '3.10' with:
luaVersion: ${{ matrix.luaVersion }}
- name: Setup env - name: Verify Lua version
run: | run: lua -v
pip install hererocks
hererocks lua-pkg --${{ matrix.lua }} -rlatest
- name: Install lanes and multi - name: Run unit tests
run: | run: |
source ${{github.workspace}}/lua-pkg/bin/activate # Replace with your actual test file
luarocks install lanes lua tests/multi_test.lua
luarocks install rockspecs/multi-16.0-0.rockspec
- name: Run Tests
run: |
source ${{github.workspace}}/lua-pkg/bin/activate
lua tests/runtests.lua
+1 -1
View File
@@ -12,7 +12,7 @@ My multitasking library for lua. It is a pure lua binding, with exceptions of th
</br> </br>
Progress is being made in [v16.1.0](https://github.com/rayaman/multi/tree/v16.1.0) Progress is being made in [v16.2.0](https://github.com/rayaman/multi/tree/v16.2.0)
--- ---
</br> </br>
+19 -3
View File
@@ -1,6 +1,7 @@
# Changelog # Changelog
Table of contents Table of contents
--- ---
[Update 16.2.0 - TimeStamps and UUIDs](#update-1620---timestamps-and-uuids-and-bugfixes)</br>
[Update 16.1.0 - The Flow State](#update-1610---the-flow-state)</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.1 - Bug fix](#update-1601---bug-fix)</br>
[Update 16.0.0 - Connecting the dots](#update-1600---getting-the-priorities-straight)</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> [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) [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 # Update 16.1.0 - The Flow State
Added Added
--- ---
@@ -615,13 +629,15 @@ Added
Output: Output:
``` ```
I run before all and control if things go! I run before all and control if execution should continue!
Hi 3 Hi 3
Hi 1 Hi 1
I run before all and control if execution should continue!
Hi 3
Hi 2
Test 1 Test 1
Test 2 Test 2
Test 3 Test 3
I run after it all!
``` ```
**Note:** Concat of connections does modify internal events on both connections depending on the direction func .. conn or conn .. func See implemention below: **Note:** Concat of connections does modify internal events on both connections depending on the direction func .. conn or conn .. func See implemention below:
@@ -3656,4 +3672,4 @@ end
event:Manager() event:Manager()
--event:CManager() --event:CManager()
--event:UManager() -- One of the few things that lived in name and spirit the u just became lowercase haha --event:UManager() -- One of the few things that lived in name and spirit the u just became lowercase haha
``` ```
+153 -36
View File
@@ -92,7 +92,7 @@ function multi.getTypes()
return types return types
end end
multi.Version = "16.1.0" multi.Version = "16.2.0"
multi.Name = "root" multi.Name = "root"
multi.NIL = {Type="NIL"} multi.NIL = {Type="NIL"}
local NIL = multi.NIL local NIL = multi.NIL
@@ -702,49 +702,21 @@ local time = os.time
local ok, chronos = pcall(require, "chronos") -- hpc local ok, chronos = pcall(require, "chronos") -- hpc
if ok then if ok then
math.randomseed(chronos.nanotime()*1000000000) math.randomseed(chronos.nanotime()*100000000)
else else
math.randomseed(time()) math.randomseed(time())
end 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) function multi:create(ref)
ref.UID = self.UUID() ref.UID = multi.generate_uuid7()
self.OnObjectCreated:Fire(ref, self) self.OnObjectCreated:Fire(ref, self)
return self return self
end end
function multi:GetCreationTimestamp()
return multi.extract_uuid7_timestamp(self.UID).iso8601
end
function multi:setName(name) function multi:setName(name)
self.Name = name self.Name = name
return self return self
@@ -1602,7 +1574,10 @@ end
function thread:newFunctionBase(generator, holdme, TYPE) function thread:newFunctionBase(generator, holdme, TYPE)
return function() return function()
local tfunc = {} local UID = multi.generate_uuid7()
local tfunc = {
GetCreationTimestamp = function() return multi.extract_uuid7_timestamp(UID).iso8601 end,
}
tfunc.Active = true tfunc.Active = true
function tfunc:Pause() function tfunc:Pause()
self.Active = false self.Active = false
@@ -1810,6 +1785,10 @@ function thread:newThread(name, func, ...)
return self._isPaused return self._isPaused
end end
function c:GetCreationTimestamp()
return multi.extract_uuid7_timestamp(self.UID).iso8601
end
local resumed = false local resumed = false
function c:Pause() function c:Pause()
if not self._isPaused then if not self._isPaused then
@@ -2677,6 +2656,144 @@ function multi.success(...)
io.write("\x1b[92mSUCCESS:\x1b[0m " .. table.concat(t," ") .. "\n") io.write("\x1b[92mSUCCESS:\x1b[0m " .. table.concat(t," ") .. "\n")
end 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 -- Old things for compatability
multi.GetType = multi.getType multi.GetType = multi.getType
multi.IsPaused = multi.isPaused multi.IsPaused = multi.isPaused
+42
View File
@@ -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",
}
}