CCEngine/CCEngineLoader/CCEngineLoader.cpp

127 lines
7.9 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// CCEngineLoader.cpp : Defines the entry point for the console application.
//
#include "CachedDownloader.h"
#include "HTTPClient.h"
#include "JSONModuleDatabase.h"
#include "ModuleManager.h"
#include <windows.h>
#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <fstream>
namespace pt = boost::property_tree;
namespace fs = boost::filesystem;
namespace
{
static const std::string updateCacheFolder = ".upd";
void waitUntilProcessTerminates(unsigned long processID)
{
HANDLE hProcess = OpenProcess(SYNCHRONIZE, true, processID);
if (NULL == hProcess)
{
WaitForSingleObject(hProcess, INFINITE);
}
}
void runApp(const std::string& cmdLine, bool waitForProcessToExit)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess(NULL, // No module name (use command line)
(LPSTR)cmdLine.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
DETACHED_PROCESS, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
if (waitForProcessToExit)
{
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
}
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
std::vector<ModuleUpdate> loadPendingUpdates(const boost::filesystem::path& appDir)
{
std::vector<ModuleUpdate> result;
boost::filesystem::path path(appDir / updateCacheFolder / ".updates.json");
if (boost::filesystem::is_regular_file(path))
{
pt::ptree root;
pt::read_json(path.string(), root);
deserialize(root, result);
}
return result;
}
}
int main(int argc, char* argv[])
{
auto appDir = fs::system_complete(argv[0]).parent_path();
unsigned long parentProcessId = 0;
if (argc >= 2)
{
parentProcessId = std::atol(argv[1]);
}
std::vector<ModuleUpdate> moduleUpdates = loadPendingUpdates(appDir);
HTTPClient httpClient;
CachedDownloader cachedDownloader(appDir / updateCacheFolder, httpClient);
JSONModuleDatabase moduleDatabase((appDir / ".inst").string());
ModuleManager moduleManager(appDir.string(), moduleDatabase, cachedDownloader);
bool isRestartRequired = false;
for (const auto& update : moduleUpdates)
{
bool restartRequired = update.flag & static_cast<uint32_t>(ModuleUpdateFlags::restartRequired);
isRestartRequired = isRestartRequired || restartRequired;
if (restartRequired && parentProcessId)
{
std::cout << "RestartRequired" << std::endl;
waitUntilProcessTerminates(parentProcessId);
parentProcessId = 0;
}
moduleManager.applyUpdate(update.moduleId, update);
std::cout << "UpdateApplied " << update.moduleId << " " << update.version << std::endl;
}
std::cout << "Done" << std::endl;
if (isRestartRequired)
{
runApp((appDir / "CCEngine.exe").string() + " --updated", false);
}
return 0;
}