1
0
KF2-Dev-Scripts/IpDrv/Classes/OnlineTitleFileDownloadWeb.uc
2020-12-13 18:01:13 +03:00

337 lines
10 KiB
Ucode

/**
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
/**
* Title file downloading implementation via web service request
*/
class OnlineTitleFileDownloadWeb extends OnlineTitleFileDownloadBase
native;
`include(Engine\Classes\HttpStatusCodes.uci);
/** The list of title files that have been read or are being read */
var private array<TitleFileWeb> TitleFiles;
/**
* Uncompress the title file
*
* @param FileCompressionType enum that that informs how to uncompress the file
* @param CompressedFileContents Source data to uncompress
* @param UncompressedFileContents the out buffer to copy the data into
*/
native function bool UncompressTitleFileContents(EMcpFileCompressionType FileCompressionType, const out array<byte> CompressedFileContents, out array<byte> UncompressedFileContents);
/**
* Starts an asynchronous read of the specified file from the network platform's
* title specific file store
*
* @param FileToRead the name of the file to read
*
* @return true if the calls starts successfully, false otherwise
*/
function bool ReadTitleFile(string FileToRead, optional EOnlineFileType FileType = OFT_Binary)
{
local int FileIndex,Idx;
local string URL;
// check for a prior request
FileIndex = INDEX_NONE;
for (Idx=0; Idx < TitleFiles.Length; Idx++)
{
// case sensitive
if (InStr(TitleFiles[Idx].Filename,FileToRead,true,false) != INDEX_NONE)
{
FileIndex = Idx;
break;
}
}
// add new entry for this file request if not found
if (FileIndex == INDEX_NONE)
{
FileIndex = TitleFiles.Length;
TitleFiles.Length = TitleFiles.Length + 1;
TitleFiles[FileIndex].Filename = FileToRead;
TitleFiles[FileIndex].AsyncState = OERS_NotStarted;
}
// file has been downloaded before successfully so already done
if (TitleFiles[FileIndex].AsyncState == OERS_Done)
{
TriggerDelegates(true,FileToRead);
}
// file has been downloaded before but failed
else if (TitleFiles[FileIndex].AsyncState == OERS_Failed)
{
TriggerDelegates(false,FileToRead);
return false;
}
// download needs to start if not already in progress
else if (TitleFiles[FileIndex].AsyncState != OERS_InProgress)
{
// mark the file entry as pending download
TitleFiles[FileIndex].AsyncState = OERS_InProgress;
// tack on the filename to the base/overridden URL
URL = GetUrlForFile(FileToRead) $ FileToRead;
`Log(`location @ "starting read for title file"
@"url="$URL);
// send off web request and register for delegate for its completion
TitleFiles[FileIndex].HTTPRequest = class'HttpFactory'.static.CreateRequest();
if (TitleFiles[FileIndex].HTTPRequest != None)
{
TitleFiles[FileIndex].HTTPRequest.OnProcessRequestComplete = OnFileDownloadComplete;
TitleFiles[FileIndex].HTTPRequest.SetVerb("GET");
TitleFiles[FileIndex].HTTPRequest.SetURL(URL);
TitleFiles[FileIndex].HTTPRequest.ProcessRequest();
}
}
return true;
}
/**
* Delegate called on each completed web request
*
* @param OriginalRequest - The original request object that spawned the response
* @param HttpResponse - The response object. Could be None if the request failed spectacularly. If the request failed to receive a complete
* response for some reason, this could contain a valid Response object with as much info as could be retrieved.
* Always use the bDidSucceed parameter to determine if the entire response was received successfully.
* @param bSucceeded - whether the response succeeded. If it did not, you should not trust the payload or headers.
* Basically indicates a net failure occurred while receiving the response.
*/
private function OnFileDownloadComplete(HttpRequestInterface Request, HttpResponseInterface Response, bool bDidSucceed)
{
local bool bSuccess;
local int FileIndex,Idx;
local string Filename;
local array<byte> BinaryData;
local string FileCompressionTypeString;
if (bDidSucceed)
{
FileIndex = INDEX_NONE;
// find file entry for this request based on what was passed on the URL
for (Idx=0; Idx < TitleFiles.Length; Idx++)
{
if (TitleFiles[Idx].HTTPRequest == Request)
{
FileIndex = Idx;
break;
}
}
`Log(`location @ ""
@"FileIndex="$FileIndex
@"OriginalURL="$Request.GetURL()
@"ResponseCode="$Response.GetResponseCode()
@"ContentLength="$Response.GetContentLength());
if (FileIndex != INDEX_NONE)
{
Filename = TitleFiles[FileIndex].Filename;
// remove ref to request since it is now complete
TitleFiles[FileIndex].HTTPRequest = None;
TitleFiles[FileIndex].AsyncState = OERS_Failed;
// only successful response code as we're not handling any redirects
if (Response.GetResponseCode() == `HTTP_STATUS_OK)
{
bSuccess = true;
// copy the payload data from the web request
Response.GetContent(BinaryData);
TitleFiles[FileIndex].Data = BinaryData;
// Get the Compression Type from the Response Header
FileCompressionTypeString = Response.GetHeader("Mcp-Content-Encoding");
// Convert CompressionTypeString stored in the datastore to the enum used on the client
switch(FileCompressionTypeString)
{
case "MFCT_ZLIB":
TitleFiles[FileIndex].FileCompressionType = MFCT_ZLIB;
break;
default:
TitleFiles[FileIndex].FileCompressionType = MFCT_NONE;
}
// mark as successfully done
TitleFiles[FileIndex].AsyncState = OERS_Done;
}
else
{
// clear failed data
TitleFiles[FileIndex].AsyncState = OERS_Failed;
TitleFiles[FileIndex].Data.Length = 0;
}
}
else
{
`Log(`location @ "No entry found for"
@"FileIndex="$FileIndex);
}
}
else
{
`Log(`location @ "web request for file download failed");
}
// web request is complete and delegate is triggered for success/failure
TriggerDelegates(bSuccess,Filename);
}
/**
* Runs the delegates registered on this interface for each file download request
*
* @param bSuccess true if the request was successful
* @param FileRead name of the file that was read
*/
private native function TriggerDelegates(bool bSuccess,string FileRead);
/**
* Copies the file data into the specified buffer for the specified file
*
* @param FileName the name of the file to read
* @param FileContents the out buffer to copy the data into
*
* @return true if the data was copied, false otherwise
*/
native function bool GetTitleFileContents(string FileName,out array<byte> FileContents);
/**
* Determines the async state of the tile file read operation
*
* @param FileName the name of the file to check on
*
* @return the async state of the file read
*/
function EOnlineEnumerationReadState GetTitleFileState(string FileName)
{
local int FileIndex;
FileIndex = TitleFiles.Find('FileName',FileName);
if (FileIndex != INDEX_NONE)
{
return TitleFiles[FileIndex].AsyncState;
}
return OERS_Failed;
}
/**
* Empties the set of downloaded files if possible (no async tasks outstanding)
*
* @return true if they could be deleted, false if they could not
*/
native function bool ClearDownloadedFiles();
/**
* Empties the cached data for this file if it is not being downloaded currently
*
* @param FileName the name of the file to remove from the cache
*
* @return true if it could be deleted, false if it could not
*/
native function bool ClearDownloadedFile(string FileName);
/**
* Async call to request a list of files (returned as string) from EMS
*/
function bool RequestTitleFileList()
{
local HttpRequestInterface HTTPRequest;
local string URL;
HTTPRequest = class'HttpFactory'.static.CreateRequest();
if (HTTPRequest != None)
{
URL = GetBaseURL() $ RequestFileListURL $ GetAppAccessURL();
HTTPRequest.OnProcessRequestComplete = OnFileListReceived;
HTTPRequest.SetVerb("GET");
HTTPRequest.SetURL(URL);
HTTPRequest.ProcessRequest();
}
else
{
`log(`location@"HTTPRequest object missing");
}
return true;
}
/**
* Delegate for when the EMS file list is received
*
* @param OriginalRequest - The original request object that spawned the response
* @param HttpResponse - The response object. Could be None if the request failed spectacularly. If the request failed to receive a complete
* response for some reason, this could contain a valid Response object with as much info as could be retrieved.
* Always use the bDidSucceed parameter to determine if the entire response was received successfully.
* @param bSucceeded - whether the response succeeded. If it did not, you should not trust the payload or headers.
* Basically indicates a net failure occurred while receiving the response.
*/
function OnFileListReceived(HttpRequestInterface Request, HttpResponseInterface Response, bool bDidSucceed)
{
local int Index;
local delegate<OnRequestTitleFileListComplete> RequestTitleFileListDelegate;
local array<string> ResponseStr;
local bool bSuccess;
ResponseStr.length = 0;
if (bDidSucceed)
{
if (Response != None &&
Response.GetResponseCode() == `HTTP_STATUS_OK)
{
ResponseStr.AddItem(Response.GetContentAsString());
bSuccess = true;
}
else
{
`log(`location@"Download of file list failed. Bad response."
@"ResponseCode="$Response.GetResponseCode()
@"URL="$Request.GetURL());
}
}
else
{
`log(`location@"Download of file list failed.");
}
// Call the completion delegate for receiving the file list
for (Index=0; Index < RequestTitleFileListCompleteDelegates.Length; Index++)
{
RequestTitleFileListDelegate = RequestTitleFileListCompleteDelegates[Index];
if (RequestTitleFileListDelegate != None)
{
RequestTitleFileListDelegate(bSuccess,ResponseStr);
}
}
}
/**
* Build the clashmob specific Url for downloading a given file
*
* @param FileName the file to search the table for
*
* @param the URL to use to request the file or BaseURL if no special mapping is present
*/
function string GetUrlForFile(string FileName)
{
local string Url;
Url = GetBaseURL() $ RequestFileURL $ GetAppAccessURL() $
"&dlName=";
return Url;
}
cpptext
{
/**
* Ticks any outstanding async tasks that need processing
*
* @param DeltaTime the amount of time that has passed since the last tick
*/
virtual void Tick(FLOAT DeltaTime);
/**
* Searches the list of files for the one that matches the filename
*
* @param FileName the file to search for
*
* @return the file details
*/
FTitleFileWeb* GetTitleFile(const FString& FileName);
}