diff --git a/Core/Util.lua b/Core/Util.lua index deff8e9..4c07f19 100644 --- a/Core/Util.lua +++ b/Core/Util.lua @@ -200,10 +200,95 @@ function Util.GetItem(idOrLink) } end -local pendingItems = {} +local pendingItems = {} -- itemID -> Liste der wartenden Callbacks +local itemQueue = {} -- noch nicht gesendete Anfragen (Reihenfolge) +local itemQueueHead = 1 +local itemSent = {} -- itemID -> true, wenn gesendet und noch offen +local itemOut = 0 -- Zahl offener, gesendeter Anfragen +local itemFailed = {} -- itemID -> true, Zeitueberschreitung (wird am Ende nochmal versucht) +local itemFailedList = {} +local itemRetried = {} +local ITEM_TIMEOUT = 5 -- Sekunden ohne Antwort = nicht ladbar +local ITEM_MAX_OUT = 50 -- so viele Anfragen gleichzeitig offen +Util.ITEM_TIMEOUT = ITEM_TIMEOUT + +local PumpItems + +local function ItemFinish(itemID, info) + local list = pendingItems[itemID] + if itemSent[itemID] then + itemSent[itemID] = nil + itemOut = math.max(0, itemOut - 1) + end + pendingItems[itemID] = nil + if list then + for _, callback in ipairs(list) do + FW.SafeCall(callback, info) + end + end +end + +-- Zweiter Versuch fuer alles, was keine Antwort bekam: erst wenn die Warteschlange leer ist. +local function RetryFailed() + if itemQueueHead <= #itemQueue or itemOut > 0 then + return + end + local todo = {} + for _, id in ipairs(itemFailedList) do + if itemFailed[id] and not itemRetried[id] then + itemRetried[id] = true + todo[#todo + 1] = id + end + end + itemFailedList = {} + for _, id in ipairs(todo) do + itemFailed[id] = nil + Util.RequestItem(id, function(info) + if info and FW.Fire then FW:Fire("CODEX_ITEMS_LOADED") end + end) + end +end + +function PumpItems() + while itemOut < ITEM_MAX_OUT and itemQueueHead <= #itemQueue do + local id = itemQueue[itemQueueHead] + itemQueueHead = itemQueueHead + 1 + if pendingItems[id] and not itemSent[id] then + if Util.GetItem(id) then + ItemFinish(id, Util.GetItem(id)) + else + itemSent[id] = true + itemOut = itemOut + 1 + if C_Item and C_Item.RequestLoadItemDataByID then + C_Item.RequestLoadItemDataByID(id) + end + if C_Timer and C_Timer.After then + C_Timer.After(ITEM_TIMEOUT, function() + if itemSent[id] then + if not itemFailed[id] then + itemFailed[id] = true + itemFailedList[#itemFailedList + 1] = id + end + ItemFinish(id, nil) + PumpItems() + end + end) + end + end + end + end + if itemQueueHead > #itemQueue then + itemQueue = {} + itemQueueHead = 1 + if itemOut == 0 and #itemFailedList > 0 and C_Timer and C_Timer.After then + C_Timer.After(1, RetryFailed) + end + end +end -- Ruft callback(info) auf, sobald die Item-Daten da sind (sofort, falls schon im Cache). --- info ist nil, wenn das Item nicht geladen werden konnte. +-- info ist nil, wenn das Item nicht geladen werden konnte (nach ITEM_TIMEOUT Sekunden ohne Antwort). +-- Anfragen laufen gestaffelt: schnelle Antworten zuerst, Ausfaelle werden zum Schluss einmal wiederholt. function Util.RequestItem(itemID, callback) local info = Util.GetItem(itemID) if info then @@ -214,23 +299,19 @@ function Util.RequestItem(itemID, callback) if not list then list = {} pendingItems[itemID] = list + itemQueue[#itemQueue + 1] = itemID end list[#list + 1] = callback - if C_Item and C_Item.RequestLoadItemDataByID then - C_Item.RequestLoadItemDataByID(itemID) - end + PumpItems() end FW:RegisterEvent("GET_ITEM_INFO_RECEIVED", function(itemID, success) - local list = pendingItems[itemID] - if not list then + if not pendingItems[itemID] then return end - pendingItems[itemID] = nil - local info = success and Util.GetItem(itemID) or nil - for _, callback in ipairs(list) do - FW.SafeCall(callback, info) - end + itemFailed[itemID] = nil + ItemFinish(itemID, success and Util.GetItem(itemID) or nil) + PumpItems() end) ------------------------------------------------------------------------ diff --git a/Freewood-OctoWoW-Core.toc b/Freewood-OctoWoW-Core.toc index 40ae21e..e74874c 100644 --- a/Freewood-OctoWoW-Core.toc +++ b/Freewood-OctoWoW-Core.toc @@ -3,7 +3,7 @@ ## Notes: Base addon of the Freewood family: data storage, UI kit, export/import and the main window. ## Notes-deDE: Basis-Addon der Freewood-Familie: Datenspeicher, UI-Bausteine, Export/Import und Hauptfenster. ## Author: Lacustat -## Version: 0.1.144 +## Version: 0.1.145 ## SavedVariables: FreewoodDB ## SavedVariablesPerCharacter: FreewoodCharDB