local CorePackages = game:GetService("CorePackages") local LuaApp = CorePackages.AppTempCommon.LuaApp local ArgCheck = require(CorePackages.ArgCheck) local Thumbnail = require(LuaApp.Models.Thumbnail) local PerformFetch = require(LuaApp.Thunks.Networking.Util.PerformFetch) local Promise = require(LuaApp.Promise) local Result = require(LuaApp.Result) local TableUtilities = require(LuaApp.TableUtilities) local RETRY_MAX_COUNT = math.max(0, settings():GetFVariable("LuaAppNonFinalThumbnailMaxRetries")) local RETRY_TIME_MULTIPLIER = math.max(0, settings():GetFVariable("LuaAppThumbnailsApiRetryTimeMultiplier")) -- seconds local FetchSubdividedThumbnails = {} function FetchSubdividedThumbnails._fetchIcons(store, networkImpl, targetIds, iconSize, keyMapper, requestName, fetchFunction, storeDispatch) local function keyMapperForCurrentRequestNameAndSize(targetId) return keyMapper({ targetId = targetId, requestName = requestName, iconSize = iconSize }) end local function getTableOfFailedResults(failedTargetIds) local results = {} for _, targetId in pairs(failedTargetIds) do local key = keyMapperForCurrentRequestNameAndSize(targetId) results[key] = Result.new(false, { targetId = targetId, }) end return results end return fetchFunction(networkImpl, targetIds, iconSize):andThen( function(result) local results = getTableOfFailedResults(targetIds) local validIcons = {} local data = result and result.responseBody and result.responseBody.data if typeof(data) == "table" then for _, iconInfo in pairs(data) do if Thumbnail.isCompleteThumbnailData(iconInfo) then local targetId = tostring(iconInfo.targetId) local success = false if Thumbnail.checkStateIsFinal(iconInfo.state) then validIcons[targetId] = Thumbnail.fromThumbnailData(iconInfo, iconSize) success = true end results[keyMapperForCurrentRequestNameAndSize(targetId)] = Result.new(success, iconInfo) end end end store:dispatch(storeDispatch(validIcons)) return Promise.resolve(results) end, function(err) local results = getTableOfFailedResults(targetIds) return Promise.resolve(results) end ) end function FetchSubdividedThumbnails._fetch(store, networkImpl, targetIds, size, keyMapper, requestName, fetchFunction, storeDispatch) return FetchSubdividedThumbnails._fetchIcons(store, networkImpl, targetIds, size, keyMapper, requestName, fetchFunction, storeDispatch) :andThen(function(results) local completedIcons = {} local iconResults = results if _G.__TESTEZ_RUNNING_TEST__ then RETRY_MAX_COUNT = 1 RETRY_TIME_MULTIPLIER = 0.001 end local function retry(retryCount) local remainingUnfinalizedIcons = {} for k, result in pairs(iconResults) do local isSuccessful, iconInfo = result:unwrap() -- Retry icon request for targetId that failed. if isSuccessful and Thumbnail.checkStateIsFinal(iconInfo.state) then completedIcons[k] = result else table.insert(remainingUnfinalizedIcons, iconInfo) end end if TableUtilities.FieldCount(remainingUnfinalizedIcons) == 0 then --All requests are successful return Promise.resolve(completedIcons) end local delayPromise = Promise.new(function(resolve, reject) coroutine.wrap(function() wait(RETRY_TIME_MULTIPLIER * math.pow(2, retryCount - 1)) resolve() end)() end) return delayPromise:andThen(function() return FetchSubdividedThumbnails._fetchIcons(store, networkImpl, targetIds, size, keyMapper, requestName, fetchFunction, storeDispatch) end):andThen(function(newResults) iconResults = newResults if retryCount > 1 then return retry(retryCount - 1) else return Promise.resolve(completedIcons) end end) end return retry(RETRY_MAX_COUNT) end) end function FetchSubdividedThumbnails.Fetch(networkImpl, requests, keyMapper, requestName, fetchFunction, storeDispatch) ArgCheck.isType(requests, "table", "requests") ArgCheck.isType(requestName, "string", "requestName") ArgCheck.isNonNegativeNumber(#requests, "requests count") FetchSubdividedThumbnails.KeyMapper = keyMapper return PerformFetch.Batch(requests, keyMapper, function(store, filteredrequests) local targetIdsNeeded = {} local size -- Filter out the icons that are already in the store. for _, request in ipairs(filteredrequests) do local targetId = request.targetId size = request.iconSize table.insert(targetIdsNeeded, targetId) end return FetchSubdividedThumbnails._fetch(store, networkImpl, targetIdsNeeded, size, keyMapper, requestName, fetchFunction, storeDispatch) end) end return FetchSubdividedThumbnails