Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul connection management #782

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ target_sources(${QUOTIENT_LIB_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS .
Quotient/events/keyverificationevent.h
Quotient/keyimport.h
Quotient/qt_connection_util.h
Quotient/pendingconnection.h
Quotient/config.h
PRIVATE
Quotient/function_traits.cpp
Quotient/networkaccessmanager.cpp
Expand Down Expand Up @@ -247,6 +249,8 @@ target_sources(${QUOTIENT_LIB_NAME} PUBLIC FILE_SET HEADERS BASE_DIRS .
Quotient/e2ee/cryptoutils.cpp
Quotient/e2ee/sssshandler.cpp
Quotient/keyimport.cpp
Quotient/pendingconnection.cpp
Quotient/config.cpp
libquotientemojis.qrc
)

Expand Down
79 changes: 18 additions & 61 deletions Quotient/accountregistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

#include "accountregistry.h"

#include "pendingconnection.h"
#include "connection.h"
#include "logging_categories_p.h"
#include "settings.h"
#include "config.h"

#include <QtCore/QCoreApplication>

Expand Down Expand Up @@ -89,69 +91,24 @@ Connection* AccountRegistry::get(const QString& userId) const
return nullptr;
}

void AccountRegistry::invokeLogin()
QStringList AccountRegistry::accountsLoading() const
{
const auto accounts = SettingsGroup("Accounts"_ls).childGroups();
for (const auto& accountId : accounts) {
AccountSettings account { accountId };

if (account.homeserver().isEmpty())
continue;

d->m_accountsLoading += accountId;
emit accountsLoadingChanged();

qCDebug(MAIN) << "Reading access token from keychain for" << accountId;
auto accessTokenLoadingJob =
new QKeychain::ReadPasswordJob(qAppName(), this);
accessTokenLoadingJob->setKey(accountId);
connect(accessTokenLoadingJob, &QKeychain::Job::finished, this,
[accountId, this, accessTokenLoadingJob]() {
if (accessTokenLoadingJob->error()
!= QKeychain::Error::NoError) {
emit keychainError(accessTokenLoadingJob->error());
d->m_accountsLoading.removeAll(accountId);
emit accountsLoadingChanged();
return;
}

AccountSettings account { accountId };
auto connection = new Connection(account.homeserver());
connect(connection, &Connection::connected, this,
[connection, this, accountId] {
connection->loadState();
connection->setLazyLoading(true);

connection->syncLoop();

d->m_accountsLoading.removeAll(accountId);
emit accountsLoadingChanged();
});
connect(connection, &Connection::loginError, this,
[this, connection, accountId](const QString& error,
const QString& details) {
emit loginError(connection, error, details);

d->m_accountsLoading.removeAll(accountId);
emit accountsLoadingChanged();
});
connect(connection, &Connection::resolveError, this,
[this, connection, accountId](const QString& error) {
emit resolveError(connection, error);

d->m_accountsLoading.removeAll(accountId);
emit accountsLoadingChanged();
});
connection->assumeIdentity(
account.userId(),
QString::fromUtf8(accessTokenLoadingJob->binaryData()));
add(connection);
});
accessTokenLoadingJob->start();
}
return d->m_accountsLoading;
}

QStringList AccountRegistry::accountsLoading() const
PendingConnection* AccountRegistry::loginWithPassword(const QString& matrixId, const QString& password, const ConnectionSettings& settings)
{
return d->m_accountsLoading;
return PendingConnection::loginWithPassword(matrixId, password, settings, this);
}

PendingConnection* AccountRegistry::restoreConnection(const QString& matrixId, const ConnectionSettings& settings)
{
return PendingConnection::restoreConnection(matrixId, settings, this);
}

QStringList AccountRegistry::availableConnections() const
{
//TODO change accounts -> QuotientAccounts?
return Config::instance()->childGroups("Accounts"_ls, Config::Data);
//TODO check whether we have plausible data?
}
25 changes: 22 additions & 3 deletions Quotient/accountregistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@

namespace Quotient {
class Connection;
class PendingConnection;

struct ConnectionSettings
{
// Only relevant when logging in or registering. This can be left empty to get a random device id
QString deviceId;
// Only relevant when logging in or registering. Otherwise leave empty
QString initialDeviceName;
bool useEncryption = true;
bool cacheState = true;
bool rememberConnection = true;
bool sync = true;
};

class QUOTIENT_API AccountRegistry : public QAbstractListModel,
private QVector<Connection*> {
Expand Down Expand Up @@ -63,9 +76,15 @@ class QUOTIENT_API AccountRegistry : public QAbstractListModel,

QStringList accountsLoading() const;

[[deprecated("This may leak Connection objects when failing and cannot be"
"fixed without breaking the API; do not use it")]] //
void invokeLogin();
Quotient::PendingConnection *loginWithPassword(const QString& matrixId, const QString& password, const ConnectionSettings& settings = {});
Quotient::PendingConnection *restoreConnection(const QString& matrixId, const ConnectionSettings& settings = {});

Quotient::PendingConnection *mockConnection(const QString& userId) {
//TODO
return nullptr;
}

QStringList availableConnections() const;

Q_SIGNALS:
void accountCountChanged();
Expand Down
55 changes: 55 additions & 0 deletions Quotient/config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <[email protected]>
// SPDX-License-Identifier: LGPL-2.0-or-later

#include "config.h"

#include <QSettings>

class QSettingsConfig : public Config
{
//TODO this backend currently ignores the type and stores everything in the same backend
QString load(const QString& group, const QString& childGroup, const QString& key, Type type) override
{
settings.beginGroup(group);
settings.beginGroup(childGroup);
auto value = settings.value(key).toString();
settings.endGroup();
settings.endGroup();
return value;
}

void store(const QString& group, const QString& childGroup, const QString& key, const QString& value, Type type) override
{
settings.beginGroup(group);
settings.beginGroup(childGroup);
settings.setValue(key, value);
settings.endGroup();
settings.endGroup();
settings.sync();
}

QStringList childGroups(const QString& group, Type type) override
{
settings.beginGroup(group);
auto childGroups = settings.childGroups();
settings.endGroup();
return childGroups;
}

QSettings settings;
};

Config* Config::s_instance = nullptr;

Config* Config::instance()
{
if (!s_instance) {
s_instance = new QSettingsConfig();
}
return s_instance;
}

void Config::setInstance(Config* config)
{
s_instance = config;
}
25 changes: 25 additions & 0 deletions Quotient/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <[email protected]>
// SPDX-License-Identifier: LGPL-2.0-or-later

#pragma once

#include <QString>

class Config
{
public:
enum Type
{
Settings,
Data,
};
virtual QString load(const QString& group, const QString& childGroup, const QString& key, Type type) = 0;
virtual void store(const QString& group, const QString& childGroup, const QString& key, const QString& value, Type type) = 0;
virtual QStringList childGroups(const QString& group, Type type) = 0;

static Config* instance();
static void setInstance(Config* config);

private:
static Config* s_instance;
};
Loading
Loading