mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-07 12:04:25 +02:00
Add signup to qt launcher, and cleanup
This commit is contained in:
parent
6db88dae3c
commit
e81deff4e9
15 changed files with 575 additions and 153 deletions
|
@ -127,8 +127,14 @@ set(src_files
|
|||
src/LauncherState.cpp
|
||||
src/LauncherWindow.h
|
||||
src/LauncherWindow.cpp
|
||||
src/PathUtils.cpp
|
||||
src/LoginRequest.h
|
||||
src/LoginRequest.cpp
|
||||
src/SignupRequest.h
|
||||
src/SignupRequest.cpp
|
||||
src/UserSettingsRequest.h
|
||||
src/UserSettingsRequest.cpp
|
||||
src/PathUtils.h
|
||||
src/PathUtils.cpp
|
||||
src/Unzipper.h
|
||||
src/Unzipper.cpp
|
||||
src/Helper.h
|
||||
|
@ -159,7 +165,7 @@ set(TARGET_NAME ${PROJECT_NAME})
|
|||
|
||||
set_packaging_parameters()
|
||||
if (WIN32)
|
||||
add_executable(${PROJECT_NAME} ${src_files} build/resources.qrc)
|
||||
add_executable(${PROJECT_NAME} ${src_files} ${CMAKE_CURRENT_BINARY_DIR}/resources.qrc)
|
||||
elseif (APPLE)
|
||||
set_target_properties(${this_target} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
|
||||
|
|
|
@ -47,7 +47,7 @@ Item {
|
|||
font.family: "Graphik"
|
||||
font.pixelSize: 14
|
||||
color: "#C4C4C4"
|
||||
text: "Use the email address that you regisetered with."
|
||||
text: "Use the email address that you regisetered with. " + LauncherState.lastSignupError
|
||||
anchors {
|
||||
left: root.left
|
||||
leftMargin: root.marginLeft
|
||||
|
@ -57,7 +57,7 @@ Item {
|
|||
}
|
||||
|
||||
HFTextField {
|
||||
id: organization
|
||||
id: email
|
||||
width: 430
|
||||
height: 50
|
||||
font.family: "Graphik"
|
||||
|
@ -83,7 +83,7 @@ Item {
|
|||
color: "#7e8c81"
|
||||
seperatorColor: Qt.rgba(1, 1, 1, 0.3)
|
||||
anchors {
|
||||
top: organization.bottom
|
||||
top: email.bottom
|
||||
left: root.left
|
||||
leftMargin: root.marginLeft
|
||||
topMargin: 18
|
||||
|
@ -157,7 +157,7 @@ Item {
|
|||
topMargin: 21
|
||||
}
|
||||
|
||||
onClicked: LauncherState.login(username.text, passwordField.text)
|
||||
onClicked: LauncherState.signup(email.text, username.text, passwordField.text, displayName.text)
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,7 +181,7 @@ Item {
|
|||
|
||||
onClicked: {
|
||||
console.log("clicked");
|
||||
root.parent.source = PathUtils.resourcePath("qml/Login.qml");
|
||||
LauncherState.gotoLogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,7 +109,6 @@ Item {
|
|||
placeholderText: "Display name"
|
||||
color: "#7E8C81"
|
||||
seperatorColor: Qt.rgba(1, 1, 1, 0.3)
|
||||
echoMode: TextInput.Password
|
||||
anchors {
|
||||
top: displayText.bottom
|
||||
horizontalCenter: instruction.horizontalCenter
|
||||
|
@ -132,7 +131,7 @@ Item {
|
|||
topMargin: 25
|
||||
}
|
||||
|
||||
onClicked: LauncherState.login(username.text, password.text)
|
||||
onClicked: LauncherState.login(username.text, password.text, displayName.text)
|
||||
}
|
||||
|
||||
Text {
|
||||
|
@ -155,7 +154,7 @@ Item {
|
|||
|
||||
onClicked: {
|
||||
console.log("clicked");
|
||||
root.parent.source = PathUtils.resourcePath("qml/Login.qml");
|
||||
LauncherState.gotoSignup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,3 +25,47 @@ void swapLaunchers(const QString& oldLauncherPath, const QString& newLauncherPat
|
|||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
QString getHTTPUserAgent() {
|
||||
#if defined(Q_OS_WIN)
|
||||
return "HQLauncher/fixme (Windows)";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return "HQLauncher/fixme (MacOS)";
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
}
|
||||
|
||||
const QString& getInterfaceSharedMemoryName() {
|
||||
static const QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
|
||||
return applicationName;
|
||||
}
|
||||
|
||||
//#ifdef Q_OS_WIN
|
||||
//#include <Windows.h>
|
||||
//#include <tlhelp32.h>
|
||||
//#include <wincrypt.h>
|
||||
//#include <tlhelp32.h>
|
||||
//#include <strsafe.h>
|
||||
//#include <winhttp.h>
|
||||
//
|
||||
//bool isProcessRunning(const wchar_t *processName, int& processID) {
|
||||
// bool exists = false;
|
||||
// PROCESSENTRY32 entry;
|
||||
// entry.dwSize = sizeof(PROCESSENTRY32);
|
||||
//
|
||||
// HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
|
||||
//
|
||||
// if (Process32First(snapshot, &entry)) {
|
||||
// while (Process32Next(snapshot, &entry)) {
|
||||
// if (!_wcsicmp(entry.szExeFile, processName)) {
|
||||
// exists = true;
|
||||
// processID = entry.th32ProcessID;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// CloseHandle(snapshot);
|
||||
// return exists;
|
||||
//}
|
||||
//#endif
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
//#define USE_STAGING
|
||||
|
||||
#ifdef USE_STAGING
|
||||
const QString METAVERSE_API_DOMAIN{ "https://staging.highfidelity.com" };
|
||||
#else
|
||||
const QString METAVERSE_API_DOMAIN{ "https://metaverse.highfidelity.com" };
|
||||
#endif
|
||||
|
||||
void launchClient(const QString& clientPath, const QString& homePath, const QString& defaultScriptOverride,
|
||||
const QString& displayName, const QString& contentCachePath, QString loginResponseToken = QString());
|
||||
|
||||
|
@ -11,3 +19,11 @@ void swapLaunchers(const QString& oldLauncherPath = QString(), const QString& ne
|
|||
#ifdef Q_OS_MAC
|
||||
bool replaceDirectory(const QString& orginalDirectory, const QString& newDirectory);
|
||||
#endif
|
||||
|
||||
QString getHTTPUserAgent();
|
||||
|
||||
const QString& getInterfaceSharedMemoryName();
|
||||
|
||||
//#ifdef Q_OS_WIN
|
||||
//bool isProcessRunning(const wchar_t *processName, int& processID) {
|
||||
//#endif
|
||||
|
|
|
@ -9,7 +9,7 @@ void launchClient(const QString& clientPath, const QString& homePath, const QStr
|
|||
// TODO Fix parameters
|
||||
QString params = "--url \"" + homePath + "\""
|
||||
+ " --setBookmark \"hqhome=" + homePath + "\""
|
||||
+ " --defaultScriptsOverride \"" + defaultScriptsPath + "\""
|
||||
+ " --defaultScriptsOverride \"file:///" + defaultScriptsPath + "\""
|
||||
+ " --displayName \"" + displayName + "\""
|
||||
+ " --cache \"" + contentCachePath + "\"";
|
||||
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
#include <qregularexpression.h>
|
||||
|
||||
const QString METAVERSE_API_URL{ "https://metaverse.highfidelity.com" };
|
||||
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
QString LauncherState::getContentCachePath() const {
|
||||
return _launcherDirectory.filePath("cache");
|
||||
|
@ -70,7 +68,7 @@ bool LatestBuilds::getBuild(QString tag, Build* outBuild) {
|
|||
}
|
||||
|
||||
static const std::array<QString, LauncherState::UIState::UI_STATE_NUM> QML_FILE_FOR_UI_STATE =
|
||||
{ { "SplashScreen.qml", "qml/HFBase/CreateAccountBase.qml", "DisplayName.qml",
|
||||
{ { "SplashScreen.qml", "qml/HFBase/CreateAccountBase.qml", "qml/HFBase/LoginBase.qml", "DisplayName.qml",
|
||||
"qml/Download.qml", "qml/DownloadFinished.qml", "qml/HFBase/Error.qml" } };
|
||||
|
||||
void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) {
|
||||
|
@ -82,7 +80,7 @@ void LauncherState::ASSERT_STATE(LauncherState::ApplicationState state) {
|
|||
}
|
||||
}
|
||||
|
||||
void LauncherState::ASSERT_STATE(std::vector<LauncherState::ApplicationState> states) {
|
||||
void LauncherState::ASSERT_STATE(const std::vector<LauncherState::ApplicationState>& states) {
|
||||
for (auto state : states) {
|
||||
if (_applicationState == state) {
|
||||
return;
|
||||
|
@ -120,6 +118,9 @@ LauncherState::UIState LauncherState::getUIState() const {
|
|||
case ApplicationState::WaitingForLogin:
|
||||
case ApplicationState::RequestingLogin:
|
||||
return LOGIN_SCREEN;
|
||||
case ApplicationState::WaitingForSignup:
|
||||
case ApplicationState::RequestingSignup:
|
||||
return SIGNUP_SCREEN;
|
||||
case ApplicationState::DownloadingClient:
|
||||
case ApplicationState::InstallingClient:
|
||||
case ApplicationState::DownloadingContentCache:
|
||||
|
@ -240,33 +241,11 @@ void LauncherState::getCurrentClientVersion() {
|
|||
QProcess client;
|
||||
QEventLoop loop;
|
||||
|
||||
//connect(&client, &QProcess::errorOccurred, &loop, &QEventLoop::exit);
|
||||
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), &loop, &QEventLoop::exit);
|
||||
/*
|
||||
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [&]() {
|
||||
qDebug() << "Finished";
|
||||
});
|
||||
connect(&client, &QProcess::errorOccurred, [&](QProcess::ProcessError err) {
|
||||
qDebug() << "Error occurred" << err << client.error();
|
||||
});
|
||||
connect(&client, &QProcess::started, [&]() {
|
||||
qDebug() << "Started";
|
||||
});
|
||||
connect(&client, &QProcess::stateChanged, [&]() {
|
||||
qDebug() << "State changed " << client.state();
|
||||
});
|
||||
*/
|
||||
connect(&client, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), &loop, &QEventLoop::exit, Qt::QueuedConnection);
|
||||
connect(&client, &QProcess::errorOccurred, &loop, &QEventLoop::exit, Qt::QueuedConnection);
|
||||
|
||||
//qDebug() << "Starting client";
|
||||
client.start(getClientExecutablePath(), { "--version" });
|
||||
//qDebug() << "Started" << client.error();
|
||||
|
||||
if (client.state() != QProcess::NotRunning) {
|
||||
//qDebug() << "Starting loop";
|
||||
loop.exec();
|
||||
} else {
|
||||
qDebug() << "Not waiting for client, there was an error starting it: " << client.error();
|
||||
}
|
||||
loop.exec();
|
||||
|
||||
// TODO Handle errors
|
||||
auto output = client.readAllStandardOutput();
|
||||
|
@ -282,132 +261,140 @@ void LauncherState::getCurrentClientVersion() {
|
|||
}
|
||||
qDebug() << "Current client version is: " << _currentClientVersion;
|
||||
|
||||
setApplicationState(ApplicationState::WaitingForLogin);
|
||||
setApplicationState(ApplicationState::WaitingForSignup);
|
||||
}
|
||||
|
||||
QString getUserAgent() {
|
||||
#if defined(Q_OS_WIN)
|
||||
return "HQLauncher/fixme (Windows)";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
return "HQLauncher/fixme (MacOS)";
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
void LauncherState::gotoSignup() {
|
||||
if (_applicationState == ApplicationState::WaitingForLogin) {
|
||||
setApplicationState(ApplicationState::WaitingForSignup);
|
||||
} else {
|
||||
qDebug() << "Error, can't switch to signup page, current state is: " << _applicationState;
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::login(QString username, QString password) {
|
||||
void LauncherState::gotoLogin() {
|
||||
if (_applicationState == ApplicationState::WaitingForSignup) {
|
||||
setApplicationState(ApplicationState::WaitingForLogin);
|
||||
} else {
|
||||
qDebug() << "Error, can't switch to signup page, current state is: " << _applicationState;
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherState::signup(QString email, QString username, QString password, QString displayName) {
|
||||
ASSERT_STATE(ApplicationState::WaitingForSignup);
|
||||
|
||||
_username = username;
|
||||
_password = password;
|
||||
|
||||
setApplicationState(ApplicationState::RequestingSignup);
|
||||
|
||||
auto signupRequest = new SignupRequest();
|
||||
|
||||
_displayName = displayName;
|
||||
|
||||
{
|
||||
_lastSignupError = SignupRequest::Error::None;
|
||||
emit lastSignupErrorChanged();
|
||||
}
|
||||
|
||||
QObject::connect(signupRequest, &SignupRequest::finished, this, [this, signupRequest] {
|
||||
signupRequest->deleteLater();
|
||||
|
||||
|
||||
_lastSignupError = signupRequest->getError();
|
||||
emit lastSignupErrorChanged();
|
||||
|
||||
if (_lastSignupError != SignupRequest::Error::None) {
|
||||
setApplicationStateError("Failed to sign up");
|
||||
return;
|
||||
}
|
||||
|
||||
setApplicationState(ApplicationState::RequestingLoginAfterSignup);
|
||||
|
||||
// After successfully signing up, attempt to login
|
||||
auto loginRequest = new LoginRequest();
|
||||
|
||||
connect(loginRequest, &LoginRequest::finished, this, [this, loginRequest]() {
|
||||
ASSERT_STATE(ApplicationState::RequestingLoginAfterSignup);
|
||||
|
||||
loginRequest->deleteLater();
|
||||
|
||||
auto err = loginRequest->getError();
|
||||
if (err != LoginRequest::Error::None) {
|
||||
setApplicationStateError("Failed to login");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_loginResponse = loginRequest->getToken();
|
||||
_loginTokenResponse = loginRequest->getRawToken();
|
||||
|
||||
requestSettings();
|
||||
});
|
||||
|
||||
setApplicationState(ApplicationState::RequestingLoginAfterSignup);
|
||||
loginRequest->send(_networkAccessManager, _username, _password);
|
||||
});
|
||||
signupRequest->send(_networkAccessManager, email, username, password);
|
||||
}
|
||||
|
||||
|
||||
void LauncherState::login(QString username, QString password, QString displayName) {
|
||||
ASSERT_STATE(ApplicationState::WaitingForLogin);
|
||||
|
||||
setApplicationState(ApplicationState::RequestingLogin);
|
||||
|
||||
_displayName = displayName;
|
||||
|
||||
qDebug() << "Got login: " << username << password;
|
||||
|
||||
auto request = new QNetworkRequest(QUrl(METAVERSE_API_URL + "/oauth/token"));
|
||||
auto request = new LoginRequest();
|
||||
|
||||
request->setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
|
||||
request->setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("grant_type", "password");
|
||||
query.addQueryItem("username", username);
|
||||
query.addQueryItem("password", password);
|
||||
query.addQueryItem("scope", "owner");
|
||||
connect(request, &LoginRequest::finished, this, [this, request]() {
|
||||
ASSERT_STATE(ApplicationState::RequestingLogin);
|
||||
|
||||
auto reply = _networkAccessManager.post(*request, query.toString().toUtf8());
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, &LauncherState::receivedLoginReply);
|
||||
}
|
||||
request->deleteLater();
|
||||
|
||||
Q_INVOKABLE void LauncherState::receivedLoginReply() {
|
||||
ASSERT_STATE(ApplicationState::RequestingLogin);
|
||||
auto err = request->getError();
|
||||
if (err != LoginRequest::Error::None) {
|
||||
setApplicationStateError("Failed to login");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Check for errors
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
_loginResponse = request->getToken();
|
||||
_loginTokenResponse = request->getRawToken();
|
||||
|
||||
if (reply->error()) {
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
requestSettings();
|
||||
});
|
||||
|
||||
auto data = reply->readAll();
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
auto root = doc.object();
|
||||
|
||||
if (!root.contains("access_token")
|
||||
|| !root.contains("token_type")
|
||||
|| !root.contains("expires_in")
|
||||
|| !root.contains("refresh_token")
|
||||
|| !root.contains("scope")
|
||||
|| !root.contains("created_at")) {
|
||||
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
_loginResponse.accessToken = root["access_token"].toString();
|
||||
_loginResponse.refreshToken = root["refresh_token"].toString();
|
||||
_loginResponse.tokenType = root["token_type"].toString();
|
||||
|
||||
qDebug() << "Got response for login: " << data;
|
||||
_loginTokenResponse = data;
|
||||
|
||||
requestSettings();
|
||||
request->send(_networkAccessManager, username, password);
|
||||
}
|
||||
|
||||
void LauncherState::requestSettings() {
|
||||
// TODO Request settings if already logged in
|
||||
qDebug() << "Requesting settings";
|
||||
|
||||
QUrl lockerURL = METAVERSE_API_URL;
|
||||
lockerURL.setPath("/api/v1/user/locker");
|
||||
auto request = new UserSettingsRequest();
|
||||
|
||||
auto lockerRequest = new QNetworkRequest(lockerURL);
|
||||
lockerRequest->setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
lockerRequest->setHeader(QNetworkRequest::UserAgentHeader, getUserAgent());
|
||||
lockerRequest->setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, QString("Bearer %1").arg(_loginResponse.accessToken).toUtf8());
|
||||
|
||||
QNetworkReply* lockerReply = _networkAccessManager.get(*lockerRequest);
|
||||
connect(lockerReply, &QNetworkReply::finished, this, &LauncherState::receivedSettingsReply);
|
||||
}
|
||||
|
||||
void LauncherState::receivedSettingsReply() {
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
qDebug() << "Got reply: " << reply->error();
|
||||
if (reply->error()) {
|
||||
setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
auto data = reply->readAll();
|
||||
qDebug() << "Settings: " << data;
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qDebug() << "Error parsing settings";
|
||||
setApplicationStateError("Error retreiving settings");
|
||||
return;
|
||||
}
|
||||
|
||||
auto root = doc.object();
|
||||
if (root["status"] != "success") {
|
||||
qDebug() << "Status is not \"success\"";
|
||||
setApplicationStateError("Error retreiving settings");
|
||||
return;
|
||||
}
|
||||
|
||||
_homeLocation = "hifi://hq";
|
||||
if (root["data"].toObject().contains("home_location")) {
|
||||
auto homeLocation = root["data"].toObject()["home_location"];
|
||||
if (homeLocation.isString()) {
|
||||
_homeLocation = homeLocation.toString();
|
||||
connect(request, &UserSettingsRequest::finished, this, [this, request]() {
|
||||
auto userSettings = request->getUserSettings();
|
||||
if (userSettings.homeLocation.isEmpty()) {
|
||||
_homeLocation = "hifi://hq";
|
||||
_contentCacheURL = "";
|
||||
} else {
|
||||
_homeLocation = userSettings.homeLocation;
|
||||
auto host = QUrl(_homeLocation).host();
|
||||
_contentCacheURL = "http://orgs.highfidelity.com/host-content-cache/" + host + ".zip";
|
||||
qDebug() << "Home location is: " << _homeLocation;
|
||||
qDebug() << "Content cache url is: " << _contentCacheURL;
|
||||
}
|
||||
}
|
||||
|
||||
//qDebug() << "Home:" << _homeLocation << QUrl(_homeLocation).host();
|
||||
qDebug() << "Home location is: " << _homeLocation;
|
||||
qDebug() << "Content cache url is: " << _contentCacheURL;
|
||||
|
||||
downloadClient();
|
||||
downloadClient();
|
||||
});
|
||||
|
||||
request->send(_networkAccessManager, _loginResponse);
|
||||
}
|
||||
|
||||
void LauncherState::downloadClient() {
|
||||
|
@ -683,10 +670,9 @@ void LauncherState::launchClient() {
|
|||
defaultScriptsPath = installDirectory.filePath("interface.app/Contents/Resources/scripts/simplifiedUIBootstrapper.js");
|
||||
#endif
|
||||
|
||||
QString displayName = "fixMe";
|
||||
QString contentCachePath = _launcherDirectory.filePath("cache");
|
||||
|
||||
::launchClient(clientPath, _homeLocation, QDir::toNativeSeparators(defaultScriptsPath), displayName, contentCachePath, _loginTokenResponse);
|
||||
::launchClient(clientPath, _homeLocation, defaultScriptsPath, _displayName, contentCachePath, _loginTokenResponse);
|
||||
}
|
||||
|
||||
void LauncherState::setApplicationStateError(QString errorMessage) {
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
#include <QNetworkAccessManager>
|
||||
#include <QFile>
|
||||
|
||||
#include "LoginRequest.h"
|
||||
#include "SignupRequest.h"
|
||||
#include "UserSettingsRequest.h"
|
||||
|
||||
struct Build {
|
||||
QString tag;
|
||||
int latestVersion;
|
||||
|
@ -22,18 +26,13 @@ struct LatestBuilds {
|
|||
Build launcherBuild;
|
||||
};
|
||||
|
||||
struct LoginResponse {
|
||||
QString accessToken;
|
||||
QString tokenType;
|
||||
QString refreshToken;
|
||||
};
|
||||
|
||||
class LauncherState : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(UIState uiState READ getUIState NOTIFY uiStateChanged);
|
||||
Q_PROPERTY(ApplicationState applicationState READ getApplicationState NOTIFY applicationStateChanged);
|
||||
Q_PROPERTY(float downloadProgress READ getDownloadProgress NOTIFY downloadProgressChanged);
|
||||
Q_PROPERTY(SignupRequest::Error lastSignupError MEMBER _lastSignupError NOTIFY lastSignupErrorChanged);
|
||||
|
||||
public:
|
||||
LauncherState();
|
||||
|
@ -41,6 +40,7 @@ public:
|
|||
|
||||
enum UIState {
|
||||
SPLASH_SCREEN = 0,
|
||||
SIGNUP_SCREEN,
|
||||
LOGIN_SCREEN,
|
||||
DISPLAY_NAME_SCREEN,
|
||||
DOWNLOAD_SCREEN,
|
||||
|
@ -60,6 +60,10 @@ public:
|
|||
WaitingForLogin,
|
||||
RequestingLogin,
|
||||
|
||||
WaitingForSignup,
|
||||
RequestingSignup,
|
||||
RequestingLoginAfterSignup,
|
||||
|
||||
DownloadingClient,
|
||||
DownloadingLauncher,
|
||||
DownloadingContentCache,
|
||||
|
@ -85,7 +89,7 @@ public:
|
|||
Q_INVOKABLE QString getCurrentUISource() const;
|
||||
|
||||
void ASSERT_STATE(LauncherState::ApplicationState state);
|
||||
void ASSERT_STATE(std::vector<LauncherState::ApplicationState> states);
|
||||
void ASSERT_STATE(const std::vector<LauncherState::ApplicationState>& states);
|
||||
|
||||
static void declareQML();
|
||||
|
||||
|
@ -98,17 +102,21 @@ public:
|
|||
void setApplicationState(ApplicationState state);
|
||||
ApplicationState getApplicationState() const;
|
||||
|
||||
Q_INVOKABLE void gotoSignup();
|
||||
Q_INVOKABLE void gotoLogin();
|
||||
|
||||
// Request builds
|
||||
void requestBuilds();
|
||||
Q_INVOKABLE void receivedBuildsReply();
|
||||
|
||||
// Signup
|
||||
Q_INVOKABLE void signup(QString email, QString username, QString password, QString displayName);
|
||||
|
||||
// Login
|
||||
Q_INVOKABLE void login(QString username, QString password);
|
||||
Q_INVOKABLE void receivedLoginReply();
|
||||
Q_INVOKABLE void login(QString username, QString password, QString displayName);
|
||||
|
||||
// Request Settings
|
||||
void requestSettings();
|
||||
Q_INVOKABLE void receivedSettingsReply();
|
||||
|
||||
// Launcher
|
||||
void downloadLauncher();
|
||||
|
@ -132,6 +140,7 @@ signals:
|
|||
void uiStateChanged();
|
||||
void applicationStateChanged();
|
||||
void downloadProgressChanged();
|
||||
void lastSignupErrorChanged();
|
||||
|
||||
private slots:
|
||||
void clientDownloadComplete();
|
||||
|
@ -154,8 +163,10 @@ private:
|
|||
|
||||
// Application State
|
||||
ApplicationState _applicationState { ApplicationState::Init };
|
||||
LoginResponse _loginResponse;
|
||||
LoginToken _loginResponse;
|
||||
LastLoginError _lastLoginError { NONE };
|
||||
SignupRequest::Error _lastSignupError{ SignupRequest::Error::None };
|
||||
QString _displayName;
|
||||
QString _applicationErrorMessage;
|
||||
QString _currentClientVersion;
|
||||
QString _buildTag { QString::null };
|
||||
|
@ -166,5 +177,8 @@ private:
|
|||
QFile _launcherZipFile;
|
||||
QFile _contentZipFile;
|
||||
|
||||
QString _username;
|
||||
QString _password;
|
||||
|
||||
float _downloadProgress { 0 };
|
||||
};
|
||||
|
|
73
launchers/qt/src/LoginRequest.cpp
Normal file
73
launchers/qt/src/LoginRequest.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
#include "LoginRequest.h"
|
||||
|
||||
#include "Helper.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
void LoginRequest::send(QNetworkAccessManager& nam, QString username, QString password) {
|
||||
QNetworkRequest request(QUrl(METAVERSE_API_DOMAIN + "/oauth/token"));
|
||||
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("grant_type", "password");
|
||||
query.addQueryItem("username", username);
|
||||
query.addQueryItem("password", password);
|
||||
query.addQueryItem("scope", "owner");
|
||||
|
||||
auto reply = nam.post(request, query.toString().toUtf8());
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, &LoginRequest::receivedResponse);
|
||||
}
|
||||
|
||||
void LoginRequest::receivedResponse() {
|
||||
_state = State::Finished;
|
||||
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
if (reply->error()) {
|
||||
qDebug() << "Error logging in: " << reply->readAll();
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
//setApplicationState(ApplicationState::UnexpectedError);
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = reply->readAll();
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qDebug() << "Error parsing response for login" << data;
|
||||
_error = Error::BadResponse;
|
||||
emit finished();
|
||||
//setApplicationStateError("Failed to login");
|
||||
return;
|
||||
}
|
||||
|
||||
auto root = doc.object();
|
||||
|
||||
if (!root.contains("access_token")
|
||||
|| !root.contains("token_type")
|
||||
|| !root.contains("expires_in")
|
||||
|| !root.contains("refresh_token")
|
||||
|| !root.contains("scope")
|
||||
|| !root.contains("created_at")) {
|
||||
|
||||
_error = Error::BadUsernameOrPassword;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
_token.accessToken = root["access_token"].toString();
|
||||
_token.refreshToken = root["refresh_token"].toString();
|
||||
_token.tokenType = root["token_type"].toString();
|
||||
|
||||
qDebug() << "Got response for login: " << data;
|
||||
_rawLoginToken = data;
|
||||
|
||||
emit finished();
|
||||
}
|
49
launchers/qt/src/LoginRequest.h
Normal file
49
launchers/qt/src/LoginRequest.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
struct LoginToken {
|
||||
QString accessToken;
|
||||
QString tokenType;
|
||||
QString refreshToken;
|
||||
};
|
||||
|
||||
class LoginRequest : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class State {
|
||||
Unsent,
|
||||
Sending,
|
||||
Finished
|
||||
};
|
||||
|
||||
enum class Error {
|
||||
None = 0,
|
||||
Unknown,
|
||||
BadResponse,
|
||||
BadUsernameOrPassword
|
||||
};
|
||||
Q_ENUM(Error)
|
||||
|
||||
void send(QNetworkAccessManager& nam, QString username, QString password);
|
||||
Error getError() const { return _error; }
|
||||
|
||||
// The token is only valid if the request has finished without error
|
||||
QString getRawToken() const { return _rawLoginToken; }
|
||||
LoginToken getToken() const { return _token; }
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void receivedResponse();
|
||||
|
||||
private:
|
||||
State _state { State::Unsent };
|
||||
Error _error { Error::None };
|
||||
|
||||
QString _rawLoginToken;
|
||||
LoginToken _token;
|
||||
};
|
||||
|
79
launchers/qt/src/SignupRequest.cpp
Normal file
79
launchers/qt/src/SignupRequest.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include "SignupRequest.h"
|
||||
|
||||
#include "Helper.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
void SignupRequest::send(QNetworkAccessManager& nam, QString email, QString username, QString password) {
|
||||
if (_state != State::Unsent) {
|
||||
qDebug() << "Error: Trying to send signuprequest, but not unsent";
|
||||
return;
|
||||
}
|
||||
|
||||
_state = State::Sending;
|
||||
|
||||
QUrl signupURL { METAVERSE_API_DOMAIN };
|
||||
signupURL.setPath("/api/v1/user/channel_user");
|
||||
QNetworkRequest request(signupURL);
|
||||
|
||||
request.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("email", email);
|
||||
query.addQueryItem("username", username);
|
||||
query.addQueryItem("password", password);
|
||||
|
||||
auto reply = nam.post(request, query.toString().toUtf8());
|
||||
QObject::connect(reply, &QNetworkReply::finished, this, &SignupRequest::receivedResponse);
|
||||
}
|
||||
|
||||
void SignupRequest::receivedResponse() {
|
||||
_state = State::Finished;
|
||||
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
if (reply->error() && reply->size() == 0) {
|
||||
qDebug() << "Error signing up: " << reply->error() << reply->readAll();
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = reply->readAll();
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qDebug() << "Error parsing response for signup " << data;
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
auto root = doc.object();
|
||||
|
||||
auto status = root["status"];
|
||||
if (status.isString() && status.toString() != "success") {
|
||||
auto error = root["data"].toString();
|
||||
|
||||
_error = Error::Unknown;
|
||||
|
||||
if (error == "no_such_email") {
|
||||
_error = Error::NoSuchEmail;
|
||||
} else if (error == "user_profile_already_completed") {
|
||||
_error = Error::UserProfileAlreadyCompleted;
|
||||
} else if (error == "bad_username") {
|
||||
_error = Error::BadUsername;
|
||||
} else if (error == "existing_username") {
|
||||
_error = Error::ExistingUsername;
|
||||
} else if (error == "bad_password") {
|
||||
_error = Error::BadPassword;
|
||||
}
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
38
launchers/qt/src/SignupRequest.h
Normal file
38
launchers/qt/src/SignupRequest.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class SignupRequest : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class State {
|
||||
Unsent,
|
||||
Sending,
|
||||
Finished
|
||||
};
|
||||
|
||||
enum class Error {
|
||||
None = 0,
|
||||
Unknown,
|
||||
NoSuchEmail,
|
||||
UserProfileAlreadyCompleted,
|
||||
BadUsername,
|
||||
ExistingUsername,
|
||||
BadPassword,
|
||||
};
|
||||
Q_ENUM(Error)
|
||||
|
||||
void send(QNetworkAccessManager& nam, QString email, QString username, QString password);
|
||||
Error getError() const { return _error; }
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void receivedResponse();
|
||||
|
||||
private:
|
||||
State _state { State::Unsent };
|
||||
Error _error { Error::None };
|
||||
};
|
67
launchers/qt/src/UserSettingsRequest.cpp
Normal file
67
launchers/qt/src/UserSettingsRequest.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
#include "UserSettingsRequest.h"
|
||||
|
||||
#include "Helper.h"
|
||||
|
||||
#include <QUrlQuery>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
|
||||
const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
void UserSettingsRequest::send(QNetworkAccessManager& nam, const LoginToken& token) {
|
||||
_state = State::Sending;
|
||||
|
||||
QUrl lockerURL = METAVERSE_API_DOMAIN;
|
||||
lockerURL.setPath("/api/v1/user/locker");
|
||||
|
||||
QNetworkRequest lockerRequest(lockerURL);
|
||||
lockerRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
lockerRequest.setHeader(QNetworkRequest::UserAgentHeader, getHTTPUserAgent());
|
||||
lockerRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, QString("Bearer %1").arg(token.accessToken).toUtf8());
|
||||
|
||||
QNetworkReply* lockerReply = nam.get(lockerRequest);
|
||||
connect(lockerReply, &QNetworkReply::finished, this, &UserSettingsRequest::receivedResponse);
|
||||
}
|
||||
|
||||
void UserSettingsRequest::receivedResponse() {
|
||||
_state = State::Finished;
|
||||
|
||||
auto reply = static_cast<QNetworkReply*>(sender());
|
||||
|
||||
qDebug() << "Got reply: " << reply->error();
|
||||
if (reply->error()) {
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = reply->readAll();
|
||||
qDebug() << "Settings: " << data;
|
||||
QJsonParseError parseError;
|
||||
auto doc = QJsonDocument::fromJson(data, &parseError);
|
||||
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qDebug() << "Error parsing settings";
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
auto root = doc.object();
|
||||
if (root["status"] != "success") {
|
||||
qDebug() << "Status is not \"success\"";
|
||||
_error = Error::Unknown;
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
if (root["data"].toObject().contains("home_location")) {
|
||||
auto homeLocation = root["data"].toObject()["home_location"];
|
||||
if (homeLocation.isString()) {
|
||||
_userSettings.homeLocation = homeLocation.toString();
|
||||
}
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
43
launchers/qt/src/UserSettingsRequest.h
Normal file
43
launchers/qt/src/UserSettingsRequest.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
#include "LoginRequest.h"
|
||||
|
||||
struct UserSettings {
|
||||
QString homeLocation{ QString::null };
|
||||
};
|
||||
|
||||
class UserSettingsRequest : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class State {
|
||||
Unsent,
|
||||
Sending,
|
||||
Finished
|
||||
};
|
||||
|
||||
enum class Error {
|
||||
None = 0,
|
||||
Unknown,
|
||||
};
|
||||
Q_ENUM(Error)
|
||||
|
||||
void send(QNetworkAccessManager& nam, const LoginToken& token);
|
||||
Error getError() const { return _error; }
|
||||
|
||||
UserSettings getUserSettings() const { return _userSettings; }
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private slots:
|
||||
void receivedResponse();
|
||||
|
||||
private:
|
||||
State _state { State::Unsent };
|
||||
Error _error { Error::None };
|
||||
|
||||
UserSettings _userSettings;
|
||||
};
|
|
@ -1,5 +1,7 @@
|
|||
#include <QtPlugin>
|
||||
|
||||
#include <qsharedmemory.h>
|
||||
|
||||
#include "LauncherWindow.h"
|
||||
#include "Launcher.h"
|
||||
#include <iostream>
|
||||
|
@ -19,7 +21,7 @@ Q_IMPORT_PLUGIN(QtQuickTemplates2Plugin);
|
|||
|
||||
|
||||
|
||||
bool hasSuffix(const std::string path, const std::string suffix) {
|
||||
bool hasSuffix(const std::string& path, const std::string& suffix) {
|
||||
if (path.substr(path.find_last_of(".") + 1) == suffix) {
|
||||
return true;
|
||||
}
|
||||
|
@ -61,6 +63,12 @@ int main(int argc, char *argv[]) {
|
|||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setOrganizationName(name);
|
||||
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
//QSharedMemory sharedMemory{ applicationName };
|
||||
//instanceMightBeRunning = !sharedMemory.create(1, QSharedMemory::ReadOnly);
|
||||
#endif
|
||||
|
||||
Launcher launcher(argc, argv);
|
||||
|
||||
return launcher.exec();
|
||||
|
|
Loading…
Reference in a new issue