diff --git a/KomplexHubPlugin/CMakeLists.txt b/KomplexHubPlugin/CMakeLists.txt index f25573a..52a4d4d 100644 --- a/KomplexHubPlugin/CMakeLists.txt +++ b/KomplexHubPlugin/CMakeLists.txt @@ -56,9 +56,12 @@ qt_add_qml_module( common/shaderpack.h packcompiler.h packcompiler.cpp - SOURCES common/userservices.h - SOURCES common/userservices.cpp - SOURCES common/qwallet.h common/qwallet.cpp + common/userservices.h + common/userservices.cpp + common/qwallet.h + common/qwallet.cpp + usermodel.h + usermodel.cpp ) target_compile_definitions( diff --git a/KomplexHubPlugin/usermodel.cpp b/KomplexHubPlugin/usermodel.cpp new file mode 100644 index 0000000..b45d38f --- /dev/null +++ b/KomplexHubPlugin/usermodel.cpp @@ -0,0 +1,288 @@ +#include "usermodel.h" +#include "common/userservices.h" +#include +#include +#include +#include +#include + +UserModel::UserModel(QObject *parent) + : QObject{parent} +{ + m_stateResetTimer = new QTimer(this); + m_stateResetTimer->setInterval(1000); + m_stateResetTimer->setSingleShot(true); + + QObject::connect + ( + m_stateResetTimer, + &QTimer::timeout, + this, + &UserModel::resetState + ); + + setState(Busy); + + QSharedPointer service = UserServices::instance(); + + if(service == nullptr) + { + setErrorString(QStringLiteral("UserServices object deleted")); + setState(LoginFailure); + return; + } + + QFuture usernameFuture = service->defaultUsername(); + + usernameFuture + .then + ( + [this] (const QString username) + { + login(username); + } + ) + .onCanceled + ( + [this] () -> void + { + reset(); + } + ) + .onFailed + ( + [this] () -> void + { + reset(); + } + ); + + service.clear(); +} + +UserModel::~UserModel() +{ + if(m_stateResetTimer != nullptr) + { + m_stateResetTimer->deleteLater(); + } +} + +auto UserModel::login() -> void +{ + QFuture aether = QtConcurrent::run + ( + [this] () -> void + { + QMutexLocker locker(&m_loginMutex); + setState(LoggingIn); + + QSharedPointer service = UserServices::instance(); + + if(service == nullptr) + { + setErrorString(QStringLiteral("UserServices object deleted")); + setState(LoginFailure); + return; + } + + m_loginAttempt = service->login(username(), password().toUtf8()); + + m_loginAttempt + .then + ( + [this] (UserCredentials credentials) -> void + { + setState(LoggedIn); + } + ) + .onCanceled + ( + [this] () -> void + { + setState(LoginFailure); + } + ) + .onFailed + ( + [this] () -> void + { + setState(LoginCancelled); + } + ); + } + ); +} + +auto UserModel::login(const QString username) -> void +{ + if(username == m_username) + { + return; + } + + m_username = username; + Q_EMIT usernameChanged(); + + QSharedPointer service = UserServices::instance(); + + if(service == nullptr) + { + setErrorString(QStringLiteral("UserServices object deleted")); + setState(LoggedOut); + return; + } + + QFuture tokenRead = service->readToken(username); + + tokenRead + .then + ( + [this] (const UserCredentials credentials) -> void + { + if(QDateTime::currentDateTime() <= credentials.expiry) + { + setState(LoggedIn); + return; + } + + QSharedPointer service = UserServices::instance(); + + if(service == nullptr) + { + setErrorString(QStringLiteral("UserServices object deleted")); + setState(LoggedOut); + return; + } + + QFuture passwordRead = service->readPassword(credentials.username); + + passwordRead + .then + ( + [this] (const QByteArray password) + { + if(password.isEmpty()) + { + setState(LoggedOut); + return; + } + + setPassword(password); + } + ); + + service.clear(); + } + ); + + service.clear(); +} + +auto UserModel::cancelLogin() -> void +{ + QFuture aether = QtConcurrent::run + ( + [this] () -> void + { + QMutexLocker locker(&m_loginMutex); + + if(m_loginAttempt.isRunning()) + { + m_loginAttempt.cancel(); + } + } + ); +} + +auto UserModel::reset() -> void +{ + resetState(); + setUsername({}); + setPassword({}); +} + +auto UserModel::setUsername(const QString &username) -> void +{ + if(username == m_username) + { + return; + } + + m_username = username; + Q_EMIT usernameChanged(); + + if(!password().isEmpty()) + { + return; + } + + setState(Busy); + + QSharedPointer service = UserServices::instance(); + + if(service == nullptr) + { + return; + } + + QFuture passwordRead = service->readPassword(username); + passwordRead + .then + ( + [this] (const QByteArray password) -> void + { + setPassword(password); + } + ); +} + +auto UserModel::setPassword(const QString &password) -> void +{ + if(password == m_password) + { + return; + } + + m_password = password; + Q_EMIT passwordChanged(); +} + +auto UserModel::resetState() -> void +{ + setState(Idle); +} + +auto UserModel::setState(State state) -> void +{ + if(state == m_state) + { + return; + } + + switch(state) + { + case LoginFailure: + case LoggedOut: + case LoginCancelled: + m_stateResetTimer->start(); + break; + + default: + break; + } + + m_state = state; + Q_EMIT stateChanged(); +} + +auto UserModel::setErrorString(const QString &string) -> void +{ + if(string == m_errorString) + { + return; + } + + m_errorString = string; + Q_EMIT errorStringChanged(); +} diff --git a/KomplexHubPlugin/usermodel.h b/KomplexHubPlugin/usermodel.h new file mode 100644 index 0000000..e77a836 --- /dev/null +++ b/KomplexHubPlugin/usermodel.h @@ -0,0 +1,76 @@ +#ifndef USERMODEL_H +#define USERMODEL_H + +#include +#include +#include +#include +#include +#include "common/userservices.h" + +class UserModel : public QObject +{ + Q_OBJECT + QML_ELEMENT + +public: + + enum State + { + Idle, + LoggingIn, + LoggedIn, + LoginFailure, + LoginCancelled, + LoggedOut, + Busy + }; + Q_ENUM(State) + + explicit UserModel(QObject *parent = nullptr); + ~UserModel(); + + Q_INVOKABLE auto login() -> void; + Q_INVOKABLE auto login(const QString username) -> void; + Q_INVOKABLE auto cancelLogin() -> void; + Q_INVOKABLE auto reset() -> void; + + auto username() const -> const QString & { return m_username; } + auto setUsername(const QString &username) -> void; + + auto password() const -> const QString & { return m_password; } + auto setPassword(const QString &password) -> void; + + auto state() const -> State { return m_state; } + auto errorString() const -> QString { return m_errorString; } + +signals: + auto loginSuccessful() -> void; + auto loginFailed() -> void; + auto stateChanged() -> void; + auto usernameChanged() -> void; + auto passwordChanged() -> void; + auto errorStringChanged() -> void; + +protected slots: + auto resetState() -> void; + +private: + auto setState(State state) -> void; + auto setErrorString(const QString &string) -> void; + + State m_state = Idle; + QString m_errorString; + QString m_username; + QString m_password; + QTimer *m_stateResetTimer = nullptr; + QMutex m_loginMutex; + QFuture m_loginAttempt; + + Q_PROPERTY(State state READ state NOTIFY stateChanged FINAL) + Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged FINAL) + Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL) + Q_PROPERTY(QString errorString READ errorString WRITE setErrorString NOTIFY errorStringChanged FINAL) +}; + +#endif // USERMODEL_H