diff options
author | Petr Mrázek <peterix@gmail.com> | 2021-12-04 01:18:05 +0100 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2021-12-04 01:18:05 +0100 |
commit | 3c46d8a412956a759f61ae802c540ef72d00b35d (patch) | |
tree | f16564ba6be96b68ba5257a982c144320fff7911 /launcher/minecraft/auth/AccountList.cpp | |
parent | ffcef673de9fe848a92d23e02a2abed8df16eb9f (diff) | |
download | PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.gz PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.tar.bz2 PrismLauncher-3c46d8a412956a759f61ae802c540ef72d00b35d.zip |
GH-4071 Heavily refactor and rearchitect account system
This makes the account system much more modular
and makes it treat errors as something recoverable,
unless they come directly from the MSA refresh token
becoming invalid.
Diffstat (limited to 'launcher/minecraft/auth/AccountList.cpp')
-rw-r--r-- | launcher/minecraft/auth/AccountList.cpp | 138 |
1 files changed, 129 insertions, 9 deletions
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index d7537345..c44e3e89 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -15,6 +15,7 @@ #include "AccountList.h" #include "AccountData.h" +#include "AccountTask.h" #include <QIODevice> #include <QFile> @@ -24,6 +25,7 @@ #include <QJsonObject> #include <QJsonParseError> #include <QDir> +#include <QTimer> #include <QDebug> @@ -35,7 +37,14 @@ enum AccountListVersion { MojangMSA = 3 }; -AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { } +AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { + m_refreshTimer = new QTimer(this); + m_refreshTimer->setSingleShot(true); + connect(m_refreshTimer, &QTimer::timeout, this, &AccountList::fillQueue); + m_nextTimer = new QTimer(this); + m_nextTimer->setSingleShot(true); + connect(m_nextTimer, &QTimer::timeout, this, &AccountList::tryNext); +} AccountList::~AccountList() noexcept {} @@ -244,13 +253,29 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } case StatusColumn: { - if(account->isActive()) { - return tr("Working", "Account status"); - } - if(account->isExpired()) { - return tr("Expired", "Account status"); + switch(account->accountState()) { + case AccountState::Unchecked: { + return tr("Unchecked", "Account status"); + } + case AccountState::Offline: { + return tr("Offline", "Account status"); + } + case AccountState::Online: { + return tr("Online", "Account status"); + } + case AccountState::Working: { + return tr("Working", "Account status"); + } + case AccountState::Errored: { + return tr("Errored", "Account status"); + } + case AccountState::Expired: { + return tr("Expired", "Account status"); + } + case AccountState::Gone: { + return tr("Gone", "Account status"); + } } - return tr("Ready", "Account status"); } case ProfileNameColumn: { @@ -583,10 +608,105 @@ void AccountList::setListFilePath(QString path, bool autosave) bool AccountList::anyAccountIsValid() { - for(auto account:m_accounts) + for(auto account: m_accounts) { - if(account->accountStatus() != NotVerified) + if(account->ownsMinecraft()) { return true; + } } return false; } + +void AccountList::fillQueue() { + + if(m_defaultAccount && m_defaultAccount->shouldRefresh()) { + auto idToRefresh = m_defaultAccount->internalId(); + m_refreshQueue.push_back(idToRefresh); + qDebug() << "AccountList: Queued default account with internal ID " << idToRefresh << " to refresh first"; + } + + for(int i = 0; i < count(); i++) { + auto account = at(i); + if(account == m_defaultAccount) { + continue; + } + + if(account->shouldRefresh()) { + auto idToRefresh = account->internalId(); + m_refreshQueue.push_back(idToRefresh); + qDebug() << "AccountList: Queued account with internal ID " << idToRefresh << " to refresh"; + } + } + m_refreshQueue.removeDuplicates(); + tryNext(); +} + +void AccountList::requestRefresh(QString accountId) { + m_refreshQueue.push_back(accountId); + if(!isActive()) { + tryNext(); + } +} + +void AccountList::tryNext() { + beginActivity(); + while (m_refreshQueue.length()) { + auto accountId = m_refreshQueue.front(); + m_refreshQueue.pop_front(); + for(int i = 0; i < count(); i++) { + auto account = at(i); + if(account->internalId() == accountId) { + m_currentTask = account->refresh(); + if(m_currentTask) { + connect(m_currentTask.get(), &AccountTask::succeeded, this, &AccountList::authSucceeded); + connect(m_currentTask.get(), &AccountTask::failed, this, &AccountList::authFailed); + m_currentTask->start(); + qDebug() << "RefreshSchedule: Processing account " << account->accountDisplayString() << " with internal ID " << accountId; + return; + } + } + } + qDebug() << "RefreshSchedule: Account with with internal ID " << accountId << " not found."; + } + endActivity(); + // if we get here, no account needed refreshing. Schedule refresh in an hour. + m_refreshTimer->start(std::chrono::hours(1)); +} + +void AccountList::authSucceeded() { + qDebug() << "RefreshSchedule: Background account refresh succeeded"; + m_currentTask.reset(); + endActivity(); + m_nextTimer->start(std::chrono::seconds(20)); +} + +void AccountList::authFailed(QString reason) { + qDebug() << "RefreshSchedule: Background account refresh failed: " << reason; + m_currentTask.reset(); + endActivity(); + m_nextTimer->start(std::chrono::seconds(20)); +} + +bool AccountList::isActive() const { + return m_activityCount != 0; +} + +void AccountList::beginActivity() { + bool activating = m_activityCount == 0; + m_activityCount++; + if(activating) { + emit activityChanged(true); + } +} + +void AccountList::endActivity() { + if(m_activityCount == 0) { + qWarning() << m_name << " - Activity count would become below zero"; + return; + } + bool deactivating = m_activityCount == 1; + m_activityCount--; + if(deactivating) { + emit activityChanged(false); + } +} |