Skip to content

Commit

Permalink
feat: cross server sync support for wow10 only
Browse files Browse the repository at this point in the history
  • Loading branch information
lantisnt committed Apr 9, 2023
1 parent f7db118 commit ca7f267
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 22 deletions.
1 change: 1 addition & 0 deletions LibEventSourcing.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<Script file="source\SlashCommands.lua"/>
<Script file="source\SortedList.lua"/>
<Script file="source\LogEntry.lua"/>
<Script file="source\LogEntryCrossRealm.lua"/>
<Script file="source\IgnoreEntry.lua"/>
<Script file="source\StateManager.lua"/>
<Script file="source\Message.lua"/>
Expand Down
13 changes: 11 additions & 2 deletions runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@
ls tests/ | grep -v '_' | xargs -I {} lua -l tests/_bootstrap tests/{}
RESULT=$?
if [ $RESULT -eq 0 ]; then
echo "\e[32;1mAll tests passed"
echo "\e[32;1mAll tests passed\e[0m"
else
echo "\e[31;1mSome tests failed"
echo "\e[31;1mSome tests failed\e[0m"
exit 1
fi

ls tests/ | grep -v '_' | xargs -I {} lua -l tests/_bootstrap_wow10 tests/{}
RESULT=$?
if [ $RESULT -eq 0 ]; then
echo "\e[32;1mAll tests passed\e[0m"
else
echo "\e[31;1mSome tests failed\e[0m"
exit 1
fi
29 changes: 9 additions & 20 deletions source/LogEntry.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

local WoW10 = select(4, GetBuildInfo()) >= 100000
if WoW10 then return end

local LogEntry, _ = LibStub:NewLibrary("EventSourcing/LogEntry", 1)
if not LogEntry then
Expand Down Expand Up @@ -28,7 +29,6 @@ local privateCreator = '_a'
local privateCounter = '_b'
local privateTimestamp = '_c'
local privateClass = '_d'
local privateRealm = '_e'



Expand All @@ -37,7 +37,6 @@ LogEntry[privateStaticClass] = 'LE'

local counter = 0
local lastTimestamp = 0
local _, myRealm = Util.getIntegerGuid("player")

-- private constructor
local function constructor(self)
Expand Down Expand Up @@ -74,7 +73,7 @@ function LogEntry.staticClassName(metatable)
end


function LogEntry:new(creator, realm)
function LogEntry:new(creator)
local o = constructor(self)
o[privateClass] = LogEntry.staticClassName(self)

Expand All @@ -87,19 +86,14 @@ function LogEntry:new(creator, realm)
end
o[privateCounter] = counter
if creator == nil then
o[privateCreator], o[privateRealm] = Util.getIntegerGuid("player")
o[privateCreator] = Util.getIntegerGuid("player")
elseif type(creator) == 'string' then
o[privateCreator], o[privateRealm] = Util.getIntegerGuid(creator)
if (o[privateCreator] == nil) or (o[privateRealm] == nil) then
o[privateCreator] = Util.getIntegerGuid(creator)
if (o[privateCreator] == nil) then
error(string.format("Failed to convert string `%s` into number", creator))
end
else
o[privateCreator], o[privateRealm] = creator, realm
if type(o[privateCreator]) ~= 'number' or type(o[privateRealm]) ~= 'number'then
error(string.format("Failed to fill data `creator [%s] -> %s | realm [%s] -> %s` ",
tostring(creator), tostring(o[privateCreator]),
tostring(realm), tostring(o[privateRealm])))
end
o[privateCreator] = creator
end

return o
Expand Down Expand Up @@ -129,18 +123,13 @@ end
Returns the numbers to be used
]]--
function LogEntry:numbersForHash()
return {self[privateTimestamp], self[privateCounter], self[privateRealm] or myRealm, self[privateCreator]}
return {self[privateTimestamp], self[privateCounter], self[privateCreator]}
end

function LogEntry:creator()
return self[privateCreator]
end

function LogEntry:realm()
return self[privateRealm] or myRealm
end


function LogEntry:counter()
return self[privateCounter]
end
Expand All @@ -160,7 +149,7 @@ function LogEntry.sortedList(data)
end

function LogEntry.fields()
return {privateTimestamp, privateCounter, privateRealm, privateCreator}
return {privateTimestamp, privateCounter, privateCreator}
end

function LogEntry:uuid()
Expand Down
167 changes: 167 additions & 0 deletions source/LogEntryCrossRealm.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
local WoW10 = select(4, GetBuildInfo()) >= 100000
if not WoW10 then return end

local LogEntry, _ = LibStub:NewLibrary("EventSourcing/LogEntry", 2)
if not LogEntry then
return
end

local Util = LibStub("EventSourcing/Util")
local SortedList = LibStub("EventSourcing/SortedList")

--[[
LogEntry models an entry in the event log
We use short field names because the field names are serialized to disk.
The assumption is that all field names are private to this file and other files will use functions to get what they need.
Since functions are not serialized we do use descriptive names for the functions
]]--

-- we use a random property name to guarantee people not accessing it.
local privateStaticPrefix = Util.random(6)
local privateStaticClass = privateStaticPrefix .. '_cls'

--[[
These are property constants that we replace for more readability in our code
CHANGING THESE WILL BREAK ALL EXISTING LEDGER ENTRIES
THIS IS ALWAYS A MAJOR BREAKING CHANGE
]]--
local privateCreator = '_a'
local privateCounter = '_b'
local privateTimestamp = '_c'
local privateClass = '_d'
local privateRealm = '_e'



LogEntry.__index = LogEntry
LogEntry[privateStaticClass] = 'LE'

local counter = 0
local lastTimestamp = 0

-- private constructor
local function constructor(self)
local o = {}
setmetatable(o, self)
return o
end

function LogEntry:extend(identifier)
local o = constructor(self)

if (identifier == nil or type(identifier) ~= "string" or string.len(identifier) == 0) then
error("Identifier must be a non-empty string")
end
o.__index = o

-- static properties (won't appear on instances)
o[privateStaticClass] = identifier
return o
end

-- Check if the given table is an subclass of LogEntry
function LogEntry.isSubClassType(child)
return child ~= nil
and type(child) == "table"
and child[privateStaticClass] ~= nil
end

function LogEntry.staticClassName(metatable)
if not LogEntry.isSubClassType(metatable) then
error("Class is not a child of LogEntry")
end
return metatable[privateStaticClass]
end


function LogEntry:new(creator, realm)
local o = constructor(self)
o[privateClass] = LogEntry.staticClassName(self)

o[privateTimestamp] = Util.time()
if o[privateTimestamp] == lastTimestamp then
counter = counter + 1
else
lastTimestamp = o[privateTimestamp]
counter = 0
end
o[privateCounter] = counter
if creator == nil then
o[privateCreator], o[privateRealm] = Util.getIntegerGuid("player")
elseif type(creator) == 'string' then
o[privateCreator], o[privateRealm] = Util.getIntegerGuid(creator)
if (o[privateCreator] == nil) or (o[privateRealm] == nil) then
error(string.format("Failed to convert string `%s` into number", creator))
end
else
o[privateCreator], o[privateRealm] = creator, realm
if type(o[privateCreator]) ~= 'number' or type(o[privateRealm]) ~= 'number'then
error(string.format("Failed to fill data `creator [%s] -> %s | realm [%s] -> %s` ",
tostring(creator), tostring(o[privateCreator]),
tostring(realm), tostring(o[privateRealm])))
end
end

return o
end

function LogEntry:class()
return self[privateClass]
end

function LogEntry:time()
return self[privateTimestamp]
end

function LogEntry:setTime(value)
self[privateTimestamp] = value
end

function LogEntry:setCounter(value)
self[privateCounter] = value
end

function LogEntry:setClass(value)
self[privateClass] = value
end

--[[
Returns the numbers to be used
]]--
function LogEntry:numbersForHash()
return {self[privateTimestamp], self[privateCounter], self[privateRealm], self[privateCreator]}
end

function LogEntry.fields()
return {privateTimestamp, privateCounter, privateRealm, privateCreator}
end

function LogEntry:creator()
return self[privateCreator]
end

function LogEntry:realm()
return self[privateRealm]
end

function LogEntry:counter()
return self[privateCounter]
end

-- return int the weeknumber of this entry
function LogEntry:weekNumber()
return Util.WeekNumber(self[privateTimestamp])
end

-- Return a sorted list set up for log entries
function LogEntry.sortedList(data)
local r = SortedList:new(data or {}, Util.CreateMultiFieldSorter(unpack(LogEntry.fields())), true)
if type(r.uniqueInsert) ~= 'function' then
error("Error creating sorted list but doesn't have unique insert function")
end
return r
end

function LogEntry:uuid()
return table.concat(self:numbersForHash(), '-')
end
87 changes: 87 additions & 0 deletions tests/_bootstrap_wow10.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require "tests/_wowstubs_wow10"

local addonName = "DoesNotMatter"
local addonTable = {}

local function parseXml(xmlFile, prefix)
prefix = prefix or ''
for line in io.lines(xmlFile) do
for file in string.gmatch(line, 'Script file="(.+\.lua)"') do
local search = prefix .. file:gsub('\\', '/');
loadfile(search, "bt", {})(addonName, addonTable)
end
for file in string.gmatch(line, 'Include file="(.+\.xml)"') do
local xmlFile = prefix .. file:gsub('\\', '/');
-- get the new prefix
local newPrefix = string.match(xmlFile, "(.*/).*")
print("new prefix", newPrefix)
parseXml(xmlFile, newPrefix)
end
end
end

parseXml('LibEventSourcing.xml')
math.randomseed(os.time())

local Util = LibStub("EventSourcing/Util")
local assertionStatistics = {
total = 0,
passed = 0,
failed = 0
}
function assertTrue(param, message)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(param == true, "Assertion failed: " .. (message or ''))
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end

function assertFalse(param, message)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(param == false, message or "failed asserting that param is false")
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end

function assertSame(expected, value)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(expected == value, "failed assert that expected " .. (expected or 'NIL') .. " matches " .. (value or 'NIL'))
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end

function assertNotSame(expected, value)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(expected ~= value, "failed assert that expected " .. (expected or 'NIL') .. " does not match " .. (value or 'NIL'))
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end

function assertEmpty(table)
assertCount(0, table)
end

function assertCount(expected, table)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(#table == expected, string.format("failed assert that table has length %d", expected))
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end
function assertError(cb)
assertionStatistics["total"] = assertionStatistics["total"] + 1
assert(pcall(cb) == false, "Assert failed: Expected error")
assertionStatistics["passed"] = assertionStatistics["passed"] + 1
end

local Util = LibStub("EventSourcing/Util")
-- freeze time
local ts = Util.time()
Util.time = function() return ts end

function printResultsAndExit()
Util.DumpTable(assertionStatistics)
if (assertionStatistics['failed'] > 0) then
os.exit(1)
else
os.exit(0)
end
end

function beginTests()
print(string.format("Starting tests in file %s", arg[0]))
end
4 changes: 4 additions & 0 deletions tests/_wowstubs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@ strsplit = function(delimiter, str, pieces)
end
end
return unpack(t)
end

GetBuildInfo = function()
return "3.4.1", "45678", "Apr 01 2023", 30401
end
6 changes: 6 additions & 0 deletions tests/_wowstubs_wow10.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Placeholders for WoW functions
require "tests/_wowstubs"

GetBuildInfo = function()
return "10.0.5", "112233", "May 01 2023", 100005
end

0 comments on commit ca7f267

Please sign in to comment.