337 lines
10 KiB
Ucode
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);
|
||
|
}
|