add gs
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"lint": {
|
||||
"ImplicitReturn": "fatal"
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local Cryo = require(CorePackages.Cryo)
|
||||
local ArgCheck = require(CorePackages.ArgCheck)
|
||||
local PromiseUtilities = require(CorePackages.AppTempCommon.LuaApp.PromiseUtilities)
|
||||
local FetchSubdividedThumbnails = require(script.Parent.FetchSubdividedThumbnails)
|
||||
|
||||
local PerformFetch = require(CorePackages.AppTempCommon.LuaApp.Thunks.Networking.Util.PerformFetch)
|
||||
|
||||
local ICON_PAGE_COUNT = 100
|
||||
local ICON_SIZE = "150x150"
|
||||
|
||||
local function convertToId(value)
|
||||
return tostring(value)
|
||||
end
|
||||
|
||||
local ApiFetchThumbnails = {}
|
||||
|
||||
local keyMapper = function (request)
|
||||
local targetId = request.targetId
|
||||
local size = request.iconSize and "."..request.iconSize or ""
|
||||
local requestName = request.requestName and "."..request.requestName or ""
|
||||
return "luaapp.thumbnails." .. convertToId(targetId)..size..requestName
|
||||
end
|
||||
|
||||
ApiFetchThumbnails.KeyMapper = keyMapper
|
||||
|
||||
local function subdivideIdsArray(requests, limit)
|
||||
local someTokens = {}
|
||||
for i = 1, #requests, limit do
|
||||
local subArray = Cryo.List.getRange(requests, i, i + limit - 1)
|
||||
table.insert(someTokens, subArray)
|
||||
end
|
||||
return someTokens
|
||||
end
|
||||
|
||||
function ApiFetchThumbnails.Fetch(networkImpl, targetIds, imageSize, requestName, fetchFunction, storeDispatch, store)
|
||||
local size = imageSize or ICON_SIZE
|
||||
ArgCheck.isType(targetIds, "table", "targetIds")
|
||||
ArgCheck.isType(requestName, "string", "requestName")
|
||||
ArgCheck.isNonNegativeNumber(#targetIds, "targetIds count")
|
||||
|
||||
local requests = {}
|
||||
local promises = {}
|
||||
-- Filter out the icons that are already in the store.
|
||||
for _, targetId in pairs(targetIds) do
|
||||
table.insert(requests, {
|
||||
targetId = targetId,
|
||||
iconSize = size,
|
||||
})
|
||||
end
|
||||
local subdividedRequestsArray = subdivideIdsArray(requests, ICON_PAGE_COUNT)
|
||||
for _, subdividedRequests in ipairs(subdividedRequestsArray) do
|
||||
table.insert(
|
||||
promises,
|
||||
store:dispatch(FetchSubdividedThumbnails.Fetch(
|
||||
networkImpl,
|
||||
subdividedRequests,
|
||||
keyMapper,
|
||||
requestName,
|
||||
fetchFunction,
|
||||
storeDispatch
|
||||
))
|
||||
)
|
||||
end
|
||||
|
||||
return PromiseUtilities.Batch(promises)
|
||||
end
|
||||
|
||||
function ApiFetchThumbnails.GetFetchingStatus(state, targetId, iconSize, requestName)
|
||||
return PerformFetch.GetStatus(state, keyMapper({targetId = targetId, requestName = requestName, iconSize = iconSize}))
|
||||
end
|
||||
|
||||
return ApiFetchThumbnails
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
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
|
||||
@@ -0,0 +1,10 @@
|
||||
-- Helper function to throttle based on player Id:
|
||||
return function(throttle, userId)
|
||||
assert(type(throttle) == "number")
|
||||
assert(type(userId) == "number")
|
||||
|
||||
-- Determine userRollout using last two digits of user ID:
|
||||
-- (+1 to change range from 0-99 to 1-100 as 0 is off, 100 is full on):
|
||||
local userRollout = (userId % 100) + 1
|
||||
return userRollout <= throttle
|
||||
end
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
return function()
|
||||
local ThrottleUserId = require(script.Parent.ThrottleUserId)
|
||||
|
||||
describe("ThrottleUserId", function()
|
||||
it("should always reject zero%", function()
|
||||
local gating = ThrottleUserId(0, 10000)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(0, 10001)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(0, 10025)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(0, 10075)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(0, 10099)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(0, 10100)
|
||||
expect(gating).to.equal(false)
|
||||
end)
|
||||
|
||||
it("should always accept 100%", function()
|
||||
local gating = ThrottleUserId(100, 10000)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(100, 10001)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(100, 10025)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(100, 10075)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(100, 10099)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(100, 10100)
|
||||
expect(gating).to.equal(true)
|
||||
end)
|
||||
|
||||
it("should reject IDs over throttle percent", function()
|
||||
local gating = ThrottleUserId(25, 10050)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(50, 10075)
|
||||
expect(gating).to.equal(false)
|
||||
|
||||
gating = ThrottleUserId(75, 10099)
|
||||
expect(gating).to.equal(false)
|
||||
end)
|
||||
|
||||
it("should accept IDs under throttle percent", function()
|
||||
local gating = ThrottleUserId(1, 10100)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(10, 10109)
|
||||
expect(gating).to.equal(true)
|
||||
|
||||
gating = ThrottleUserId(25, 10023)
|
||||
expect(gating).to.equal(true)
|
||||
end)
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user