annotate Comm.lua @ 94:2058d86778b4

Corrections on the receiver end of an incremental update.
author John@Yosemite-PC
date Sun, 22 Apr 2012 23:13:43 -0400
parents df94161e6d7c
children 082ff877c443
rev   line source
John@72 1 local bsk=bsk
John@72 2 local _G=_G
John@72 3 local table=table
John@72 4 local pairs=pairs
John@72 5 local setmetatable=setmetatable
John@72 6 local ipairs=ipairs
John@72 7 local unpack=unpack
John@72 8 local string=string
John@72 9 local sformat=string.format
John@72 10 local tostring=tostring
John@72 11 local type=type
John@72 12 local getn=getn
John@72 13
John@72 14 local commlib = LibStub("AceComm-3.0") or _G.error("Couldn't load up AceComm")
John@72 15 local s = LibStub("AceSerializer-3.0") or _G.error("Couldn't load up AceSerializer")
John@72 16
John@72 17 setfenv(1,bsk)
John@72 18
John@72 19 local function BuildPacket(handler,message)
John@72 20 local p = {handler,message}
John@72 21 local str = s:Serialize({handler,message})
John@72 22 print("sending",str)
John@72 23 return p,str
John@72 24 end
John@72 25
John@72 26 local function SendMessage(str)
John@72 27 --commlib:SendCommMessage("BSKADDON",str,"GUILD")
John@86 28 commlib:SendCommMessage("BSKADDON"..commversion,str,"RAID")
John@72 29 end
John@72 30
John@72 31 local function Send(handler,message)
John@72 32 local p,str = BuildPacket(handler,message)
John@72 33 SendMessage(str)
John@72 34 end
John@72 35
John@72 36 -- todo: ActivateList and AddReserve -> state
John@72 37 Comm =
John@72 38 {
John@72 39 ["SS"] = function(self,packet,sender,isloop)
John@72 40 print("isloop",isloop)
John@72 41 if not isloop then DispatchState(packet) end
John@72 42 end,
John@72 43 ["SendStateChange"] = function(self,...)
John@72 44 local p,str = BuildPacket("SS",{...})
John@72 45 DispatchState(p[2])
John@72 46 SendMessage(str)
John@72 47 end,
John@72 48 ["AR"] = function(self,packet,sender,isloop)
John@72 49 if isloop then return end
John@72 50 PersonList:AddReserve(packet)
John@72 51 changeListener:DataEvent()
John@72 52 end,
John@72 53 ["AddReserve"] = function(self,packet)
John@72 54 if changeListener then
John@72 55 changeListener:DataEvent(change)
John@72 56 end
John@72 57 Send("AR",packet)
John@72 58 end,
John@72 59 ["SendChange"] = function(self,change)
John@72 60 if changeListener then
John@72 61 changeListener:DataEvent(change)
John@72 62 end
John@72 63 Send("CC",change)
John@72 64 end,
John@72 65 ["CC"] = function(self,change,sender,isloop)
John@72 66 if isloop then return end
John@91 67 table.insert(db.profile.changes,change)
John@72 68 ProcessChange(change)
John@72 69 changeListener:DataEvent()
John@72 70 end,
John@72 71 ["Push"] = function(self)
John@91 72 Send("PU",{db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time})
John@72 73 end,
John@72 74 ["PU"] = function(self,packet,sender,isloop)
John@72 75 if isloop then return end
John@91 76 db.profile.lists,db.profile.persons,db.profile.changes,db.profile.time = unpack(packet)
John@72 77 CreateWorkingStateFromChanges(db.profile.changes)
John@72 78 if changeListener then
John@72 79 changeListener:DataEvent()
John@72 80 end
John@72 81 end,
John@91 82
John@91 83 ["TS"] = function(self,packet,sender,isloop)
John@91 84 if isloop then return end
John@91 85 if masterLooterIsMe and admin then
John@91 86 -- only non-admins will send this message, send them the present
John@91 87 -- working state
John@92 88
John@92 89 local t = packet
John@92 90 local remoteBase = table.remove(t,1)
John@92 91
John@92 92 -- if their base is older than ours, this is easy - send them our
John@92 93 -- base and all the changes
John@92 94 -- if their base is equal to ours, then diff their changes vs ours
John@92 95 -- and send them the remainder - it's ok if they have changes we
John@92 96 -- don't
John@92 97 -- if their base is newer, then we have a problem - it means another
John@92 98 -- admin rebased and we aren't aware of that. but the other admin
John@92 99 -- wouldn't have done that if they didn't believe all the admins
John@92 100 -- were synced up to the release point. So do we trust that and use
John@92 101 -- this as a rebase opportunity? print an error? just reply that we
John@92 102 -- don't have anything new to share with them? only send them
John@92 103 --
John@92 104
John@92 105 if remoteBase == db.profile.time then
John@92 106 local j = 1 -- index in foreign list
John@92 107 local n = getn(t)
John@92 108 local o = {}
John@92 109 for i,v in pairs(db.profile.changes) do -- for each timestamp in our list
John@92 110 if t and t[j] < v.time then
John@92 111 table.insert(o,v)
John@92 112 end
John@92 113 while j<n and t[j] <= v.time do j = j+1 end -- advance the foreign pointer past our current entry
John@92 114 end -- j>=n ? add because the remote hit end of road. lt? add because it's a missing stamp
John@92 115 print("Received request at timebase",remoteBase,"and returning:")
John@92 116 PrintTable(o)
John@93 117 if getn(o) > 0 then
John@93 118 Send("CU",o) -- todo: send privately to the requster
John@93 119 end
John@92 120 else
John@93 121 print("Received request at differing timebase",remoteBase,db.profile.time," ... pushing")
John@93 122 self:Push() -- todo: send privately to requester
John@92 123 end
John@91 124 end
John@91 125 end,
John@91 126
John@91 127 ["CU"] = function(self,packet,sender,isloop) -- blindly trust an admin loot master
John@91 128 if isloop then return end
John@93 129
John@93 130 local c = packet
John@93 131 local old = db.profile.changes
John@93 132
John@93 133 local new = {}
John@93 134
John@93 135 local op = 1
John@93 136 local cp = 1
John@93 137
John@93 138 local no = getn(old)
John@93 139 local nc = getn(c)
John@93 140
John@93 141 if no == 0 then
John@93 142 db.profile.changes = c
John@93 143 else
John@94 144 while op <= no or cp <= nc do -- lists are pre-sorted. insertion merge them
John@94 145 if cp > nc then -- inelegant
John@94 146 table.insert(new,old[op])
John@94 147 op = op + 1
John@94 148 elseif op > no then
John@94 149 table.insert(new,c[cp])
John@94 150 cp = cp + 1
John@94 151 elseif c[cp].time < old[op].time then
John@94 152 table.insert(new,c[cp])
John@94 153 cp = cp + 1
John@94 154 elseif c[cp].time > old[op].time then
John@94 155 table.insert(new,old[op])
John@94 156 op = op + 1
John@94 157 else
John@93 158 error("Bad update received from ",sender)
John@93 159 end
John@93 160 end
John@94 161 print("Updating changes - ",getn(new), "entries")
John@93 162 db.profile.changes = new
John@93 163 end
John@93 164
John@91 165 CreateWorkingStateFromChanges(db.profile.changes)
John@91 166 if changeListener then
John@91 167 changeListener:DataEvent()
John@91 168 end
John@91 169 end,
John@91 170
John@91 171 ["RequestCatchup"] = function(self)
John@91 172 if not admin then
John@92 173 --local string = _g.tostring(timestamp)
John@92 174 --for i,v in pairs(db.profile.changes) do -- append all change timestamps
John@92 175 -- string = string .. "|" .. _g.tostring(v.time)
John@92 176 --end
John@92 177 local t = {db.profile.time}
John@92 178 for i,v in pairs(db.profile.changes) do -- append all change timestamps
John@92 179 table.insert(t,v.time)
John@92 180 end
John@92 181 Send("TS", t) -- todo: send privately to loot master
John@91 182 else
John@91 183 -- todo: admins talking to one another
John@91 184 end
John@91 185
John@91 186 end,
John@72 187 }
John@72 188
John@72 189 local function OnCommReceived(prefix, message, distribution, sender)
John@72 190 print("Received on", distribution)
John@72 191 local success,packet = s:Deserialize(message)
John@72 192 local isloop = _G.UnitName("player") == sender
John@72 193
John@72 194 print("received",message)
John@72 195
John@72 196 Comm[packet[1]](Comm,packet[2],sender,isloop)
John@72 197 end
John@72 198
John@86 199 alertlist = {}
John@86 200 local function OnOlderCommReceived(prefix, message, distribution, sender)
John@86 201 if not alertlist[sender] then
John@86 202 printf("Received communication from %s, who is using an older version of the addon; ignoring",sender)
John@86 203 alertlist[sender]=true
John@86 204 end
John@86 205 end
John@86 206
John@86 207 local function OnNewerCommReceived(prefix, message, distribution, sender)
John@86 208 if not alertlist[sender] then
John@86 209 printf("Received communication from %s, who is using a newer version of the addon; ignoring",sender)
John@86 210 alertlist[sender]=true
John@86 211 end
John@86 212 end
John@86 213
John@72 214 function InitializeComm()
John@86 215 for i = 0,commversion-1 do
John@86 216 commlib:RegisterComm("BSKADDON"..i,OnOlderCommReceived)
John@86 217 end
John@86 218 commlib:RegisterComm("BSKADDON"..commversion,OnCommReceived)
John@86 219 for i = commversion+1,commversion+5 do -- some sensible number
John@86 220 commlib:RegisterComm("BSKADDON"..i,OnNewerCommReceived)
John@86 221 end
John@72 222 end
John@72 223
John@72 224 function DeinitializeComm()
John@72 225
John@72 226 end