mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
If depot vector is empty, the SDK launcher will download all files in depot json, but still use the depot vector as the count for how many packages instead of the depot json array.
804 lines
21 KiB
C++
804 lines
21 KiB
C++
#include "sdklauncher_utils.h"
|
|
#include "windows/window.h"
|
|
#include "tier1/xorstr.h"
|
|
#include "tier1/utlmap.h"
|
|
#include "tier2/curlutils.h"
|
|
#include "zip/src/ZipFile.h"
|
|
#include <public/tier0/binstream.h>
|
|
|
|
bool g_bPartialInstall = false;
|
|
//bool g_bExperimentalBuilds = false;
|
|
float g_flUpdateCheckRate = 64;
|
|
|
|
double s_flLastProgressUpdate = 0.0;
|
|
|
|
#define PROGRESS_CALLBACK_UPDATE_DELTA 0.1
|
|
|
|
// !TODO: perhaps this should be a core utility shared across
|
|
// the entire SDK to allow processes to restart them selfs.
|
|
void SDKLauncher_Restart()
|
|
{
|
|
char currentPath[MAX_PATH];
|
|
BOOL getResult = GetCurrentDirectoryA(sizeof(currentPath), currentPath);
|
|
|
|
if (!getResult)
|
|
{
|
|
// TODO: dialog box and instruct user to manually open the launcher again.
|
|
printf("%s: Failed to obtain current directory: error code = %08x\n", __FUNCTION__, GetLastError());
|
|
ExitProcess(0xBADC0DE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
STARTUPINFOA StartupInfo = { 0 };
|
|
PROCESS_INFORMATION ProcInfo = { 0 };
|
|
|
|
// Initialize startup info struct.
|
|
StartupInfo.cb = sizeof(STARTUPINFOA);
|
|
|
|
DWORD processId = GetProcessId(GetCurrentProcess());
|
|
|
|
char commandLine[MAX_PATH];
|
|
sprintf(commandLine, "%lu %s %s", processId, RESTART_DEPOT_DOWNLOAD_DIR, currentPath);
|
|
|
|
BOOL createResult = CreateProcessA(
|
|
"bin\\updater.exe", // lpApplicationName
|
|
commandLine, // lpCommandLine
|
|
NULL, // lpProcessAttributes
|
|
NULL, // lpThreadAttributes
|
|
FALSE, // bInheritHandles
|
|
CREATE_SUSPENDED, // dwCreationFlags
|
|
NULL, // lpEnvironment
|
|
currentPath, // lpCurrentDirectory
|
|
&StartupInfo, // lpStartupInfo
|
|
&ProcInfo // lpProcessInformation
|
|
);
|
|
|
|
if (!createResult)
|
|
{
|
|
// TODO: dialog box and instruct user to update again.
|
|
printf("%s: Failed to create update process: error code = %08x\n", __FUNCTION__, GetLastError());
|
|
ExitProcess(0xBADC0DE);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Resume the process.
|
|
ResumeThread(ProcInfo.hThread);
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Close the process and thread handles.
|
|
CloseHandle(ProcInfo.hProcess);
|
|
CloseHandle(ProcInfo.hThread);
|
|
|
|
ExitProcess(EXIT_SUCCESS);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_CreateDepotDirectories()
|
|
{
|
|
if ((!CreateDirectoryA(BASE_PLATFORM_DIR, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) ||
|
|
(!CreateDirectoryA(DEFAULT_DEPOT_DOWNLOAD_DIR, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) ||
|
|
(!CreateDirectoryA(RESTART_DEPOT_DOWNLOAD_DIR, NULL) && GetLastError() != ERROR_ALREADY_EXISTS))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_ClearDepotDirectories()
|
|
{
|
|
// Clear all depot files.
|
|
if (!RemoveDirectoryA(RESTART_DEPOT_DOWNLOAD_DIR) ||
|
|
!RemoveDirectoryA(DEFAULT_DEPOT_DOWNLOAD_DIR))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool GetDepotList(const nlohmann::json& manifest, nlohmann::json& outDepotList)
|
|
{
|
|
if (manifest.contains("depot"))
|
|
{
|
|
const nlohmann::json& depotListArray = manifest["depot"];
|
|
|
|
if (!depotListArray.empty())
|
|
{
|
|
outDepotList = depotListArray;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool GetDepotEntry(const nlohmann::json& manifest, const char* targetDepotName, nlohmann::json& outDepotEntry)
|
|
{
|
|
nlohmann::json depotList;
|
|
|
|
if (GetDepotList(manifest, depotList))
|
|
{
|
|
printf("*** -<[DEPOT_LIST]>- ***\n%s\n", depotList.dump(4).c_str());
|
|
|
|
for (const auto& depot : depotList)
|
|
{
|
|
if (!depot.contains("name"))
|
|
continue;
|
|
|
|
const string depotName = depot["name"].get<string>();
|
|
|
|
if (depotName.compare(targetDepotName) == NULL)
|
|
{
|
|
outDepotEntry = depot;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%s: Failed on target(%s):\n%s\n", __FUNCTION__, targetDepotName, manifest.dump(4).c_str());
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool GetDepotAssetList(const nlohmann::json& manifest, const char* targetDepotName, nlohmann::json& outAssetList)
|
|
{
|
|
nlohmann::json depotEntry;
|
|
|
|
if (GetDepotEntry(manifest, targetDepotName, depotEntry))
|
|
{
|
|
printf("*** -<[DEPOT_ENTRY]>- ***\n%s\n", depotEntry.dump(4).c_str());
|
|
|
|
if (depotEntry.contains("assets"))
|
|
{
|
|
const nlohmann::json& assetList = depotEntry["assets"];
|
|
|
|
if (!assetList.empty())
|
|
{
|
|
outAssetList = depotEntry["assets"];
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("%s: Failed on target(%s):\n%s\n", __FUNCTION__, targetDepotName, manifest.dump(4).c_str());
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_ExtractZipFile(nlohmann::json& manifest, const CUtlString& filePath, CProgressPanel* pProgress)
|
|
{
|
|
ZipArchive::Ptr archive = ZipFile::Open(filePath.Get());
|
|
size_t entries = archive->GetEntriesCount();
|
|
|
|
nlohmann::json assetList;
|
|
CUtlString fileName = filePath.UnqualifiedFilename();
|
|
|
|
const bool assetListRet = GetDepotAssetList(manifest, fileName.String(), assetList);
|
|
|
|
for (size_t i = 0; i < entries; ++i)
|
|
{
|
|
auto entry = archive->GetEntry(int(i));
|
|
|
|
if (entry->IsDirectory())
|
|
continue;
|
|
|
|
const CUtlString fullName = entry->GetFullName().c_str();
|
|
bool installDuringRestart = false;
|
|
|
|
const char* const pFullName = fullName.Get();
|
|
|
|
// Determine whether or not the asset needs
|
|
// to be installed during a restart.
|
|
if (assetListRet && assetList.contains(pFullName))
|
|
{
|
|
const nlohmann::json& assetEntry = assetList[pFullName];
|
|
|
|
if (assetEntry.contains("restart"))
|
|
{
|
|
installDuringRestart = assetEntry["restart"].get<bool>();
|
|
}
|
|
}
|
|
|
|
CUtlString absDirName = fullName.AbsPath();
|
|
CUtlString dirName = absDirName.DirName();
|
|
|
|
CreateDirectories(absDirName.Get());
|
|
|
|
if (pProgress)
|
|
{
|
|
pProgress->SetExportLabel(Format("%s (%llu of %llu)", pFullName, i+1, entries).c_str());
|
|
|
|
size_t percentage = (i * 100) / entries;
|
|
pProgress->UpdateProgress((uint32_t)percentage, false);
|
|
}
|
|
|
|
printf("Extracting: %s to %s\n", pFullName, dirName.Get());
|
|
|
|
if (installDuringRestart)
|
|
{
|
|
CUtlString tempDir = RESTART_DEPOT_DOWNLOAD_DIR;
|
|
tempDir.Append(pFullName);
|
|
|
|
ZipFile::ExtractFile(filePath.Get(), pFullName, tempDir.Get());
|
|
}
|
|
else
|
|
{
|
|
ZipFile::ExtractFile(filePath.Get(), pFullName, pFullName);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_QueryServer(const char* url, string& outResponse, string& outMessage, CURLINFO& outStatus)
|
|
{
|
|
curl_slist* sList = nullptr;
|
|
CURLParams params;
|
|
|
|
params.writeFunction = CURLWriteStringCallback;
|
|
params.timeout = QUERY_TIMEOUT;
|
|
params.verifyPeer = true;
|
|
params.followRedirect = true;
|
|
params.verbose = 0;// IsDebug();
|
|
|
|
CURL* curl = CURLInitRequest(url, nullptr, outResponse, sList, params);
|
|
|
|
if (!curl)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
CURLcode res = CURLSubmitRequest(curl, sList);
|
|
|
|
if (!CURLHandleError(curl, res, outMessage, true))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
outStatus = CURLRetrieveInfo(curl);
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_AcquireReleaseManifest(const char* url, string& responseMessage,
|
|
nlohmann::json& outManifest, const bool preRelease)
|
|
{
|
|
string responseBody;
|
|
CURLINFO status;
|
|
|
|
if (!SDKLauncher_QueryServer(url, responseBody, responseMessage, status))
|
|
{
|
|
responseMessage = responseBody;
|
|
return false;
|
|
}
|
|
|
|
if (status != 200)
|
|
{
|
|
responseMessage = responseBody;
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
nlohmann::json responseJson = nlohmann::json::parse(responseBody);
|
|
|
|
for (size_t i = 0; i < responseJson.size(); i++)
|
|
{
|
|
auto& release = responseJson[i];
|
|
|
|
if (preRelease && release["prerelease"])
|
|
{
|
|
outManifest = release;
|
|
break;
|
|
}
|
|
else if (!release["prerelease"])
|
|
{
|
|
outManifest = release;
|
|
break;
|
|
}
|
|
|
|
if (i == responseJson.size() - 1 && outManifest.empty())
|
|
release[0]; // Just take the first one then.
|
|
}
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
printf("%s - Exception while parsing response:\n%s\n", __FUNCTION__, ex.what());
|
|
return false;
|
|
}
|
|
|
|
Assert(!outManifest.empty());
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
int SDKLauncher_ProgressCallback(CURLProgress* progessData, double dltotal,
|
|
double dlnow, double ultotal, double ulnow)
|
|
{
|
|
CProgressPanel* pDownloadSurface = (CProgressPanel*)progessData->cust;
|
|
|
|
if (pDownloadSurface->IsCanceled())
|
|
{
|
|
pDownloadSurface->Close();
|
|
return -1;
|
|
}
|
|
|
|
// This gets called often, prevent this callback from eating all CPU.
|
|
//const double curTime = Plat_FloatTime();
|
|
//if ((curTime - s_flLastProgressUpdate) < PROGRESS_CALLBACK_UPDATE_DELTA)
|
|
//{
|
|
// return 0;
|
|
//}
|
|
//s_flLastProgressUpdate = curTime;
|
|
|
|
double downloaded;
|
|
curl_easy_getinfo(progessData->curl, CURLINFO_SIZE_DOWNLOAD, &downloaded);
|
|
|
|
pDownloadSurface->SetExportLabel(Format("%s (%s of %s)", progessData->name,
|
|
FormatBytes((size_t)downloaded).c_str(), FormatBytes(progessData->size).c_str()).c_str());
|
|
|
|
size_t percentage = ((size_t)downloaded * 100) / progessData->size;
|
|
pDownloadSurface->UpdateProgress((uint32_t)percentage, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_DownloadAsset(const char* url, const char* path, const char* fileName,
|
|
const size_t fileSize, const char* options, CProgressPanel* pProgress)
|
|
{
|
|
CURLParams params;
|
|
|
|
params.writeFunction = CURLWriteFileCallback;
|
|
params.statusFunction = SDKLauncher_ProgressCallback;
|
|
params.followRedirect = true;
|
|
|
|
return CURLDownloadFile(url, path, fileName, options, fileSize, pProgress, params);
|
|
}
|
|
|
|
bool SDKLauncher_BuildUpdateList(const nlohmann::json& localManifest,
|
|
const nlohmann::json& remoteManifest, CUtlVector<CUtlString>& outDepotList)
|
|
{
|
|
try
|
|
{
|
|
const nlohmann::json& remoteDepotArray = remoteManifest["depot"];
|
|
const nlohmann::json& localDepotArray = localManifest["depot"];
|
|
|
|
for (const auto& remoteDepot : remoteDepotArray)
|
|
{
|
|
const string& remoteDepotName = remoteDepot["name"];
|
|
|
|
bool containsDepot = false;
|
|
bool digestMatch = false;
|
|
|
|
for (const auto& localDepot : localDepotArray)
|
|
{
|
|
if (localDepot["name"] == remoteDepotName)
|
|
{
|
|
containsDepot = true;
|
|
|
|
if (remoteDepot["digest"].get<string>() == localDepot["digest"].get<string>())
|
|
{
|
|
digestMatch = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (containsDepot)
|
|
{
|
|
if (!digestMatch)
|
|
{
|
|
// Checksum mismatch, the file has been changed,
|
|
// add it to the list so we are installing it.
|
|
outDepotList.AddToTail(remoteDepotName.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Local manifest does not contain the asset,
|
|
// add it to the list so we are installing it.
|
|
outDepotList.AddToTail(remoteDepotName.c_str());
|
|
}
|
|
}
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
printf("%s - Exception while building update list:\n%s\n", __FUNCTION__, ex.what());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots,
|
|
CUtlVector<CUtlString>& zipList, CProgressPanel* pProgress)
|
|
{
|
|
string responseMessage;
|
|
nlohmann::json remoteManifest;
|
|
|
|
if (!SDKLauncher_GetRemoteManifest(XorStr(SDK_DEPOT_VENDOR), responseMessage, remoteManifest, bPreRelease))
|
|
{
|
|
printf("%s: Failed! %s\n", "SDKLauncher_GetRemoteManifest", responseMessage.c_str());
|
|
return false;
|
|
}
|
|
|
|
CUtlVector<CUtlString> depotList;
|
|
nlohmann::json localManifest;
|
|
|
|
if (SDKLauncher_GetLocalManifest(localManifest))
|
|
{
|
|
SDKLauncher_BuildUpdateList(localManifest, remoteManifest, depotList);
|
|
}
|
|
else
|
|
{
|
|
// Leave the vector empty, this will download everything.
|
|
Assert(depotList.IsEmpty());
|
|
}
|
|
|
|
FOR_EACH_VEC(depotList, i)
|
|
{
|
|
const CUtlString& depotName = depotList[i];
|
|
printf("CUtlVector< CUtlString >::depotList[ %d ] = %s\n", i, depotName.Get());
|
|
}
|
|
|
|
if (!SDKLauncher_DownloadDepotList(remoteManifest, depotList,
|
|
zipList, pProgress, DEFAULT_DEPOT_DOWNLOAD_DIR, bOptionalDepots))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Canceling returns true, as the function didn't fail.
|
|
// We should however still delete all the downloaded files.
|
|
if (pProgress->IsCanceled())
|
|
return true;
|
|
|
|
|
|
if (!SDKLauncher_InstallDepotList(remoteManifest, zipList, pProgress))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!SDKLauncher_WriteLocalManifest(remoteManifest))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_DownloadDepotList(nlohmann::json& manifest, CUtlVector<CUtlString>& depotList,
|
|
CUtlVector<CUtlString>& outZipList, CProgressPanel* pProgress, const char* pPath,
|
|
const bool bOptionalDepots)
|
|
{
|
|
if (!manifest.contains("depot"))
|
|
{
|
|
Assert(0);
|
|
return false;
|
|
}
|
|
|
|
const auto depotListArray = manifest["depot"];
|
|
|
|
if (depotListArray.empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int i = 1;
|
|
|
|
for (auto& depot : depotListArray)
|
|
{
|
|
if (pProgress->IsCanceled())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!SDKLauncher_IsDepositoryValid(depot))
|
|
{
|
|
// Invalid manifest format.
|
|
Assert(0);
|
|
continue;
|
|
}
|
|
|
|
if ((!bOptionalDepots &&
|
|
depot["optional"].get<bool>()))
|
|
{
|
|
// Optional depots disabled.
|
|
continue;
|
|
}
|
|
|
|
const string fileName = depot["name"].get<string>();
|
|
|
|
if (!depotList.IsEmpty())
|
|
{
|
|
if (!depotList.HasElement(fileName.c_str()))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const size_t fileSize = depot["size"].get<size_t>();
|
|
string downloadLink = depot["vendor"].get<string>();
|
|
|
|
AppendSlash(downloadLink, '/');
|
|
downloadLink.append(fileName);
|
|
|
|
pProgress->SetText(Format("Downloading package %i of %i...", i,
|
|
!depotList.IsEmpty() ? depotList.Count() : (int)depotListArray.size()).c_str());
|
|
|
|
SDKLauncher_DownloadAsset(downloadLink.c_str(), pPath, fileName.c_str(), fileSize, "wb+", pProgress);
|
|
|
|
// Check if its a zip file, as these are
|
|
// the only files that will be installed.
|
|
if (V_strcmp(V_GetFileExtension(fileName.c_str()), "zip") == NULL)
|
|
{
|
|
CUtlString filePath;
|
|
|
|
filePath = pPath;
|
|
filePath.AppendSlash('/');
|
|
filePath.Append(fileName.c_str());
|
|
|
|
outZipList.AddToTail(filePath);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_InstallDepotList(nlohmann::json& manifest, CUtlVector<CUtlString>& fileList, CProgressPanel* pProgress)
|
|
{
|
|
// Install process cannot be canceled.
|
|
pProgress->SetCanCancel(false);
|
|
|
|
FOR_EACH_VEC(fileList, i)
|
|
{
|
|
pProgress->SetText(Format("Installing package %i of %i...", i + 1, fileList.Count()).c_str());
|
|
|
|
CUtlString& filePath = fileList[i];
|
|
if (!SDKLauncher_ExtractZipFile(manifest, filePath, pProgress))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose: checks if client has enough disk space
|
|
// Input : minRequiredSpace -
|
|
// : *availableSize -
|
|
// Output : true if space is sufficient, false otherwise
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_CheckDiskSpace(const int minRequiredSpace, int* const availableSize)
|
|
{
|
|
char currentDir[MAX_PATH]; // Get current dir.
|
|
GetCurrentDirectoryA(sizeof(currentDir), currentDir);
|
|
|
|
// Does this disk have enough space?
|
|
ULARGE_INTEGER avaliableSize;
|
|
GetDiskFreeSpaceEx(currentDir, &avaliableSize, nullptr, nullptr);
|
|
|
|
const int currentAvailSpace = (int)(avaliableSize.QuadPart / uint64_t(1024 * 1024 * 1024));
|
|
|
|
if (availableSize)
|
|
{
|
|
*availableSize = currentAvailSpace;
|
|
}
|
|
|
|
if (currentAvailSpace < minRequiredSpace)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDKLauncher_IsManifestValid(const nlohmann::json& depotManifest)
|
|
{
|
|
return (!depotManifest.empty() &&
|
|
depotManifest.contains("version") &&
|
|
depotManifest.contains("depot"));
|
|
}
|
|
|
|
bool SDKLauncher_IsDepositoryValid(const nlohmann::json& depot)
|
|
{
|
|
return (!depot.empty() &&
|
|
depot.contains("optional") &&
|
|
depot.contains("vendor") &&
|
|
depot.contains("size") &&
|
|
depot.contains("name"));
|
|
}
|
|
|
|
bool SDKLauncher_GetRemoteManifest(const char* url, string& responseMessage, nlohmann::json& remoteManifest, const bool bPreRelease)
|
|
{
|
|
nlohmann::json responseJson;
|
|
|
|
if (!SDKLauncher_AcquireReleaseManifest(url, responseMessage, responseJson, bPreRelease))
|
|
{
|
|
// TODO: Error dialog.
|
|
|
|
printf("%s: failed!\n", "SDKLauncher_AcquireReleaseManifest");
|
|
return false;
|
|
}
|
|
|
|
if (!responseJson.contains("assets"))
|
|
{
|
|
printf("%s: failed!\n", "responseJson.contains(\"assets\")");
|
|
return false;
|
|
}
|
|
|
|
try
|
|
{
|
|
string depotManifestUrl;
|
|
|
|
{
|
|
nlohmann::json& assetList = responseJson["assets"];
|
|
|
|
for (const auto& asset : assetList)
|
|
{
|
|
if (asset["name"] == DEPOT_MANIFEST_FILE)
|
|
{
|
|
depotManifestUrl = asset["browser_download_url"];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (depotManifestUrl.empty())
|
|
{
|
|
printf("depotManifestUrl.empty()==true\n");
|
|
return false;
|
|
}
|
|
|
|
string responseBody;
|
|
CURLINFO status;
|
|
|
|
if (!SDKLauncher_QueryServer(depotManifestUrl.c_str(), responseBody, responseMessage, status) ||
|
|
status != 200)
|
|
{
|
|
printf("%s: failed! %s, status=%d\n", "SDKLauncher_QueryServer", responseMessage.c_str(), status);
|
|
|
|
responseMessage = responseBody;
|
|
return false;
|
|
}
|
|
|
|
remoteManifest = nlohmann::json::parse(responseBody);
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
printf("%s - Exception while parsing response:\n%s\n", __FUNCTION__, ex.what());
|
|
return false;
|
|
}
|
|
|
|
Assert(!remoteManifest.empty());
|
|
return true;
|
|
}
|
|
|
|
bool SDKLauncher_GetLocalManifest(nlohmann::json& localManifest)
|
|
{
|
|
if (!fs::exists(DEPOT_MANIFEST_FILE_PATH))
|
|
return false;
|
|
|
|
ifstream localFile(DEPOT_MANIFEST_FILE_PATH);
|
|
|
|
if (!localFile.good())
|
|
return false;
|
|
|
|
try
|
|
{
|
|
localManifest = nlohmann::json::parse(localFile);
|
|
|
|
if (!SDKLauncher_IsManifestValid(localManifest))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
printf("%s - Exception while parsing manifest:\n%s\n", __FUNCTION__, ex.what());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SDKLauncher_WriteLocalManifest(const nlohmann::json& localManifest)
|
|
{
|
|
CIOStream writer;
|
|
if (!writer.Open(DEPOT_MANIFEST_FILE_PATH, CIOStream::Mode_t::WRITE))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const string manifestBuf = localManifest.dump(4);
|
|
writer.Write(manifestBuf.c_str(), manifestBuf.size());
|
|
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_CheckForUpdate(const bool bPreRelease)
|
|
{
|
|
nlohmann::json remoteManifest;
|
|
string responseMessage;
|
|
|
|
if (!SDKLauncher_AcquireReleaseManifest(XorStr(SDK_DEPOT_VENDOR), responseMessage, remoteManifest, bPreRelease))
|
|
{
|
|
printf("%s: Failed to obtain remote manifest: %s\n", __FUNCTION__, responseMessage.c_str());
|
|
return false; // Can't determine if there is an update or not; skip...
|
|
}
|
|
|
|
nlohmann::json localManifest;
|
|
|
|
if (!SDKLauncher_GetLocalManifest(localManifest))
|
|
{
|
|
// Failed to load a local one; assume an update is required.
|
|
printf("%s: Failed to obtain local manifest\n", __FUNCTION__);
|
|
return true;
|
|
}
|
|
|
|
if (!localManifest.contains("version"))
|
|
{
|
|
// No version information; assume an update is required.
|
|
printf("%s: Local manifest does not contain field '%s'!\n", __FUNCTION__, "version");
|
|
return true;
|
|
}
|
|
|
|
// This evaluates to '0' if the version tags are equal.
|
|
return !(localManifest["version"] == remoteManifest["tag_name"]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//----------------------------------------------------------------------------
|
|
bool SDKLauncher_ForceExistingInstanceOnTop()
|
|
{
|
|
HWND existingApp = FindWindowA(FORM_DEFAULT_CLASS_NAME, NULL);
|
|
|
|
if (existingApp)
|
|
{
|
|
ForceForegroundWindow(existingApp);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|