Merge pull request #15916 from luiscuenca/WLAsyncThunder

BUGZ-989: Get recent builds asynchronously while the windows launcher is showing the splash screen
This commit is contained in:
Shannon Romano 2019-07-15 08:36:33 -07:00 committed by GitHub
commit 8ad1202bcb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 135 additions and 84 deletions

View file

@ -672,7 +672,7 @@ void CLauncherDlg::OnTimer(UINT_PTR nIDEvent) {
theApp._manager.addToLog(_T("Start splash screen")); theApp._manager.addToLog(_T("Start splash screen"));
setDrawDialog(DrawStep::DrawLogo); setDrawDialog(DrawStep::DrawLogo);
} }
} else if (_splashStep > 100) { } else if (_splashStep > 100 && !theApp._manager.needsToWait()) {
_showSplash = false; _showSplash = false;
if (theApp._manager.shouldShutDown()) { if (theApp._manager.shouldShutDown()) {
if (_applicationWND != NULL) { if (_applicationWND != NULL) {

View file

@ -24,35 +24,7 @@ LauncherManager::~LauncherManager() {
void LauncherManager::init() { void LauncherManager::init() {
initLog(); initLog();
addToLog(_T("Getting most recent build")); addToLog(_T("Getting most recent build"));
CString response; getMostRecentBuild(_latestApplicationURL, _latestVersion);
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);
}
} }
BOOL LauncherManager::initLog() { BOOL LauncherManager::initLog() {
@ -387,39 +359,71 @@ LauncherUtils::ResponseError LauncherManager::readOrganizationJSON(const CString
return LauncherUtils::ResponseError::ParsingJSON; return LauncherUtils::ResponseError::ParsingJSON;
} }
LauncherUtils::ResponseError LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut, void LauncherManager::getMostRecentBuild(CString& urlOut, CString& versionOut) {
CString& response) {
CString contentTypeJson = L"content-type:application/json"; CString contentTypeJson = L"content-type:application/json";
LauncherUtils::ResponseError error = LauncherUtils::makeHTTPCall(L"HQ Launcher", std::function<void(CString, int)> httpCallback = [&](CString response, int err) {
L"thunder.highfidelity.com", LauncherUtils::ResponseError error = LauncherUtils::ResponseError(err);
L"/builds/api/tags/latest?format=json", if (error == LauncherUtils::ResponseError::NoError) {
contentTypeJson, CStringA(), Json::Value json;
response, false); error = LauncherUtils::ResponseError::ParsingJSON;
if (error != LauncherUtils::ResponseError::NoError) { if (LauncherUtils::parseJSON(response, json)) {
return error; int count = json["count"].isInt() ? json["count"].asInt() : 0;
} if (count > 0 && json["results"].isArray()) {
Json::Value json; for (int i = 0; i < count; i++) {
if (LauncherUtils::parseJSON(response, json)) { if (json["results"][i].isObject()) {
int count = json["count"].isInt() ? json["count"].asInt() : 0; Json::Value result = json["results"][i];
if (count > 0 && json["results"].isArray()) { if (result["latest_version"].isInt()) {
for (int i = 0; i < count; i++) { std::string version = std::to_string(result["latest_version"].asInt());
if (json["results"][i].isObject()) { versionOut = CString(version.c_str());
Json::Value result = json["results"][i]; }
if (result["latest_version"].isInt()) { if (result["installers"].isObject() &&
std::string version = std::to_string(result["latest_version"].asInt()); result["installers"]["windows"].isObject() &&
versionOut = CString(version.c_str()); result["installers"]["windows"]["zip_url"].isString()) {
} urlOut = result["installers"]["windows"]["zip_url"].asCString();
if (result["installers"].isObject() && error = LauncherUtils::ResponseError::NoError;
result["installers"]["windows"].isObject() && }
result["installers"]["windows"]["zip_url"].isString()) { }
urlOut = result["installers"]["windows"]["zip_url"].asCString();
return 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, LauncherUtils::ResponseError LauncherManager::getAccessTokenForCredentials(const CString& username,
@ -603,12 +607,10 @@ BOOL LauncherManager::downloadFile(ProcessType type, const CString& url, CString
std::function<void(int, bool)> onDownloadFinished = [&](int type, bool error) { std::function<void(int, bool)> onDownloadFinished = [&](int type, bool error) {
if (!error) { if (!error) {
onFileDownloaded((ProcessType)type); onFileDownloaded((ProcessType)type);
} } else {
else {
if (type == ProcessType::DownloadApplication) { if (type == ProcessType::DownloadApplication) {
addToLog(_T("Error downloading content.")); addToLog(_T("Error downloading content."));
} } else {
else {
addToLog(_T("Error downloading application.")); addToLog(_T("Error downloading application."));
} }
_hasFailed = true; _hasFailed = true;

View file

@ -67,7 +67,7 @@ public:
BOOL isApplicationInstalled(CString& version, CString& domain, BOOL isApplicationInstalled(CString& version, CString& domain,
CString& content, bool& loggedIn); CString& content, bool& loggedIn);
LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password); LauncherUtils::ResponseError getAccessTokenForCredentials(const CString& username, const CString& password);
LauncherUtils::ResponseError getMostRecentBuild(CString& urlOut, CString& versionOut, CString& response); void getMostRecentBuild(CString& urlOut, CString& versionOut);
LauncherUtils::ResponseError readOrganizationJSON(const CString& hash); LauncherUtils::ResponseError readOrganizationJSON(const CString& hash);
LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain, LauncherUtils::ResponseError readConfigJSON(CString& version, CString& domain,
CString& content, bool& loggedIn); CString& content, bool& loggedIn);
@ -90,12 +90,13 @@ public:
BOOL needsUpdate() { return _shouldUpdate; } BOOL needsUpdate() { return _shouldUpdate; }
BOOL needsUninstall() { return _shouldUninstall; } BOOL needsUninstall() { return _shouldUninstall; }
BOOL needsInstall() { return _shouldInstall; } BOOL needsInstall() { return _shouldInstall; }
BOOL needsToWait() { return _shouldWait; }
void setDisplayName(const CString& displayName) { _displayName = displayName; } void setDisplayName(const CString& displayName) { _displayName = displayName; }
bool isLoggedIn() { return _loggedIn; } bool isLoggedIn() { return _loggedIn; }
bool hasFailed() { return _hasFailed; } bool hasFailed() { return _hasFailed; }
void setFailed(bool hasFailed) { _hasFailed = hasFailed; } void setFailed(bool hasFailed) { _hasFailed = hasFailed; }
const CString& getLatestInterfaceURL() const { return _latestApplicationURL; } 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 downloadFile(ProcessType type, const CString& url, CString& localPath);
BOOL downloadContent(); BOOL downloadContent();
@ -110,6 +111,7 @@ public:
private: private:
ProcessType _currentProcess { ProcessType::DownloadApplication }; ProcessType _currentProcess { ProcessType::DownloadApplication };
void onMostRecentBuildReceived(const CString& response, LauncherUtils::ResponseError error);
CString _latestApplicationURL; CString _latestApplicationURL;
CString _latestVersion; CString _latestVersion;
CString _contentURL; CString _contentURL;
@ -126,6 +128,7 @@ private:
BOOL _shouldInstall { FALSE }; BOOL _shouldInstall { FALSE };
BOOL _shouldShutdown { FALSE }; BOOL _shouldShutdown { FALSE };
BOOL _shouldLaunch { FALSE }; BOOL _shouldLaunch { FALSE };
BOOL _shouldWait { TRUE };
float _progress { 0.0f }; float _progress { 0.0f };
CStdioFile _logFile; CStdioFile _logFile;
}; };

View file

@ -470,9 +470,9 @@ BOOL LauncherUtils::hMac256(const CString& cmessage, const char* keystr, CString
DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) { DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
UnzipThreadData& data = *((UnzipThreadData*)lpParameter); UnzipThreadData& data = *((UnzipThreadData*)lpParameter);
uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>(), data.progressCallback); uint64_t size = LauncherUtils::extractZip(data._zipFile, data._path, std::vector<std::string>(), data._progressCallback);
int mb_size = (int)(size * 0.001f); int mb_size = (int)(size * 0.001f);
data.callback(data._type, mb_size); data._callback(data._type, mb_size);
delete &data; delete &data;
return 0; return 0;
} }
@ -480,17 +480,26 @@ DWORD WINAPI LauncherUtils::unzipThread(LPVOID lpParameter) {
DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) { DWORD WINAPI LauncherUtils::downloadThread(LPVOID lpParameter) {
DownloadThreadData& data = *((DownloadThreadData*)lpParameter); DownloadThreadData& data = *((DownloadThreadData*)lpParameter);
ProgressCallback progressCallback; ProgressCallback progressCallback;
progressCallback.setProgressCallback(data.progressCallback); progressCallback.setProgressCallback(data._progressCallback);
auto hr = URLDownloadToFile(0, data._url, data._file, 0, auto hr = URLDownloadToFile(0, data._url, data._file, 0,
static_cast<LPBINDSTATUSCALLBACK>(&progressCallback)); static_cast<LPBINDSTATUSCALLBACK>(&progressCallback));
data.callback(data._type, hr != S_OK); data._callback(data._type, hr != S_OK);
return 0; return 0;
} }
DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) { DWORD WINAPI LauncherUtils::deleteDirectoryThread(LPVOID lpParameter) {
DeleteThreadData& data = *((DeleteThreadData*)lpParameter); DeleteThreadData& data = *((DeleteThreadData*)lpParameter);
BOOL success = LauncherUtils::deleteFileOrDirectory(data._dirPath); 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; return 0;
} }
@ -543,6 +552,26 @@ BOOL LauncherUtils::deleteDirectoryOnThread(const CString& dirPath, std::functio
return FALSE; return FALSE;
} }
BOOL LauncherUtils::httpCallOnThread(const CString& callerName, 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->_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) { HWND LauncherUtils::executeOnForeground(const CString& path, const CString& params) {
SHELLEXECUTEINFO info; SHELLEXECUTEINFO info;
info.cbSize = sizeof(SHELLEXECUTEINFO); info.cbSize = sizeof(SHELLEXECUTEINFO);

View file

@ -55,15 +55,15 @@ public:
ULONG ulStatusCode, LPCWSTR szStatusText) { ULONG ulStatusCode, LPCWSTR szStatusText) {
float progress = (float)ulProgress / ulProgressMax; float progress = (float)ulProgress / ulProgressMax;
if (!isnan(progress)) { if (!isnan(progress)) {
onProgressCallback(progress); _onProgressCallback(progress);
} }
return S_OK; return S_OK;
} }
void setProgressCallback(std::function<void(float)> fn) { void setProgressCallback(std::function<void(float)> fn) {
onProgressCallback = std::bind(fn, std::placeholders::_1); _onProgressCallback = std::bind(fn, std::placeholders::_1);
} }
private: private:
std::function<void(float)> onProgressCallback; std::function<void(float)> _onProgressCallback;
}; };
enum ResponseError { enum ResponseError {
@ -82,14 +82,14 @@ public:
int _type; int _type;
CString _url; CString _url;
CString _file; CString _file;
std::function<void(int, bool)> callback; std::function<void(int, bool)> _callback;
std::function<void(float)> progressCallback; std::function<void(float)> _progressCallback;
// function(type, errorType) // function(type, errorType)
void setCallback(std::function<void(int, bool)> fn) { void setCallback(std::function<void(int, bool)> 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<void(float)> fn) { void setProgressCallback(std::function<void(float)> 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 _zipFile;
std::string _path; std::string _path;
// function(type, size) // function(type, size)
std::function<void(int, int)> callback; std::function<void(int, int)> _callback;
std::function<void(float)> progressCallback; std::function<void(float)> _progressCallback;
void setCallback(std::function<void(int, int)> fn) { void setCallback(std::function<void(int, int)> 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<void(float)> fn) { void setProgressCallback(std::function<void(float)> fn) {
progressCallback = std::bind(fn, std::placeholders::_1); _progressCallback = std::bind(fn, std::placeholders::_1);
} }
}; };
struct DeleteThreadData { struct DeleteThreadData {
CString _dirPath; CString _dirPath;
std::function<void(bool)> callback; std::function<void(bool)> _callback;
std::function<void(float)> progressCallback; std::function<void(float)> _progressCallback;
void setCallback(std::function<void(bool)> fn) { callback = std::bind(fn, std::placeholders::_1); } void setCallback(std::function<void(bool)> fn) { _callback = std::bind(fn, std::placeholders::_1); }
void setProgressCallback(std::function<void(float)> fn) { void setProgressCallback(std::function<void(float)> 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<void(CString, int)> _callback;
void setCallback(std::function<void(CString, int)> fn) {
_callback = std::bind(fn, std::placeholders::_1, std::placeholders::_2);
} }
}; };
@ -150,6 +163,9 @@ public:
std::function<void(int, bool)> callback, std::function<void(int, bool)> callback,
std::function<void(float)> progressCallback); std::function<void(float)> progressCallback);
static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback); static BOOL deleteDirectoryOnThread(const CString& dirPath, std::function<void(bool)> callback);
static BOOL httpCallOnThread(const CString& callerName, const CString& mainUrl, const CString& dirUrl,
const CString& contentType, CStringA& postData, bool isPost,
std::function<void(CString, int)> callback);
static CString urlEncodeString(const CString& url); static CString urlEncodeString(const CString& url);
static HWND executeOnForeground(const CString& path, const CString& params); static HWND executeOnForeground(const CString& path, const CString& params);
@ -159,4 +175,5 @@ private:
static DWORD WINAPI unzipThread(LPVOID lpParameter); static DWORD WINAPI unzipThread(LPVOID lpParameter);
static DWORD WINAPI downloadThread(LPVOID lpParameter); static DWORD WINAPI downloadThread(LPVOID lpParameter);
static DWORD WINAPI deleteDirectoryThread(LPVOID lpParameter); static DWORD WINAPI deleteDirectoryThread(LPVOID lpParameter);
}; static DWORD WINAPI httpThread(LPVOID lpParameter);
};