mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-04-09 19:12:15 +02:00
Merge pull request #16038 from huffman/feat/win-launcher-tags
DEV-256: Add build tags to Windows launcher
This commit is contained in:
commit
c31d463b6a
4 changed files with 109 additions and 40 deletions
|
@ -36,6 +36,7 @@ void LauncherManager::init(BOOL allowUpdate, ContinueActionOnStart continueActio
|
|||
}
|
||||
addToLog(_T("Launcher is running version: " + _launcherVersion));
|
||||
addToLog(_T("Getting most recent builds"));
|
||||
_isInstalled = isApplicationInstalled(_currentVersion, _domainURL, _contentURL, _loggedIn, _organizationBuildTag);
|
||||
getMostRecentBuilds(_latestLauncherURL, _latestLauncherVersion, _latestApplicationURL, _latestVersion);
|
||||
}
|
||||
|
||||
|
@ -260,14 +261,14 @@ BOOL LauncherManager::deleteShortcuts() {
|
|||
}
|
||||
|
||||
BOOL LauncherManager::isApplicationInstalled(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn) {
|
||||
CString& content, bool& loggedIn, CString& organizationBuildTag) {
|
||||
CString applicationDir;
|
||||
getAndCreatePaths(PathType::Launcher_Directory, applicationDir);
|
||||
CString applicationPath = applicationDir + "interface\\interface.exe";
|
||||
BOOL isInstalled = PathFileExistsW(applicationPath);
|
||||
BOOL configFileExist = PathFileExistsW(applicationDir + _T("interface\\config.json"));
|
||||
if (configFileExist) {
|
||||
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn);
|
||||
LauncherUtils::ResponseError status = readConfigJSON(version, domain, content, loggedIn, organizationBuildTag);
|
||||
return isInstalled && status == LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
return FALSE;
|
||||
|
@ -326,7 +327,6 @@ BOOL LauncherManager::getInstalledVersion(const CString& path, CString& version)
|
|||
return success;
|
||||
}
|
||||
|
||||
|
||||
HWND LauncherManager::launchApplication() {
|
||||
CString installDir;
|
||||
LauncherManager::getAndCreatePaths(PathType::Interface_Directory, installDir);
|
||||
|
@ -368,6 +368,7 @@ BOOL LauncherManager::createConfigJSON() {
|
|||
config["launcherPath"] = LauncherUtils::cStringToStd(applicationPath);
|
||||
config["version"] = LauncherUtils::cStringToStd(_latestVersion);
|
||||
config["domain"] = LauncherUtils::cStringToStd(_domainURL);
|
||||
config["organizationBuildTag"] = LauncherUtils::cStringToStd(_organizationBuildTag);
|
||||
CString content;
|
||||
getAndCreatePaths(PathType::Content_Directory, content);
|
||||
config["content"] = LauncherUtils::cStringToStd(content);
|
||||
|
@ -377,7 +378,7 @@ BOOL LauncherManager::createConfigJSON() {
|
|||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn) {
|
||||
CString& content, bool& loggedIn, CString& organizationBuildTag) {
|
||||
CString configPath;
|
||||
getAndCreatePaths(PathType::Interface_Directory, configPath);
|
||||
configPath += "\\config.json";
|
||||
|
@ -394,6 +395,13 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C
|
|||
version = config["version"].asCString();
|
||||
domain = config["domain"].asCString();
|
||||
content = config["content"].asCString();
|
||||
|
||||
if (config["organizationBuildTag"].isString()) {
|
||||
organizationBuildTag = config["organizationBuildTag"].asCString();
|
||||
} else {
|
||||
organizationBuildTag = "";
|
||||
}
|
||||
|
||||
configFile.close();
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
|
@ -401,12 +409,43 @@ LauncherUtils::ResponseError LauncherManager::readConfigJSON(CString& version, C
|
|||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
bool findBuildInResponse(const Json::Value& json, const CString& tag, CString& interfaceUrlOut, CString& interfaceVersionOut) {
|
||||
if (json["results"].isArray()) {
|
||||
auto& results = json["results"];
|
||||
int count = results.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (results[i].isObject()) {
|
||||
Json::Value result = results[i];
|
||||
if (result["name"].asCString() == tag) {
|
||||
if (result["latest_version"].isInt()) {
|
||||
std::string version = std::to_string(result["latest_version"].asInt());
|
||||
interfaceVersionOut = CString(version.c_str());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (result["installers"].isObject() &&
|
||||
result["installers"]["windows"].isObject() &&
|
||||
result["installers"]["windows"]["zip_url"].isString()) {
|
||||
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString& hash) {
|
||||
CString contentTypeJson = L"content-type:application/json";
|
||||
CString response;
|
||||
CString url = _T("/organizations/") + hash + _T(".json");
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(),
|
||||
L"orgs.highfidelity.com", url,
|
||||
true, L"orgs.highfidelity.com", url,
|
||||
contentTypeJson, CStringA(),
|
||||
response, false);
|
||||
if (error != LauncherUtils::ResponseError::NoError) {
|
||||
|
@ -417,6 +456,13 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
|
|||
if (json["content_set_url"].isString() && json["domain"].isString()) {
|
||||
_contentURL = json["content_set_url"].asCString();
|
||||
_domainURL = json["domain"].asCString();
|
||||
_organizationBuildTag = json.get("build_tag", "").asCString();
|
||||
auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag;
|
||||
|
||||
if (!findBuildInResponse(_latestBuilds, buildTag, _latestApplicationURL, _latestVersion)) {
|
||||
return LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
|
||||
return LauncherUtils::ResponseError::NoError;
|
||||
}
|
||||
}
|
||||
|
@ -429,8 +475,12 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun
|
|||
std::function<void(CString, int)> httpCallback = [&](CString response, int err) {
|
||||
LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err);
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
Json::Value json;
|
||||
Json::Value& json = _latestBuilds;
|
||||
if (LauncherUtils::parseJSON(response, json)) {
|
||||
_defaultBuildTag = json.get("default_tag", "").asCString();
|
||||
auto buildTag = _organizationBuildTag.IsEmpty() ? _defaultBuildTag : _organizationBuildTag;
|
||||
addToLog(_T("Build tag is: ") + buildTag);
|
||||
|
||||
if (json["launcher"].isObject()) {
|
||||
if (json["launcher"]["windows"].isObject() && json["launcher"]["windows"]["url"].isString()) {
|
||||
launcherUrlOut = json["launcher"]["windows"]["url"].asCString();
|
||||
|
@ -440,41 +490,50 @@ void LauncherManager::getMostRecentBuilds(CString& launcherUrlOut, CString& laun
|
|||
launcherVersionOut = CString(version.c_str());
|
||||
}
|
||||
}
|
||||
int count = json["count"].isInt() ? json["count"].asInt() : 0;
|
||||
if (count > 0 && json["results"].isArray()) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (json["results"][i].isObject()) {
|
||||
Json::Value result = json["results"][i];
|
||||
if (result["latest_version"].isInt()) {
|
||||
std::string version = std::to_string(result["latest_version"].asInt());
|
||||
interfaceVersionOut = CString(version.c_str());
|
||||
}
|
||||
if (result["installers"].isObject() &&
|
||||
result["installers"]["windows"].isObject() &&
|
||||
result["installers"]["windows"]["zip_url"].isString()) {
|
||||
interfaceUrlOut = result["installers"]["windows"]["zip_url"].asCString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty()) {
|
||||
error = LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
if (launcherUrlOut.IsEmpty() || launcherVersionOut.IsEmpty() || interfaceUrlOut.IsEmpty() || interfaceVersionOut.IsEmpty()) {
|
||||
|
||||
if (!findBuildInResponse(json, buildTag, _latestApplicationURL, _latestVersion)) {
|
||||
addToLog(_T("Failed to find build"));
|
||||
error = LauncherUtils::ResponseError::ParsingJSON;
|
||||
}
|
||||
}
|
||||
}
|
||||
onMostRecentBuildsReceived(response, error);
|
||||
};
|
||||
|
||||
bool useHTTPS{ true };
|
||||
|
||||
CString domainName;
|
||||
if (domainName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_DOMAIN")) {
|
||||
addToLog(_T("Using overridden builds domain: ") + domainName);
|
||||
useHTTPS = false;
|
||||
} else {
|
||||
domainName = L"thunder.highfidelity.com";
|
||||
}
|
||||
|
||||
CString pathName;
|
||||
if (pathName.GetEnvironmentVariable(L"HQ_LAUNCHER_BUILDS_PATH")) {
|
||||
addToLog(_T("Using overridden builds path: ") + pathName);
|
||||
useHTTPS = false;
|
||||
} else {
|
||||
pathName = L"/builds/api/tags/latest?format=json";
|
||||
}
|
||||
|
||||
LauncherUtils::httpCallOnThread(getHttpUserAgent(),
|
||||
L"thunder.highfidelity.com",
|
||||
L"/builds/api/tags/latest?format=json",
|
||||
useHTTPS,
|
||||
domainName,
|
||||
pathName,
|
||||
contentTypeJson, CStringA(), false, httpCallback);
|
||||
}
|
||||
|
||||
void LauncherManager::onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error) {
|
||||
if (error == LauncherUtils::ResponseError::NoError) {
|
||||
addToLog(_T("Latest launcher version: ") + _latestLauncherVersion);
|
||||
CString currentVersion;
|
||||
BOOL isInstalled = (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn);
|
||||
CString currentVersion = _currentVersion;
|
||||
BOOL isInstalled = _isInstalled && _loggedIn;
|
||||
bool newInterfaceVersion = _latestVersion.Compare(currentVersion) != 0;
|
||||
bool newLauncherVersion = _latestLauncherVersion.Compare(_launcherVersion) != 0 && _updateLauncherAllowed;
|
||||
if (newLauncherVersion) {
|
||||
|
@ -511,7 +570,7 @@ void LauncherManager::onMostRecentBuildsReceived(const CString& response, Launch
|
|||
_shouldWait = FALSE;
|
||||
|
||||
} else {
|
||||
_hasFailed = true;
|
||||
setFailed(true);
|
||||
CString msg;
|
||||
msg.Format(_T("Getting most recent builds has failed with error: %d"), error);
|
||||
addToLog(msg);
|
||||
|
@ -531,6 +590,7 @@ LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const
|
|||
CString contentTypeText = L"content-type:application/x-www-form-urlencoded";
|
||||
CString response;
|
||||
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(getHttpUserAgent(),
|
||||
true,
|
||||
L"metaverse.highfidelity.com",
|
||||
L"/oauth/token",
|
||||
contentTypeText, post,
|
||||
|
@ -611,7 +671,7 @@ BOOL LauncherManager::extractApplication() {
|
|||
onZipExtracted((ProcessType)type, size);
|
||||
} else {
|
||||
addToLog(_T("Error decompressing application zip file."));
|
||||
_hasFailed = true;
|
||||
setFailed(true);
|
||||
}
|
||||
};
|
||||
std::function<void(float)> onProgress = [&](float progress) {
|
||||
|
@ -688,7 +748,7 @@ BOOL LauncherManager::installContent() {
|
|||
}
|
||||
else {
|
||||
addToLog(_T("Error decompressing content zip file."));
|
||||
_hasFailed = true;
|
||||
setFailed(true);
|
||||
}
|
||||
};
|
||||
std::function<void(float)> onProgress = [&](float progress) {
|
||||
|
@ -728,7 +788,7 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString
|
|||
} else {
|
||||
addToLog(_T("Error downloading application."));
|
||||
}
|
||||
_hasFailed = true;
|
||||
setFailed(true);
|
||||
}
|
||||
};
|
||||
std::function<void(float)> onProgress = [&, type](float progress) {
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
BOOL getAndCreatePaths(PathType type, CString& outPath);
|
||||
BOOL getInstalledVersion(const CString& path, CString& version);
|
||||
BOOL isApplicationInstalled(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn);
|
||||
CString& content, bool& loggedIn, CString& organizationBuildTag);
|
||||
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
|
||||
void getMostRecentBuilds(CString& launcherUrlOut,
|
||||
CString& launcherVersionOut,
|
||||
|
@ -84,7 +84,7 @@ public:
|
|||
CString& interfaceVersionOut);
|
||||
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
|
||||
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
|
||||
CString& content, bool& loggedIn);
|
||||
CString& content, bool& loggedIn, CString& organizationBuildTag);
|
||||
BOOL createConfigJSON();
|
||||
BOOL createApplicationRegistryKeys(int size);
|
||||
BOOL deleteApplicationRegistryKeys();
|
||||
|
@ -139,10 +139,12 @@ public:
|
|||
private:
|
||||
ProcessType _currentProcess { ProcessType::DownloadApplication };
|
||||
void onMostRecentBuildsReceived(const CString& response, LauncherUtils::ResponseError error);
|
||||
|
||||
CString _latestApplicationURL;
|
||||
CString _latestVersion;
|
||||
CString _latestLauncherURL;
|
||||
CString _latestLauncherVersion;
|
||||
|
||||
CString _contentURL;
|
||||
CString _domainURL;
|
||||
CString _version;
|
||||
|
@ -152,6 +154,8 @@ private:
|
|||
CString _contentZipPath;
|
||||
CString _launcherVersion;
|
||||
CString _tempLauncherPath;
|
||||
CString _currentVersion;
|
||||
bool _isInstalled{ false };
|
||||
bool _loggedIn { false };
|
||||
bool _hasFailed { false };
|
||||
BOOL _shouldUpdate { FALSE };
|
||||
|
@ -171,4 +175,7 @@ private:
|
|||
float _progressOffset { 0.0f };
|
||||
float _progress { 0.0f };
|
||||
CStdioFile _logFile;
|
||||
Json::Value _latestBuilds;
|
||||
CString _defaultBuildTag;
|
||||
CString _organizationBuildTag;
|
||||
};
|
||||
|
|
|
@ -181,7 +181,7 @@ BOOL LauncherUtils::deleteRegistryKey(const CString& registryPath) {
|
|||
}
|
||||
|
||||
LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerName,
|
||||
const CString& mainUrl, const CString& dirUrl,
|
||||
bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData,
|
||||
CString& response, bool isPost = false) {
|
||||
|
||||
|
@ -190,12 +190,12 @@ LauncherUtils::ResponseError LauncherUtils::makeHTTPCall(const CString& callerNa
|
|||
if (!hopen) {
|
||||
return ResponseError::Open;
|
||||
}
|
||||
HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
|
||||
HINTERNET hconnect = WinHttpConnect(hopen, mainUrl, useHTTPS ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
|
||||
if (!hconnect) {
|
||||
return ResponseError::Connect;
|
||||
}
|
||||
HINTERNET hrequest = WinHttpOpenRequest(hconnect, isPost ? L"POST" : L"GET", dirUrl,
|
||||
NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
|
||||
NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, useHTTPS ? WINHTTP_FLAG_SECURE : 0);
|
||||
if (!hrequest) {
|
||||
return ResponseError::OpenRequest;
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
|
|||
DWORD WINAPI LauncherUtils::httpThread(LPVOID lpParameter) {
|
||||
HttpThreadData& data = *((HttpThreadData*)lpParameter);
|
||||
CString response;
|
||||
auto error = LauncherUtils::makeHTTPCall(data._callerName, data._mainUrl, data._dirUrl,
|
||||
auto error = LauncherUtils::makeHTTPCall(data._callerName, data._useHTTPS, data._mainUrl, data._dirUrl,
|
||||
data._contentType, data._postData, response, data._isPost);
|
||||
data._callback(response, error);
|
||||
return 0;
|
||||
|
@ -552,12 +552,13 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
|
||||
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData, bool isPost,
|
||||
std::function<void(CString, int)> callback) {
|
||||
DWORD myThreadID;
|
||||
HttpThreadData* httpThreadData = new HttpThreadData();
|
||||
httpThreadData->_callerName = callerName;
|
||||
httpThreadData->_useHTTPS = useHTTPS;
|
||||
httpThreadData->_mainUrl = mainUrl;
|
||||
httpThreadData->_dirUrl = dirUrl;
|
||||
httpThreadData->_contentType = contentType;
|
||||
|
|
|
@ -120,6 +120,7 @@ public:
|
|||
|
||||
struct HttpThreadData {
|
||||
CString _callerName;
|
||||
bool _useHTTPS;
|
||||
CString _mainUrl;
|
||||
CString _dirUrl;
|
||||
CString _contentType;
|
||||
|
@ -137,7 +138,7 @@ public:
|
|||
};
|
||||
|
||||
static BOOL parseJSON(const CString& jsonTxt, Json::Value& jsonObject);
|
||||
static ResponseError makeHTTPCall(const CString& callerName, const CString& mainUrl,
|
||||
static ResponseError makeHTTPCall(const CString& callerName, bool useHTTPS, const CString& mainUrl,
|
||||
const CString& dirUrl, const CString& contentType,
|
||||
CStringA& postData, CString& response, bool isPost);
|
||||
static std::string cStringToStd(CString cstring);
|
||||
|
@ -163,7 +164,7 @@ public:
|
|||
std::function<void(int, bool)> callback,
|
||||
std::function<void(float)> progressCallback);
|
||||
static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback);
|
||||
static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
|
||||
static BOOL httpCallOnThread(const CString& callerName, bool useHTTPS, const CString& mainUrl, const CString& dirUrl,
|
||||
const CString& contentType, CStringA& postData, bool isPost,
|
||||
std::function<void(CString, int)> callback);
|
||||
|
||||
|
|
Loading…
Reference in a new issue