127 lines
7.9 KiB
C++
127 lines
7.9 KiB
C++
// 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;
|
||
}
|