mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-20 03:37:47 +00:00
Improve character sync error handling, and the sync itself
Ported from libQuotient's invokeLogin to our own custom one, so we can avoid the initial sync until login. Then, make sure we find the room *after* the sync, not before it. Also since I wiped the media cache from my server, I hit a crash since it tried to open an invalid ZIP file. Now we can handle that.
This commit is contained in:
parent
b5b9cdfdc0
commit
807cf0e062
4 changed files with 68 additions and 33 deletions
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QCoro::Task<void> uploadCharacterData(const QDir &dir, const QString &id);
|
QCoro::Task<void> uploadCharacterData(const QDir &dir, const QString &id);
|
||||||
QCoro::Task<void> downloadCharacterData(const QDir &dir, const QString &id, const QString &contentUri);
|
QCoro::Task<bool> downloadCharacterData(const QDir &dir, const QString &id, const QString &contentUri);
|
||||||
|
|
||||||
LauncherCore &launcher;
|
LauncherCore &launcher;
|
||||||
Account &m_account;
|
Account &m_account;
|
||||||
|
|
|
@ -105,12 +105,12 @@ Q_SIGNALS:
|
||||||
void loginError(const QString &message);
|
void loginError(const QString &message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void invokeLogin();
|
||||||
QString roomId() const;
|
QString roomId() const;
|
||||||
void setRoomId(const QString &roomId);
|
void setRoomId(const QString &roomId);
|
||||||
QCoro::Task<> findRoom();
|
QCoro::Task<> findRoom();
|
||||||
QCoro::Task<> beginInitialSync();
|
|
||||||
|
|
||||||
Quotient::AccountRegistry m_accountRegistry;
|
Quotient::AccountRegistry m_accountRegistry;
|
||||||
|
|
||||||
Quotient::Room *m_currentRoom = nullptr;
|
Quotient::Room *m_currentRoom = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,6 +33,9 @@ QCoro::Task<bool> CharacterSync::sync(const bool initialSync)
|
||||||
co_return false;
|
co_return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform a manual sync just in case
|
||||||
|
co_await syncManager->sync();
|
||||||
|
|
||||||
if (!syncManager->isReady()) {
|
if (!syncManager->isReady()) {
|
||||||
Q_EMIT launcher.stageChanged(i18n("Waiting for sync connection..."));
|
Q_EMIT launcher.stageChanged(i18n("Waiting for sync connection..."));
|
||||||
|
|
||||||
|
@ -42,9 +45,6 @@ QCoro::Task<bool> CharacterSync::sync(const bool initialSync)
|
||||||
|
|
||||||
Q_EMIT launcher.stageChanged(i18n("Synchronizing character data..."));
|
Q_EMIT launcher.stageChanged(i18n("Synchronizing character data..."));
|
||||||
|
|
||||||
// Perform a manual sync just in case
|
|
||||||
co_await syncManager->sync();
|
|
||||||
|
|
||||||
// On game boot, check if we need the lock. Otherwise break it when we clean up.
|
// On game boot, check if we need the lock. Otherwise break it when we clean up.
|
||||||
if (initialSync) {
|
if (initialSync) {
|
||||||
if (const auto hostname = co_await syncManager->checkLock(); hostname.has_value()) {
|
if (const auto hostname = co_await syncManager->checkLock(); hostname.has_value()) {
|
||||||
|
@ -110,10 +110,15 @@ QCoro::Task<bool> CharacterSync::sync(const bool initialSync)
|
||||||
const bool needsDownload = areFilesDifferent;
|
const bool needsDownload = areFilesDifferent;
|
||||||
|
|
||||||
if (needsUpload) {
|
if (needsUpload) {
|
||||||
|
qCDebug(ASTRA_LOG) << id << "uploading character data";
|
||||||
// if we didn't upload character data yet, upload it now
|
// if we didn't upload character data yet, upload it now
|
||||||
co_await uploadCharacterData(dir.absoluteFilePath(), id);
|
co_await uploadCharacterData(dir.absoluteFilePath(), id);
|
||||||
} else if (needsDownload) {
|
} else if (needsDownload) {
|
||||||
co_await downloadCharacterData(dir.absoluteFilePath(), id, previousData->mxcUri);
|
qCDebug(ASTRA_LOG) << id << "downloading character data";
|
||||||
|
if (!co_await downloadCharacterData(dir.absoluteFilePath(), id, previousData->mxcUri)) {
|
||||||
|
Q_EMIT launcher.loginError(i18n("Failed to sync character data from the server. Please do another initial sync under Settings and try again."));
|
||||||
|
co_return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +154,7 @@ QCoro::Task<void> CharacterSync::uploadCharacterData(const QDir &dir, const QStr
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCoro::Task<void> CharacterSync::downloadCharacterData(const QDir &dir, const QString &id, const QString &contentUri)
|
QCoro::Task<bool> CharacterSync::downloadCharacterData(const QDir &dir, const QString &id, const QString &contentUri)
|
||||||
{
|
{
|
||||||
const QTemporaryDir tempDir;
|
const QTemporaryDir tempDir;
|
||||||
|
|
||||||
|
@ -160,17 +165,27 @@ QCoro::Task<void> CharacterSync::downloadCharacterData(const QDir &dir, const QS
|
||||||
auto zip = new KZip(tempZipPath);
|
auto zip = new KZip(tempZipPath);
|
||||||
zip->setCompression(KZip::DeflateCompression);
|
zip->setCompression(KZip::DeflateCompression);
|
||||||
zip->open(QIODevice::ReadOnly);
|
zip->open(QIODevice::ReadOnly);
|
||||||
|
if (zip->isOpen()) {
|
||||||
|
qCDebug(ASTRA_LOG) << "contents:" << zip->directory()->entries();
|
||||||
|
|
||||||
qCDebug(ASTRA_LOG) << "contents:" << zip->directory()->entries();
|
if (auto file = zip->directory()->file(gearsetFilename); file != nullptr) {
|
||||||
|
Q_UNUSED(file->copyTo(dir.absolutePath()))
|
||||||
|
|
||||||
Q_UNUSED(zip->directory()->file(gearsetFilename)->copyTo(dir.absolutePath()))
|
qCDebug(ASTRA_LOG) << "Extracted character data!";
|
||||||
|
|
||||||
qCDebug(ASTRA_LOG) << "Extracted character data!";
|
zip->close();
|
||||||
|
delete zip;
|
||||||
|
|
||||||
|
co_return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
zip->close();
|
zip->close();
|
||||||
delete zip;
|
delete zip;
|
||||||
|
|
||||||
co_return;
|
qCDebug(ASTRA_LOG) << "Failed to read character ZIP!";
|
||||||
|
|
||||||
|
co_return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "moc_charactersync.cpp"
|
#include "moc_charactersync.cpp"
|
||||||
|
|
|
@ -33,7 +33,7 @@ using namespace Quotient;
|
||||||
SyncManager::SyncManager(QObject *parent)
|
SyncManager::SyncManager(QObject *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
m_accountRegistry.invokeLogin(); // TODO: port from invokeLogin
|
invokeLogin();
|
||||||
connect(&m_accountRegistry, &AccountRegistry::rowsInserted, this, [this]() {
|
connect(&m_accountRegistry, &AccountRegistry::rowsInserted, this, [this]() {
|
||||||
connection()->setCacheState(false);
|
connection()->setCacheState(false);
|
||||||
connection()->setLazyLoading(false);
|
connection()->setLazyLoading(false);
|
||||||
|
@ -43,8 +43,6 @@ SyncManager::SyncManager(QObject *parent)
|
||||||
Q_EMIT connectedChanged();
|
Q_EMIT connectedChanged();
|
||||||
Q_EMIT userIdChanged();
|
Q_EMIT userIdChanged();
|
||||||
Q_EMIT connectionChanged();
|
Q_EMIT connectionChanged();
|
||||||
|
|
||||||
beginInitialSync();
|
|
||||||
});
|
});
|
||||||
connect(&m_accountRegistry, &AccountRegistry::rowsRemoved, this, [this]() {
|
connect(&m_accountRegistry, &AccountRegistry::rowsRemoved, this, [this]() {
|
||||||
Q_EMIT connectedChanged();
|
Q_EMIT connectedChanged();
|
||||||
|
@ -117,7 +115,11 @@ QCoro::Task<> SyncManager::sync()
|
||||||
auto connection = m_accountRegistry.accounts().first();
|
auto connection = m_accountRegistry.accounts().first();
|
||||||
connection->sync();
|
connection->sync();
|
||||||
co_await qCoro(connection, &Connection::syncDone);
|
co_await qCoro(connection, &Connection::syncDone);
|
||||||
m_accountRegistry.accounts().first()->stopSync();
|
|
||||||
|
if (!m_currentRoom) {
|
||||||
|
co_await findRoom();
|
||||||
|
}
|
||||||
|
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +134,18 @@ QCoro::Task<void> SyncManager::findRoom()
|
||||||
// If we have no room id set, we need to find the correct room type
|
// If we have no room id set, we need to find the correct room type
|
||||||
const bool needsFirstTimeRoom = roomId.isEmpty();
|
const bool needsFirstTimeRoom = roomId.isEmpty();
|
||||||
|
|
||||||
|
if (!needsFirstTimeRoom) {
|
||||||
|
auto room = m_accountRegistry.accounts().first()->room(roomId);
|
||||||
|
if (room) {
|
||||||
|
qCDebug(ASTRA_LOG) << "Found pre-existing room!";
|
||||||
|
|
||||||
|
m_currentRoom = room;
|
||||||
|
Q_EMIT isReadyChanged();
|
||||||
|
|
||||||
|
co_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Try to find our room
|
// Try to find our room
|
||||||
auto rooms = m_accountRegistry.accounts().first()->rooms(Quotient::JoinState::Join);
|
auto rooms = m_accountRegistry.accounts().first()->rooms(Quotient::JoinState::Join);
|
||||||
for (auto room : rooms) {
|
for (auto room : rooms) {
|
||||||
|
@ -151,15 +165,6 @@ QCoro::Task<void> SyncManager::findRoom()
|
||||||
Q_EMIT isReadyChanged();
|
Q_EMIT isReadyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (room->id() == roomId) {
|
|
||||||
qCDebug(ASTRA_LOG) << "Found pre-existing room!";
|
|
||||||
|
|
||||||
m_currentRoom = room;
|
|
||||||
Q_EMIT isReadyChanged();
|
|
||||||
|
|
||||||
co_return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,6 +195,28 @@ QCoro::Task<void> SyncManager::findRoom()
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SyncManager::invokeLogin()
|
||||||
|
{
|
||||||
|
// Simplified from libQuotient, but this can be simplified even more
|
||||||
|
const auto accounts = SettingsGroup("Accounts"_L1).childGroups();
|
||||||
|
for (const auto &accountId : accounts) {
|
||||||
|
AccountSettings account{accountId};
|
||||||
|
|
||||||
|
if (account.homeserver().isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto accessTokenLoadingJob = new QKeychain::ReadPasswordJob(qAppName(), this);
|
||||||
|
accessTokenLoadingJob->setKey(accountId);
|
||||||
|
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this, [accountId, this, accessTokenLoadingJob]() {
|
||||||
|
AccountSettings account{accountId};
|
||||||
|
auto connection = new Connection(account.homeserver());
|
||||||
|
connection->assumeIdentity(account.userId(), account.deviceId(), QString::fromUtf8(accessTokenLoadingJob->binaryData()));
|
||||||
|
m_accountRegistry.add(connection);
|
||||||
|
});
|
||||||
|
accessTokenLoadingJob->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString SyncManager::roomId() const
|
QString SyncManager::roomId() const
|
||||||
{
|
{
|
||||||
return KSharedConfig::openStateConfig()->group(QStringLiteral("Sync")).readEntry(QStringLiteral("RoomId"));
|
return KSharedConfig::openStateConfig()->group(QStringLiteral("Sync")).readEntry(QStringLiteral("RoomId"));
|
||||||
|
@ -204,6 +231,7 @@ void SyncManager::setRoomId(const QString &roomId)
|
||||||
|
|
||||||
bool SyncManager::isReady() const
|
bool SyncManager::isReady() const
|
||||||
{
|
{
|
||||||
|
qInfo() << connected() << m_currentRoom;
|
||||||
return connected() && m_currentRoom;
|
return connected() && m_currentRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,12 +322,4 @@ QCoro::Task<> SyncManager::breakLock()
|
||||||
co_return;
|
co_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QCoro::Task<> SyncManager::beginInitialSync()
|
|
||||||
{
|
|
||||||
co_await sync();
|
|
||||||
|
|
||||||
// Find the room we need to sync with
|
|
||||||
findRoom();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_syncmanager.cpp"
|
#include "moc_syncmanager.cpp"
|
||||||
|
|
Loading…
Add table
Reference in a new issue