From 9c56f7466246f619e1f410b608721d85ac23ab40 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 11 Jul 2019 10:28:49 -0700 Subject: [PATCH 1/2] Get recent builds asynchronously --- launchers/win32/LauncherDlg.cpp | 2 +- launchers/win32/LauncherManager.cpp | 121 ++++++++++++++-------------- launchers/win32/LauncherManager.h | 7 +- launchers/win32/LauncherUtils.cpp | 39 +++++++-- launchers/win32/LauncherUtils.h | 49 +++++++---- 5 files changed, 135 insertions(+), 83 deletions(-) diff --git a/launchers/win32/LauncherDlg.cpp b/launchers/win32/LauncherDlg.cpp index 704a2f3050..2e5d568839 100644 --- a/launchers/win32/LauncherDlg.cpp +++ b/launchers/win32/LauncherDlg.cpp @@ -672,7 +672,7 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) { theApp._manager.addToLog(_T("Start splash screen")); setDrawDialog(DrawStep::DrawLogo); } - } else if (_splashStep > 100) { + } else if (_splashStep > 100 && !theApp._manager.needsToWait()) { _showSplash = false; if (theApp._manager.shouldShutDown()) { if (_applicationWND != NULL) { diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index e56e0e71fc..81b76d13e7 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -25,34 +25,7 @@ void LauncherManager::init() { initLog(); addToLog(_T("Getting most recent build")); CString response; - LauncherUtils::ResponseError error = getMostRecentBuild(_latestApplicationURL, _latestVersion, response); - if (error == LauncherUtils::ResponseError::NoError) { - addToLog(_T("Latest version: ") + _latestVersion); - CString currentVersion; - if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) { - addToLog(_T("Installed version: ") + currentVersion); - if (_latestVersion.Compare(currentVersion) == 0) { - addToLog(_T("Already running most recent build. Launching interface.exe")); - _shouldLaunch = TRUE; - _shouldShutdown = TRUE; - } else { - addToLog(_T("New build found. Updating")); - _shouldUpdate = TRUE; - } - } else if (_loggedIn) { - addToLog(_T("Interface not found but logged in. Reinstalling")); - _shouldUpdate = TRUE; - } else { - _shouldInstall = TRUE; - } - } else { - _hasFailed = true; - CString msg; - msg.Format(_T("Getting most recent build has failed with error: %d"), error); - addToLog(msg); - msg.Format(_T("Response: %s"), response); - addToLog(msg); - } + getMostRecentBuild(_latestApplicationURL, _latestVersion, response); } BOOL LauncherManager::initLog() { @@ -387,39 +360,71 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString return LauncherUtils::ResponseError::ParsingJSON; } -LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut, - CString& response) { +void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response) { CString contentTypeJson = L"content-type:application/json"; - LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", - L"thunder.highfidelity.com", - L"/builds/api/tags/latest?format=json", - contentTypeJson, CStringA(), - response, false); - if (error != LauncherUtils::ResponseError::NoError) { - return error; - } - Json::Value json; - if (LauncherUtils::parseJSON(response, json)) { - 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()); - versionOut = CString(version.c_str()); - } - if (result["installers"].isObject() && - result["installers"]["windows"].isObject() && - result["installers"]["windows"]["zip_url"].isString()) { - urlOut = result["installers"]["windows"]["zip_url"].asCString(); - return LauncherUtils::ResponseError::NoError; + std::function httpCallback = [&](CString response, int err) { + LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err); + if (error == LauncherUtils::ResponseError::NoError) { + Json::Value json; + error = LauncherUtils::ResponseError::ParsingJSON; + if (LauncherUtils::parseJSON(response, json)) { + 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()); + versionOut = CString(version.c_str()); + } + if (result["installers"].isObject() && + result["installers"]["windows"].isObject() && + result["installers"]["windows"]["zip_url"].isString()) { + urlOut = result["installers"]["windows"]["zip_url"].asCString(); + error = LauncherUtils::ResponseError::NoError; + } + } } } } + onMostRecentBuildReceived(response, error); } + }; + LauncherUtils::httpCallOnThread(L"HQ Launcher", + L"thunder.highfidelity.com", + L"/builds/api/tags/latest?format=json", + contentTypeJson, CStringA(), false, httpCallback); +} + +void LauncherManager::onMostRecentBuildReceived(const CString& response, LauncherUtils::ResponseError error) { + if (error == LauncherUtils::ResponseError::NoError) { + addToLog(_T("Latest version: ") + _latestVersion); + CString currentVersion; + if (isApplicationInstalled(currentVersion, _domainURL, _contentURL, _loggedIn) && _loggedIn) { + addToLog(_T("Installed version: ") + currentVersion); + if (_latestVersion.Compare(currentVersion) == 0) { + addToLog(_T("Already running most recent build. Launching interface.exe")); + _shouldLaunch = TRUE; + _shouldShutdown = TRUE; + } else { + addToLog(_T("New build found. Updating")); + _shouldUpdate = TRUE; + } + } else if (_loggedIn) { + addToLog(_T("Interface not found but logged in. Reinstalling")); + _shouldUpdate = TRUE; + } else { + _shouldInstall = TRUE; + } + _shouldWait = FALSE; + } else { + _hasFailed = true; + CString msg; + msg.Format(_T("Getting most recent build has failed with error: %d"), error); + addToLog(msg); + msg.Format(_T("Response: %s"), response); + addToLog(msg); } - return LauncherUtils::ResponseError::ParsingJSON; } LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username, @@ -603,12 +608,10 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString std::function onDownloadFinished = [&](int type, bool error) { if (!error) { onFileDownloaded((ProcessType)type); - } - else { + } else { if (type == ProcessType::DownloadApplication) { addToLog(_T("Error downloading content.")); - } - else { + } else { addToLog(_T("Error downloading application.")); } _hasFailed = true; diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index cb707e0a14..e97ae6efcc 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -67,7 +67,7 @@ public: BOOL isApplicationInstalled(CString& version, CString& domain, CString& content, bool& loggedIn); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); - LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response); + void getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn); @@ -90,12 +90,13 @@ public: BOOL needsUpdate() { return _shouldUpdate; } BOOL needsUninstall() { return _shouldUninstall; } BOOL needsInstall() { return _shouldInstall; } + BOOL needsToWait() { return _shouldWait; } void setDisplayName(const CString& displayName) { _displayName = displayName; } bool isLoggedIn() { return _loggedIn; } bool hasFailed() { return _hasFailed; } void setFailed(bool hasFailed) { _hasFailed = hasFailed; } const CString& getLatestInterfaceURL() const { return _latestApplicationURL; } - void uninstall() { _shouldUninstall = true; }; + void uninstall() { _shouldUninstall = true; _shouldWait = false; }; BOOL downloadFile(ProcessType type, const CString& url, CString& localPath); BOOL downloadContent(); @@ -110,6 +111,7 @@ public: private: ProcessType _currentProcess { ProcessType::DownloadApplication }; + void onMostRecentBuildReceived(const CString& response, LauncherUtils::ResponseError error); CString _latestApplicationURL; CString _latestVersion; CString _contentURL; @@ -126,6 +128,7 @@ private: BOOL _shouldInstall { FALSE }; BOOL _shouldShutdown { FALSE }; BOOL _shouldLaunch { FALSE }; + BOOL _shouldWait { TRUE }; float _progress { 0.0f }; CStdioFile _logFile; }; diff --git a/launchers/win32/LauncherUtils.cpp b/launchers/win32/LauncherUtils.cpp index 3ba4b26901..e0a85302f0 100644 --- a/launchers/win32/LauncherUtils.cpp +++ b/launchers/win32/LauncherUtils.cpp @@ -470,9 +470,9 @@ BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) { UnzipThreadData& data = *((UnzipThreadData*)lpParameter); - uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector(), data.progressCallback); + uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector(), data._progressCallback); int mb_size = (int)(size * 0.001f); - data.callback(data._type, mb_size); + data._callback(data._type, mb_size); delete &data; return 0; } @@ -480,17 +480,26 @@ DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) { DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) { DownloadThreadData& data = *((DownloadThreadData*)lpParameter); ProgressCallback progressCallback; - progressCallback.setProgressCallback(data.progressCallback); + progressCallback.setProgressCallback(data._progressCallback); auto hr = URLDownloadToFile(0, data._url, data._file, 0, static_cast(&progressCallback)); - data.callback(data._type, hr != S_OK); + data._callback(data._type, hr != S_OK); return 0; } DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) { DeleteThreadData& data = *((DeleteThreadData*)lpParameter); BOOL success = LauncherUtils::deleteFileOrDirectory(data._dirPath); - data.callback(!success); + data._callback(!success); + return 0; +} + +DWORD WINAPI LauncherUtils::httpThread(LPVOID lpParameter) { + HttpThreadData& data = *((HttpThreadData*)lpParameter); + CString response; + auto error = LauncherUtils::makeHTTPCall(data._callerName, data._mainUrl, data._dirUrl, + data._contentType, data._postData, response, data._isPost); + data._callback(response, error); return 0; } @@ -543,6 +552,26 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio return FALSE; } +BOOL LauncherUtils::httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl, + const CString& contentType, CStringA& postData, bool isPost, + std::function callback) { + DWORD myThreadID; + HttpThreadData* httpThreadData = new HttpThreadData(); + httpThreadData->_callerName = callerName; + httpThreadData->_mainUrl = mainUrl; + httpThreadData->_dirUrl = dirUrl; + httpThreadData->_contentType = contentType; + httpThreadData->_postData = postData; + httpThreadData->_isPost = isPost; + httpThreadData->setCallback(callback); + HANDLE myHandle = CreateThread(0, 0, httpThread, httpThreadData, 0, &myThreadID); + if (myHandle) { + CloseHandle(myHandle); + return TRUE; + } + return FALSE; +} + HWND LauncherUtils::executeOnForeground(const CString& path, const CString& params) { SHELLEXECUTEINFO info; info.cbSize = sizeof(SHELLEXECUTEINFO); diff --git a/launchers/win32/LauncherUtils.h b/launchers/win32/LauncherUtils.h index 3e07d2af05..32cd5031b4 100644 --- a/launchers/win32/LauncherUtils.h +++ b/launchers/win32/LauncherUtils.h @@ -55,15 +55,15 @@ public: ULONG ulStatusCode, LPCWSTR szStatusText) { float progress = (float)ulProgress / ulProgressMax; if (!isnan(progress)) { - onProgressCallback(progress); + _onProgressCallback(progress); } return S_OK; } void setProgressCallback(std::function fn) { - onProgressCallback = std::bind(fn, std::placeholders::_1); + _onProgressCallback = std::bind(fn, std::placeholders::_1); } private: - std::function onProgressCallback; + std::function _onProgressCallback; }; enum ResponseError { @@ -82,14 +82,14 @@ public: int _type; CString _url; CString _file; - std::function callback; - std::function progressCallback; + std::function _callback; + std::function _progressCallback; // function(type, errorType) void setCallback(std::function fn) { - callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); + _callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); } void setProgressCallback(std::function fn) { - progressCallback = std::bind(fn, std::placeholders::_1); + _progressCallback = std::bind(fn, std::placeholders::_1); } }; @@ -98,23 +98,36 @@ public: std::string _zipFile; std::string _path; // function(type, size) - std::function callback; - std::function progressCallback; + std::function _callback; + std::function _progressCallback; void setCallback(std::function fn) { - callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); + _callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); } void setProgressCallback(std::function fn) { - progressCallback = std::bind(fn, std::placeholders::_1); + _progressCallback = std::bind(fn, std::placeholders::_1); } }; struct DeleteThreadData { CString _dirPath; - std::function callback; - std::function progressCallback; - void setCallback(std::function fn) { callback = std::bind(fn, std::placeholders::_1); } + std::function _callback; + std::function _progressCallback; + void setCallback(std::function fn) { _callback = std::bind(fn, std::placeholders::_1); } void setProgressCallback(std::function fn) { - progressCallback = std::bind(fn, std::placeholders::_1); + _progressCallback = std::bind(fn, std::placeholders::_1); + } + }; + + struct HttpThreadData { + CString _callerName; + CString _mainUrl; + CString _dirUrl; + CString _contentType; + CStringA _postData; + bool _isPost { false }; + std::function _callback; + void setCallback(std::function fn) { + _callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2); } }; @@ -150,6 +163,9 @@ public: std::function callback, std::function progressCallback); static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function callback); + static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl, + const CString& contentType, CStringA& postData, bool isPost, + std::function callback); static CString urlEncodeString(const CString& url); static HWND executeOnForeground(const CString& path, const CString& params); @@ -159,4 +175,5 @@ private: static DWORD WINAPI unzipThread(LPVOID lpParameter); static DWORD WINAPI downloadThread(LPVOID lpParameter); static DWORD WINAPI deleteDirectoryThread(LPVOID lpParameter); -}; \ No newline at end of file + static DWORD WINAPI httpThread(LPVOID lpParameter); +}; From bc5f8ad77543f7ea31e447f2ea22986db5814ac1 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Thu, 11 Jul 2019 11:13:58 -0700 Subject: [PATCH 2/2] Remove unneeded response --- launchers/win32/LauncherManager.cpp | 5 ++--- launchers/win32/LauncherManager.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/launchers/win32/LauncherManager.cpp b/launchers/win32/LauncherManager.cpp index 81b76d13e7..294c9742f5 100644 --- a/launchers/win32/LauncherManager.cpp +++ b/launchers/win32/LauncherManager.cpp @@ -24,8 +24,7 @@ LauncherManager::~LauncherManager() { void LauncherManager::init() { initLog(); addToLog(_T("Getting most recent build")); - CString response; - getMostRecentBuild(_latestApplicationURL, _latestVersion, response); + getMostRecentBuild(_latestApplicationURL, _latestVersion); } BOOL LauncherManager::initLog() { @@ -360,7 +359,7 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString return LauncherUtils::ResponseError::ParsingJSON; } -void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response) { +void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) { CString contentTypeJson = L"content-type:application/json"; std::function httpCallback = [&](CString response, int err) { LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err); diff --git a/launchers/win32/LauncherManager.h b/launchers/win32/LauncherManager.h index e97ae6efcc..6ebebc5fc3 100644 --- a/launchers/win32/LauncherManager.h +++ b/launchers/win32/LauncherManager.h @@ -67,7 +67,7 @@ public: BOOL isApplicationInstalled(CString& version, CString& domain, CString& content, bool& loggedIn); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); - void getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response); + void getMostRecentBuild(CString& urlOut, CString& versionOut); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, CString& content, bool& loggedIn);