comparison 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
comparison
equal deleted inserted replaced
104:9aa2dcbbdc87 105:c6c748a5823b
13 local getn=getn 13 local getn=getn
14 setfenv(1,bsk) 14 setfenv(1,bsk)
15 15
16 adminList = {} 16 adminList = {}
17 17
18 local lastZoneTime = 0
19 local function ZoneChanged()
20 lastZoneTime = _G.time()
21 end
18 local function GuildRosterUpdate() 22 local function GuildRosterUpdate()
19 local guildInfoText = _G.GetGuildInfoText() 23 local guildInfoText = _G.GetGuildInfoText()
24 if lastZoneTime+5 > _G.time() then return end -- silly workaround - GGIT() returns "" when you zone in
20 local newAdminList = {} 25 local newAdminList = {}
21 for line in guildInfoText:gmatch("[^\r\n]+") do 26 for line in guildInfoText:gmatch("[^\r\n]+") do
22 local l,r = line:match("(.*):(.*)") -- could use wow strsplit had I known about it before writing this 27 local l,r = line:match("(.*):(.*)") -- could use wow strsplit had I known about it before writing this
23 l = string.trim(l or "") 28 l = string.trim(l or "")
24 r = string.trim(r or "") 29 r = string.trim(r or "")
65 end 70 end
66 71
67 function RemoteAdminUpdateReceived(sender,remoteAdminStatusTable) 72 function RemoteAdminUpdateReceived(sender,remoteAdminStatusTable)
68 if not admin then return end 73 if not admin then return end
69 74
70 local rs = remoteAdminStatusTable 75 local rs,base,changes = unpack(remoteAdminStatusTable)
71 local events = {} -- record all timestamps seen in this update
72 for i,_ in pairs(adminList) do -- update each admin's entry in your own DB 76 for i,_ in pairs(adminList) do -- update each admin's entry in your own DB
73 77
74 -- grab the db copy and the incoming copy for that admin 78 if i ~= me then
75 if not db.profile.adminStatus then db.profile.adminStatus = {} end 79 -- grab the db copy and the incoming copy for that admin
76 local dbs = db.profile.adminStatus[i] or {base=0, changes={}} 80 if not db.profile.adminStatus then db.profile.adminStatus = {} end
77 local ics = rs[i] or {base=0, changes={}} 81 local dbs = db.profile.adminStatus[i] or {base=0, changes={}}
78 82 local ics = rs[i] or {base=0, changes={}}
79 -- figure out which is better and keep that one 83
80 -- winning criteria: 84 -- figure out which is better and keep that one
81 -- * broadcast was actually from that person (ie best 85 -- winning criteria:
82 -- verification possible) 86 -- * broadcast was actually from that person (ie best
83 -- * newer base 87 -- verification possible)
84 -- * same base, more entries 88 -- * newer base
85 -- * todo: see if date last observed is a better option 89 -- * same base, more entries
86 90 -- * todo: see if date last observed is a better option
87 if i==sender then 91
88 db.profile.adminStatus[i] = ics 92 if i==sender then
89 elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then 93 db.profile.adminStatus[i] = ics
90 db.profile.adminStatus[i] = ics 94 elseif ics.base > dbs.base or (ics.base==dbs.base and getn(ics.changes) > getn(dbs.changes)) then
91 end 95 db.profile.adminStatus[i] = ics
92 end 96 end
93 97 end
94 local rss = rs[sender] 98 end
95 99
96 -- now figure out what I'm missing - and ask for it! 100 if changes and getn(changes)>0 then
97 101 IntegrateChangeDiff(base,changes)
98 -- construct a hash table of all entries that the sender has / should have 102 end
99 local entries = {} 103
100 for i,v in pairs(rs) do 104 -- trim if the replies said it's safe
101 if v.changes then 105
102 for j,k in pairs(v.changes) do 106 local trimPoint = db.profile.time
103 entries[k.time] = true 107 -- come up with a tentative starting point (max base)
104 end 108 for i,v in pairs(db.profile.adminStatus) do
105 end 109 if v.base > trimPoint then trimPoint = v.base end
106 end 110 end
107 -- now go back and scrub my own keys from that list 111
112 local pointer = {}
113 -- fast forward pointers *past* the trimPoint in each list
114 for p,l in pairs(db.profile.adminStatus) do
115 pointer[p] = 1
116 for i,v in ipairs(l.changes) do
117 if v <= trimPoint then
118 pointer[p] = i+1 -- "past" the trim point - might point to nil
119 else
120 break
121 end
122 end
123 end
124 print("pointers")
125 PrintTable(pointer)
126
108 for i,v in ipairs(db.profile.changes) do 127 for i,v in ipairs(db.profile.changes) do
109 entries[v.time] = nil 128 if v.time > trimPoint then -- advance to the trim point estimate before doing anything
110 end 129 -- into uncharted territory, let's see how far we can push it
111 -- what's left is what I need to ask for 130 local continue = true
112 local request = {} 131 for p,t in pairs(pointer) do
113 for i,v in pairs(entries) do 132 local dbpapct = db.profile.adminStatus[p].changes[t]
114 if v then table.insert(request,i) end 133 if dbpapct and dbpapct==v.time then
115 end 134 pointer[p] = pointer[p]+1
116 table.sort(request) 135 else
117 Comm:RequestSpecificChanges(request,sender) 136 continue=false
118 137 break
119 for 138 end
120 -- specifically leaving this broken. note to self. 139 trimPoint = v.time
121 -- this still isn't good enough. it doesn't communicate an admin's 140 end
122 -- present working state. like if they had put in new changes since 141 if not continue then break end
123 -- loading up. or learned of some changes to fill in an old gap 142 end
143 end
144 print("pointers")
145 PrintTable(pointer)
146 if trimPoint > db.profile.time then
147
148 -- protect trimming back to beginning of previous month so we're not
149 -- trimming like madmen
150 local ct = _G.date("*t",_G.time())
151 ct.month = ct.month-1
152 if ct.month < 1 then ct.month = 12 end
153 ct.day = 1
154 ct.hour = 1
155 ct.minute = 0
156 ct.sec = 0
157 local ts = _G.time(ct)
158 print("I think I can trim to",trimPoint,ts)
159 TrimLists(ts)
160 else
161 print("no bother trimming",trimPoint)
162 end
124 end 163 end
125 164
126 function InitializeAdmin() 165 function InitializeAdmin()
127 if not event then 166 if not event then
128 _G.error("BSK: Improper order of initialization") 167 _G.error("BSK: Improper order of initialization")
151 onloadAdminStatus = {} 190 onloadAdminStatus = {}
152 db.profile.adminStatus = nil 191 db.profile.adminStatus = nil
153 end 192 end
154 193
155 event:RegisterEvent("GUILD_ROSTER_UPDATE",GuildRosterUpdate) 194 event:RegisterEvent("GUILD_ROSTER_UPDATE",GuildRosterUpdate)
195 event:RegisterEvent("ZONE_CHANGED_NEW_AREA",ZoneChanged)
196 event:RegisterEvent("ZONE_CHANGED_INDOORS",ZoneChanged)
197 event:RegisterEvent("ZONE_CHANGED",ZoneChanged)
156 _G.GuildRoster() -- will eventually force the event to fire 198 _G.GuildRoster() -- will eventually force the event to fire
157 199
158 if me == "Breuemama" then -- debugging only 200 if me == "Breuemama" then -- debugging only
159 GuildRosterUpdate() 201 GuildRosterUpdate()
160 end 202 end