annotate Admin.lua @ 105:c6c748a5823b tip

Collaborative list trimming 80% functional Updates for the zone-in problem
author John@Yosemite-PC
date Sun, 06 May 2012 08:33:34 -0400
parents d3ea0ab1428d
children
rev   line source
John@98 1 local bsk=bsk
John@98 2 local _G=_G
John@98 3 local table=table
John@98 4 local pairs=pairs
John@98 5 local setmetatable=setmetatable
John@98 6 local ipairs=ipairs
John@98 7 local string=string
John@98 8 local sformat=string.format
John@98 9 local strsplit=strsplit
John@98 10 local tostring=tostring
John@98 11 local type=type
John@98 12 local unpack=unpack
John@98 13 local getn=getn
John@98 14 setfenv(1,bsk)
John@98 15
John@98 16 adminList = {}
John@98 17
John@105 18 local lastZoneTime = 0
John@105 19 local function ZoneChanged()
John@105 20 lastZoneTime = _G.time()
John@105 21 end
John@98 22 local function GuildRosterUpdate()
John@98 23 local guildInfoText = _G.GetGuildInfoText()
John@105 24 if lastZoneTime+5 > _G.time() then return end -- silly workaround - GGIT() returns "" when you zone in
John@98 25 local newAdminList = {}
John@98 26 for line in guildInfoText:gmatch("[^\r\n]+") do
John@98 27 local l,r = line:match("(.*):(.*)") -- could use wow strsplit had I known about it before writing this
John@98 28 l = string.trim(l or "")
John@98 29 r = string.trim(r or "")
John@99 30 if l == "BSKADMIN" then -- found a juicy line. may contain multiple, comma or space delimited
John@98 31 local admins = {strsplit(", ",r)}
John@98 32 for _,a in pairs(admins) do
John@98 33 a = string.trim(a or "")
John@98 34 if a ~= "" then
John@98 35 newAdminList[a] = true
John@98 36 end
John@98 37 end
John@98 38 end
John@98 39 end
John@98 40
John@103 41 if me == "Breuemama" then -- todo: strictly debugging ...
John@103 42 newAdminList[me] = true
John@103 43 newAdminList["Breue"] = true
John@103 44 end
John@103 45
John@98 46 if _G.next(adminList) ~= nil then -- had old admins. don't want to spam on initial load
John@98 47 -- diff new vs old
John@98 48 for a in pairs(adminList) do
John@98 49 if not newAdminList[a] then
John@98 50 print("Admin removed:", a)
John@98 51 end
John@98 52 end
John@98 53 for a in pairs(newAdminList) do
John@98 54 if not adminList[a] then
John@98 55 print("Admin added:",a)
John@98 56 end
John@98 57 end
John@98 58 end
John@98 59 adminList = newAdminList
John@99 60
John@103 61 if adminList[me] then -- I'm an admin!
John@99 62 admin = true
John@99 63 bsk.db.profile.admin = true
John@99 64 RegisterAdminChannels()
John@99 65 else
John@99 66 admin = false
John@99 67 bsk.db.profile.admin = false
John@99 68 UnregisterAdminChannels()
John@99 69 end
John@99 70 end
John@99 71
John@99 72 function RemoteAdminUpdateReceived(sender,remoteAdminStatusTable)
John@99 73 if not admin then return end
John@99 74
John@105 75 local rs,base,changes = unpack(remoteAdminStatusTable)
John@99 76 for i,_ in pairs(adminList) do -- update each admin's entry in your own DB
John@99 77
John@105 78 if i ~= me then
John@105 79 -- grab the db copy and the incoming copy for that admin
John@105 80 if not db.profile.adminStatus then db.profile.adminStatus = {} end
John@105 81 local dbs = db.profile.adminStatus[i] or {base=0, changes={}}
John@105 82 local ics = rs[i] or {base=0, changes={}}
John@99 83
John@105 84 -- figure out which is better and keep that one
John@105 85 -- winning criteria:
John@105 86 -- * broadcast was actually from that person (ie best
John@105 87 -- verification possible)
John@105 88 -- * newer base
John@105 89 -- * same base, more entries
John@105 90 -- * todo: see if date last observed is a better option
John@99 91
John@105 92 if i==sender then
John@105 93 db.profile.adminStatus[i] = ics
John@105 94 elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then
John@105 95 db.profile.adminStatus[i] = ics
John@105 96 end
John@99 97 end
John@99 98 end
John@103 99
John@105 100 if changes and getn(changes)>0 then
John@105 101 IntegrateChangeDiff(base,changes)
John@105 102 end
John@103 103
John@105 104 -- trim if the replies said it's safe
John@103 105
John@105 106 local trimPoint = db.profile.time
John@105 107 -- come up with a tentative starting point (max base)
John@105 108 for i,v in pairs(db.profile.adminStatus) do
John@105 109 if v.base > trimPoint then trimPoint = v.base end
John@105 110 end
John@105 111
John@105 112 local pointer = {}
John@105 113 -- fast forward pointers *past* the trimPoint in each list
John@105 114 for p,l in pairs(db.profile.adminStatus) do
John@105 115 pointer[p] = 1
John@105 116 for i,v in ipairs(l.changes) do
John@105 117 if v <= trimPoint then
John@105 118 pointer[p] = i+1 -- "past" the trim point - might point to nil
John@105 119 else
John@105 120 break
John@103 121 end
John@103 122 end
John@103 123 end
John@105 124 print("pointers")
John@105 125 PrintTable(pointer)
John@105 126
John@103 127 for i,v in ipairs(db.profile.changes) do
John@105 128 if v.time > trimPoint then -- advance to the trim point estimate before doing anything
John@105 129 -- into uncharted territory, let's see how far we can push it
John@105 130 local continue = true
John@105 131 for p,t in pairs(pointer) do
John@105 132 local dbpapct = db.profile.adminStatus[p].changes[t]
John@105 133 if dbpapct and dbpapct==v.time then
John@105 134 pointer[p] = pointer[p]+1
John@105 135 else
John@105 136 continue=false
John@105 137 break
John@105 138 end
John@105 139 trimPoint = v.time
John@105 140 end
John@105 141 if not continue then break end
John@105 142 end
John@103 143 end
John@105 144 print("pointers")
John@105 145 PrintTable(pointer)
John@105 146 if trimPoint > db.profile.time then
John@105 147
John@105 148 -- protect trimming back to beginning of previous month so we're not
John@105 149 -- trimming like madmen
John@105 150 local ct = _G.date("*t",_G.time())
John@105 151 ct.month = ct.month-1
John@105 152 if ct.month < 1 then ct.month = 12 end
John@105 153 ct.day = 1
John@105 154 ct.hour = 1
John@105 155 ct.minute = 0
John@105 156 ct.sec = 0
John@105 157 local ts = _G.time(ct)
John@105 158 print("I think I can trim to",trimPoint,ts)
John@105 159 TrimLists(ts)
John@105 160 else
John@105 161 print("no bother trimming",trimPoint)
John@103 162 end
John@98 163 end
John@98 164
John@98 165 function InitializeAdmin()
John@98 166 if not event then
John@98 167 _G.error("BSK: Improper order of initialization")
John@98 168 end
John@103 169 me = _G.UnitName("player")
John@99 170
John@99 171 if admin then -- if at last login I was an admin ...
John@99 172
John@99 173 -- note that we're not transmitting anything here. we'll do that once we
John@99 174 -- know for certain we're an admin
John@99 175
John@99 176 -- cache the onload status in case it changes in memory later
John@99 177 onloadAdminStatus = {}
John@99 178 tcopy(onloadAdminStatus,db.profile.adminStatus)
John@99 179
John@99 180 -- update our own entry - safe because comms shouldn't have happened yet
John@99 181 if not onloadAdminStatus then onloadAdminStatus = {} end
John@99 182 if not onloadAdminStatus[me] then onloadAdminStatus[me] = {} end
John@99 183 onloadAdminStatus[me].base = db.profile.time or 0
John@99 184 onloadAdminStatus[me].changes= {}
John@99 185 for _,v in ipairs(db.profile.changes) do
John@99 186 table.insert(onloadAdminStatus[me].changes,v.time) -- only timestamps
John@99 187 end
John@99 188
John@99 189 else -- otherwise store a blank slate
John@99 190 onloadAdminStatus = {}
John@99 191 db.profile.adminStatus = nil
John@99 192 end
John@99 193
John@98 194 event:RegisterEvent("GUILD_ROSTER_UPDATE",GuildRosterUpdate)
John@105 195 event:RegisterEvent("ZONE_CHANGED_NEW_AREA",ZoneChanged)
John@105 196 event:RegisterEvent("ZONE_CHANGED_INDOORS",ZoneChanged)
John@105 197 event:RegisterEvent("ZONE_CHANGED",ZoneChanged)
John@98 198 _G.GuildRoster() -- will eventually force the event to fire
John@103 199
John@103 200 if me == "Breuemama" then -- debugging only
John@103 201 GuildRosterUpdate()
John@103 202 end
John@98 203 end
John@98 204
John@98 205