mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
mac auto-updater
This commit is contained in:
parent
7d6404b40b
commit
09b9b1e10c
7 changed files with 175 additions and 3 deletions
|
@ -3,6 +3,11 @@
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
void launchClient(const QString& homePath, const QString& defaultScriptOverride, const QString& displayName,
|
void launchClient(const QString& homePath, const QString& defaultScriptOverride, const QString& displayName,
|
||||||
|
@ -45,5 +50,24 @@ void launchClient(const QString& homePath, const QString& defaultScriptOverride,
|
||||||
CloseHandle(pi.hThread);
|
CloseHandle(pi.hThread);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void swapLaunchers(const QString& oldLauncherPath, const QString& newLauncherPath) {
|
||||||
|
if (!(QFileInfo::exists(oldLauncherPath) && QFileInfo::exists(newLauncherPath))) {
|
||||||
|
qDebug() << "old launcher: " << oldLauncherPath << "new launcher: " << newLauncherPath << " file does not exist";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = false;
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
success = replaceDirectory(oldLauncherPath, newLauncherPath);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
qDebug() << "succeessfully replaced";
|
||||||
|
} else {
|
||||||
|
qDebug() << "failed";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,13 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
void launchClient(const QString& clientPath, const QString& homePath, const QString& defaultScriptOverride,
|
void launchClient(const QString& clientPath, const QString& homePath, const QString& defaultScriptOverride,
|
||||||
const QString& displayName, const QString& contentCachePath, const QString& loginResponseToken = QString());
|
const QString& displayName, const QString& contentCachePath, const QString& loginResponseToken = QString());
|
||||||
|
|
||||||
|
|
||||||
|
void launchAutoUpdater(const QString& autoUpdaterPath);
|
||||||
|
void swapLaunchers(const QString& oldLauncherPath = QString(), const QString& newLauncherPath = QString());
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
bool replaceDirectory(const QString& orginalDirectory, const QString& newDirectory);
|
||||||
|
#endif
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
Launcher::Launcher(int& argc, char**argv) : QGuiApplication(argc, argv) {
|
Launcher::Launcher(int& argc, char**argv) : QGuiApplication(argc, argv) {
|
||||||
QString resourceBinaryLocation = QGuiApplication::applicationDirPath() + "/resources.rcc";
|
QString resourceBinaryLocation = QGuiApplication::applicationDirPath() + "/resources.rcc";
|
||||||
|
qDebug() << "resources.rcc path: " << resourceBinaryLocation;
|
||||||
QResource::registerResource(resourceBinaryLocation);
|
QResource::registerResource(resourceBinaryLocation);
|
||||||
_launcherState = std::make_shared<LauncherState>();
|
_launcherState = std::make_shared<LauncherState>();
|
||||||
//_launcherState->setUIState(LauncherState::SPLASH_SCREEN);
|
//_launcherState->setUIState(LauncherState::SPLASH_SCREEN);
|
||||||
|
|
|
@ -174,8 +174,24 @@ void LauncherState::receivedBuildsReply() {
|
||||||
#endif
|
#endif
|
||||||
_latestBuilds.builds.push_back(build);
|
_latestBuilds.builds.push_back(build);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto launcherResults = root["launcher"].toObject();
|
||||||
|
|
||||||
|
Build launcherBuild;
|
||||||
|
launcherBuild.latestVersion = launcherResults["version"].toInt();
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
launcherBuild.installerZipURL = launcherResults["windows"].toObject()["url"].toString();
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
launcherBuild.installerZipURL = launcherResults["mac"].toObject()["url"].toString();
|
||||||
|
#else
|
||||||
|
#error "Launcher is only supported on Windows and Mac OS"
|
||||||
|
#endif
|
||||||
|
_latestBuilds.launcherBuild = launcherBuild;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//downloadLauncher();
|
||||||
setApplicationState(ApplicationState::WaitingForLogin);
|
setApplicationState(ApplicationState::WaitingForLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +306,11 @@ void LauncherState::downloadClient() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LauncherState::launcherDownloadComplete() {
|
||||||
|
_launcherZipFile.close();
|
||||||
|
installLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
void LauncherState::clientDownloadComplete() {
|
void LauncherState::clientDownloadComplete() {
|
||||||
ASSERT_STATE(ApplicationState::DownloadingClient);
|
ASSERT_STATE(ApplicationState::DownloadingClient);
|
||||||
|
|
||||||
|
@ -330,6 +351,61 @@ void LauncherState::installClient() {
|
||||||
//launchClient();
|
//launchClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LauncherState::downloadLauncher() {
|
||||||
|
auto request = new QNetworkRequest(QUrl(_latestBuilds.launcherBuild.installerZipURL));
|
||||||
|
auto reply = _networkAccessManager.get(*request);
|
||||||
|
|
||||||
|
_launcherZipFile.setFileName(_launcherDirectory.absoluteFilePath("launcher.zip"));
|
||||||
|
|
||||||
|
qDebug() << "opening " << _launcherZipFile.fileName();
|
||||||
|
|
||||||
|
if (!_launcherZipFile.open(QIODevice::WriteOnly)) {
|
||||||
|
setApplicationState(ApplicationState::UnexpectedError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(reply, &QNetworkReply::finished, this, &LauncherState::launcherDownloadComplete);
|
||||||
|
connect(reply, &QNetworkReply::readyRead, this, [this, reply]() {
|
||||||
|
char buf[4096];
|
||||||
|
while (reply->bytesAvailable() > 0) {
|
||||||
|
qint64 size;
|
||||||
|
size = reply->read(buf, (qint64)sizeof(buf));
|
||||||
|
if (size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_launcherZipFile.write(buf, size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void LauncherState::installLauncher() {
|
||||||
|
auto installDir = _launcherDirectory.absoluteFilePath("launcher_install");
|
||||||
|
_launcherDirectory.mkpath("launcher_install");
|
||||||
|
|
||||||
|
qDebug() << "Uzipping " << _launcherZipFile.fileName() << " to " << installDir;
|
||||||
|
|
||||||
|
auto unzipper = new Unzipper(_launcherZipFile.fileName(), QDir(installDir));
|
||||||
|
unzipper->setAutoDelete(true);
|
||||||
|
connect(unzipper, &Unzipper::finished, this, [this](bool error, QString errorMessage) {
|
||||||
|
if (error) {
|
||||||
|
qDebug() << "Unzipper finished with error: " << errorMessage;
|
||||||
|
} else {
|
||||||
|
qDebug() << "Unzipper finished without error";
|
||||||
|
|
||||||
|
QDir installDirectory = _launcherDirectory.filePath("launcher_install");
|
||||||
|
QString launcherPath;
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
launcherPath = installDirectory.absoluteFilePath("HQ Launcher.exe");
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
launcherPath = installDirectory.absoluteFilePath("HQ Launcher.app");
|
||||||
|
#endif
|
||||||
|
//::launchAutoUpdater(launcherPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QThreadPool::globalInstance()->start(unzipper);
|
||||||
|
}
|
||||||
|
|
||||||
void LauncherState::downloadContentCache() {
|
void LauncherState::downloadContentCache() {
|
||||||
ASSERT_STATE(ApplicationState::InstallingClient);
|
ASSERT_STATE(ApplicationState::InstallingClient);
|
||||||
|
|
||||||
|
@ -431,7 +507,6 @@ void LauncherState::launchClient() {
|
||||||
defaultScriptsPath = installDirectory.filePath("interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js");
|
defaultScriptsPath = installDirectory.filePath("interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
qDebug() << "------> " << defaultScriptsPath;
|
|
||||||
QString displayName = "fixMe";
|
QString displayName = "fixMe";
|
||||||
QString contentCachePath = _launcherDirectory.filePath("cache");
|
QString contentCachePath = _launcherDirectory.filePath("cache");
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct LatestBuilds {
|
||||||
|
|
||||||
QString defaultTag;
|
QString defaultTag;
|
||||||
std::vector<Build> builds;
|
std::vector<Build> builds;
|
||||||
|
Build launcherBuild;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LoginResponse {
|
struct LoginResponse {
|
||||||
|
@ -59,9 +60,11 @@ public:
|
||||||
RequestingLogin,
|
RequestingLogin,
|
||||||
|
|
||||||
DownloadingClient,
|
DownloadingClient,
|
||||||
|
DownloadingLauncher,
|
||||||
DownloadingContentCache,
|
DownloadingContentCache,
|
||||||
|
|
||||||
InstallingClient,
|
InstallingClient,
|
||||||
|
InstallingLauncher,
|
||||||
InstallingContentCache,
|
InstallingContentCache,
|
||||||
|
|
||||||
LaunchingHighFidelity
|
LaunchingHighFidelity
|
||||||
|
@ -101,6 +104,10 @@ public:
|
||||||
Q_INVOKABLE void login(QString username, QString password);
|
Q_INVOKABLE void login(QString username, QString password);
|
||||||
Q_INVOKABLE void receivedLoginReply();
|
Q_INVOKABLE void receivedLoginReply();
|
||||||
|
|
||||||
|
// Launcher
|
||||||
|
void downloadLauncher();
|
||||||
|
void installLauncher();
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
void downloadClient();
|
void downloadClient();
|
||||||
void installClient();
|
void installClient();
|
||||||
|
@ -123,6 +130,7 @@ signals:
|
||||||
private slots:
|
private slots:
|
||||||
void clientDownloadComplete();
|
void clientDownloadComplete();
|
||||||
void contentCacheDownloadComplete();
|
void contentCacheDownloadComplete();
|
||||||
|
void launcherDownloadComplete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool shouldDownloadContentCache() const;
|
bool shouldDownloadContentCache() const;
|
||||||
|
@ -140,6 +148,7 @@ private:
|
||||||
QString _contentCacheURL{ "https://orgs.highfidelity.com/content-cache/content_cache_small-only_data8.zip" }; // QString::null }; // If null, there is no content cache to download
|
QString _contentCacheURL{ "https://orgs.highfidelity.com/content-cache/content_cache_small-only_data8.zip" }; // QString::null }; // If null, there is no content cache to download
|
||||||
QString _loginTokenResponse;
|
QString _loginTokenResponse;
|
||||||
QFile _clientZipFile;
|
QFile _clientZipFile;
|
||||||
|
QFile _launcherZipFile;
|
||||||
QFile _contentZipFile;
|
QFile _contentZipFile;
|
||||||
|
|
||||||
float _downloadProgress { 0 };
|
float _downloadProgress { 0 };
|
||||||
|
|
|
@ -40,3 +40,33 @@ void launchClient(const QString& clientPath, const QString& homePath, const QStr
|
||||||
[task replaceThisProcess];
|
[task replaceThisProcess];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void launchAutoUpdater(const QString& autoUpdaterPath) {
|
||||||
|
NSTask* task = [[NSTask alloc] init];
|
||||||
|
task.launchPath = [autoUpdaterPath.toNSString() stringByAppendingString:@"/Contents/Resources/updater"];
|
||||||
|
task.arguments = @[[[NSBundle mainBundle] bundlePath], autoUpdaterPath.toNSString()];
|
||||||
|
[task launch];
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@interface UpdaterHelper : NSObject
|
||||||
|
+(NSURL*) NSStringToNSURL: (NSString*) path;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation UpdaterHelper
|
||||||
|
+(NSURL*) NSStringToNSURL: (NSString*) path
|
||||||
|
{
|
||||||
|
return [NSURL URLWithString: [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]] relativeToURL: [NSURL URLWithString:@"file://"]];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
bool replaceDirectory(const QString& orginalDirectory, const QString& newDirectory) {
|
||||||
|
NSFileManager* fileManager = [NSFileManager defaultManager];
|
||||||
|
NSURL* destinationUrl = [UpdaterHelper NSStringToNSURL:newDirectory.toNSString()];
|
||||||
|
return (bool) [fileManager replaceItemAtURL:[UpdaterHelper NSStringToNSURL:orginalDirectory.toNSString()] withItemAtURL:[UpdaterHelper NSStringToNSURL:newDirectory.toNSString()]
|
||||||
|
backupItemName:nil options:NSFileManagerItemReplacementUsingNewMetadataOnly resultingItemURL:&destinationUrl error:nil];
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
|
|
||||||
#include "LauncherWindow.h"
|
#include "LauncherWindow.h"
|
||||||
#include "Launcher.h"
|
#include "Launcher.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include "Helper.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin);
|
||||||
|
@ -14,7 +16,29 @@ Q_IMPORT_PLUGIN(QtQuick2Plugin);
|
||||||
Q_IMPORT_PLUGIN(QtQuickControls2Plugin);
|
Q_IMPORT_PLUGIN(QtQuickControls2Plugin);
|
||||||
Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin);
|
Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool hasSuffix(const std::string path, const std::string suffix) {
|
||||||
|
if (path.substr(path.find_last_of(".") + 1) == suffix) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
#ifdef Q_OS_MAC
|
||||||
|
// auto updater
|
||||||
|
if (argc == 3) {
|
||||||
|
if (hasSuffix(argv[1], "app") && hasSuffix(argv[2], "app")) {
|
||||||
|
std::cout << "swapping launcher \n";
|
||||||
|
swapLaunchers(argv[1], argv[2]);
|
||||||
|
} else {
|
||||||
|
std::cout << "not swapping launcher \n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
QString name { "High Fidelity" };
|
QString name { "High Fidelity" };
|
||||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
QCoreApplication::setOrganizationName(name);
|
QCoreApplication::setOrganizationName(name);
|
||||||
|
|
Loading…
Reference in a new issue