184 lines
5.2 KiB
Lua
184 lines
5.2 KiB
Lua
--[[
|
|
Provides HTTP request methods for ScreenTime feature.
|
|
]]
|
|
|
|
local CorePackages = game:GetService("CorePackages")
|
|
local Url = require(CorePackages.AppTempCommon.LuaApp.Http.Url)
|
|
local UrlBuilder = require(CorePackages.Packages.UrlBuilder).UrlBuilder
|
|
local Logging = require(CorePackages.Logging)
|
|
local ArgCheck = require(CorePackages.ArgCheck)
|
|
|
|
local TEA_END_POINTS = {
|
|
GET_INSTRUCTIONS = "timed-entertainment-allowance/v1/instructions",
|
|
REPORT_EXECUTION = "timed-entertainment-allowance/v1/reportExecute",
|
|
}
|
|
|
|
local RESPONSE_FORMATS = {
|
|
GET_INSTRUCTIONS = {
|
|
errorCode = "number",
|
|
instructions = "table"
|
|
},
|
|
INSTRUCTION = {
|
|
type = "number",
|
|
instructionName = "string",
|
|
serialId = "string",
|
|
title = "string",
|
|
message = "string",
|
|
url = "string",
|
|
modalType = "number",
|
|
data = "string"
|
|
},
|
|
REPORT_EXECUTION = {
|
|
errorCode = "number",
|
|
},
|
|
}
|
|
|
|
local TAG = "HttpRequests"
|
|
|
|
local getInstructionsUrl = UrlBuilder.new({
|
|
base = Url.APIS_URL,
|
|
path = TEA_END_POINTS.GET_INSTRUCTIONS
|
|
})()
|
|
|
|
local reportExecutionUrl = UrlBuilder.new({
|
|
base = Url.APIS_URL,
|
|
path = TEA_END_POINTS.REPORT_EXECUTION
|
|
})()
|
|
|
|
--[[
|
|
A helper function to check object table have the required fields and fields'
|
|
type specified in format table.
|
|
It will throw exceptions, so must be encapsulated by pcall.
|
|
]]
|
|
local function checkFormat(format, object)
|
|
for key, typeString in pairs(format) do
|
|
assert(object[key] ~= nil, "Missing key")
|
|
assert(type(object[key]) == typeString, "Wrong type")
|
|
end
|
|
end
|
|
|
|
local HttpRequests = {
|
|
httpService = nil,
|
|
}
|
|
|
|
--[[
|
|
Create a new HttpRequests object.
|
|
|
|
@param httpService: Pass in HttpService from game:GetService("HttpService")
|
|
]]
|
|
function HttpRequests:new(httpService)
|
|
ArgCheck.isNotNil(httpService, "httpService")
|
|
local obj = {
|
|
httpService = httpService,
|
|
}
|
|
setmetatable(obj, self)
|
|
self.__index = self
|
|
return obj
|
|
end
|
|
|
|
--[[
|
|
Query TEA endpoint to get the instructions to execute.
|
|
|
|
@param callback: it should be non-nil with signature:
|
|
callback(success, unauthorized, instructions)
|
|
success (boolean): indicate whether the query is successful.
|
|
unauthorized (boolean): if success is false, indicate whether the
|
|
failure is due to authorization issue.
|
|
instructions (table): if success is true, this is the result
|
|
(associative array) of tables following
|
|
RESPONSE_FORMATS.INSTRUCTION format.
|
|
]]
|
|
function HttpRequests:getInstructions(callback)
|
|
ArgCheck.isNotNil(self.httpService, "httpService")
|
|
ArgCheck.isNotNil(callback, "callback")
|
|
local httpRequest = self.httpService:RequestInternal({
|
|
Url = getInstructionsUrl,
|
|
Method = "GET",
|
|
})
|
|
httpRequest:Start(function(reqSuccess, reqResponse)
|
|
local success
|
|
local err
|
|
local unauthorized = false
|
|
local instructions = {}
|
|
if not reqSuccess then
|
|
success = false
|
|
err = "Connection error"
|
|
elseif reqResponse.StatusCode == 401 then
|
|
success = false
|
|
unauthorized = true
|
|
err = "Unauthorized"
|
|
elseif reqResponse.StatusCode < 200 or reqResponse.StatusCode >= 400 then
|
|
success = false
|
|
err = "Status code: " .. reqResponse.StatusCode
|
|
else
|
|
-- reqSuccess == true and StatusCode >= 200 and StatusCode < 400
|
|
success, err = pcall(function()
|
|
local json = self.httpService:JSONDecode(reqResponse.Body)
|
|
checkFormat(RESPONSE_FORMATS.GET_INSTRUCTIONS, json)
|
|
assert(json.errorCode == 0, "Error code is not 0")
|
|
for i, instruction in ipairs(json.instructions) do
|
|
checkFormat(RESPONSE_FORMATS.INSTRUCTION, instruction)
|
|
end
|
|
instructions = json.instructions
|
|
end)
|
|
end
|
|
if not success then
|
|
Logging.warn(TAG .. " getInstructions failed: " .. getInstructionsUrl .. ", ".. err)
|
|
end
|
|
callback(success, unauthorized, instructions)
|
|
end)
|
|
end
|
|
|
|
--[[
|
|
Tell TEA endpoint that an instruction has been executed.
|
|
|
|
@param instructionName: from RESPONSE_FORMATS.INSTRUCTION
|
|
@param serialId: from RESPONSE_FORMATS.INSTRUCTION
|
|
@param callback: can be nil, signature: callback(success)
|
|
success (boolean): indicate whether the http request is successful.
|
|
]]
|
|
function HttpRequests:reportExecution(instructionName, serialId, callback)
|
|
ArgCheck.isNotNil(self.httpService, "httpService")
|
|
-- ISO 8601, Example: 2020-06-04T04:44:09Z
|
|
local formattedTime = os.date("%Y-%m-%dT%H:%M:%SZ")
|
|
local payload = self.httpService:JSONEncode({
|
|
instructionName = instructionName,
|
|
serialId = serialId,
|
|
execTime = formattedTime,
|
|
})
|
|
local httpRequest = self.httpService:RequestInternal({
|
|
Url = reportExecutionUrl,
|
|
Method = "POST",
|
|
Headers = {
|
|
["Content-Type"] = "application/json",
|
|
},
|
|
Body = payload,
|
|
})
|
|
httpRequest:Start(function(reqSuccess, reqResponse)
|
|
local success
|
|
local err
|
|
if not reqSuccess then
|
|
success = false
|
|
err = "Connection error"
|
|
elseif reqResponse.StatusCode < 200 and reqResponse.StatusCode >= 400 then
|
|
success = false
|
|
err = "Status code: " .. reqResponse.StatusCode
|
|
else
|
|
-- reqSuccess == true and StatusCode >= 200 and StatusCode < 400
|
|
success, err = pcall(function()
|
|
local json = self.httpService:JSONDecode(reqResponse.Body)
|
|
checkFormat(RESPONSE_FORMATS.REPORT_EXECUTION, json)
|
|
assert(json.errorCode == 0, "Error code is not 0")
|
|
end)
|
|
end
|
|
if not success then
|
|
Logging.warn(TAG .. " reportExecution failed: " .. reportExecutionUrl .. ", ".. err)
|
|
end
|
|
if callback ~= nil then
|
|
callback(success)
|
|
end
|
|
end)
|
|
end
|
|
|
|
return HttpRequests
|