Skip to content
Merged
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
77 changes: 46 additions & 31 deletions Quotient/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "user.h"

#include "csapi/account-data.h"
#include "csapi/capabilities.h"
#include "csapi/joining.h"
#include "csapi/leaving.h"
#include "csapi/logout.h"
Expand Down Expand Up @@ -194,37 +193,49 @@ void Connection::assumeIdentity(const QString& mxId, const QString& accessToken)
});
}

void Connection::reloadCapabilities()
JobHandle<GetVersionsJob> Connection::loadVersions()
{
d->capabilitiesJob = callApi<GetCapabilitiesJob>(BackgroundRequest);
connect(d->capabilitiesJob, &BaseJob::success, this, [this] {
d->capabilities = d->capabilitiesJob->capabilities();

if (d->capabilities.roomVersions) {
qCDebug(MAIN) << "Room versions:" << defaultRoomVersion()
<< "is default, full list:" << availableRoomVersions();
emit capabilitiesLoaded();
for (auto* r: std::as_const(d->roomMap))
r->checkVersion();
} else
qCWarning(MAIN)
<< "The server returned an empty set of supported versions;"
" disabling version upgrade recommendations to reduce noise";
});
connect(d->capabilitiesJob, &BaseJob::failure, this, [this] {
if (d->capabilitiesJob->error() == BaseJob::IncorrectRequest)
qCDebug(MAIN) << "Server doesn't support /capabilities;"
" version upgrade recommendations won't be issued";
return callApi<GetVersionsJob>(BackgroundRequest).then([this](GetVersionsJob::Response r) {
d->data->setSupportedSpecVersions(std::move(r.versions));
});
}

bool Connection::loadingCapabilities() const
JobHandle<GetCapabilitiesJob> Connection::loadCapabilities()
{
return callApi<GetCapabilitiesJob>(BackgroundRequest)
.then(
[this](GetCapabilitiesJob::Capabilities response) {
d->capabilities = std::move(response);
if (d->capabilities.roomVersions) {
qCInfo(MAIN) << "Room versions:" << defaultRoomVersion()
<< "is default, full list:" << availableRoomVersions();
emit capabilitiesLoaded();
for (auto* r : std::as_const(d->roomMap))
r->checkVersion();
} else
qCWarning(MAIN) << "The server hasn't reported room versions it supports;"
" version upgrade recommendations won't be issued";
},
[](const GetCapabilitiesJob* job) {
if (job->error() == BaseJob::IncorrectRequest)
qCDebug(MAIN) << "The server doesn't support /capabilities;"
" version upgrade recommendations won't be issued";
});
}

void Connection::reloadCapabilities() { loadCapabilities(); }

bool Connection::loadingCapabilities() const { return !capabilitiesReady(); }

bool Connection::capabilitiesReady() const
{
// (Ab)use the fact that room versions cannot be omitted after
// the capabilities have been loaded (see reloadCapabilities() above).
return !d->capabilities.roomVersions;
return d->capabilities.roomVersions.has_value();
}

QStringList Connection::supportedMatrixSpecVersions() const { return d->apiVersions.versions; }

void Connection::Private::saveAccessTokenToKeychain() const
{
qCDebug(MAIN) << "Saving access token to keychain for" << q->userId();
Expand Down Expand Up @@ -296,14 +307,18 @@ void Connection::Private::loginToServer(LoginArgTs&&... loginArgs)
void Connection::Private::completeSetup(const QString& mxId, bool mock)
{
data->setUserId(mxId);
if (!mock)
q->user()->load(); // Load the local user's profile
q->setObjectName(data->userId() % u'/' % data->deviceId());
qCDebug(MAIN) << "Using server" << data->baseUrl().toDisplayString()
<< "by user" << data->userId()
<< "from device" << data->deviceId();
connect(qApp, &QCoreApplication::aboutToQuit, q, &Connection::saveState);

if (!mock) {
q->loadVersions();
q->loadCapabilities();
q->user()->load(); // Load the local user's profile
}

if (useEncryption) {
if (auto&& maybeEncryptionData =
_impl::ConnectionEncryptionData::setup(q, mock)) {
Expand All @@ -318,8 +333,6 @@ void Connection::Private::completeSetup(const QString& mxId, bool mock)

emit q->stateChanged();
emit q->connected();
if (!mock)
q->reloadCapabilities();
}

QFuture<void> Connection::Private::ensureHomeserver(const QString& userId,
Expand Down Expand Up @@ -741,15 +754,15 @@ JobHandle<UploadContentJob> Connection::uploadFile(const QString& fileName,
overrideContentType);
}

GetContentJob* Connection::getContent(const QString& mediaId)
BaseJob* Connection::getContent(const QString& mediaId)
{
auto idParts = splitMediaId(mediaId);
return callApi<GetContentJob>(idParts.front(), idParts.back());
return callApi<DownloadFileJob>(idParts.front(), idParts.back());
}

GetContentJob* Connection::getContent(const QUrl& url)
BaseJob* Connection::getContent(const QUrl& url)
{
return getContent(url.authority() + url.path());
QT_IGNORE_DEPRECATIONS(return getContent(url.authority() + url.path());)
}

DownloadFileJob* Connection::downloadFile(const QUrl& url, const QString& localFilename)
Expand Down Expand Up @@ -1294,6 +1307,8 @@ const ConnectionData* Connection::connectionData() const
return d->data.get();
}

HomeserverData Connection::homeserverData() const { return d->data->homeserverData(); }

Room* Connection::provideRoom(const QString& id, std::optional<JoinState> joinState)
{
// TODO: This whole function is a strong case for a RoomManager class.
Expand Down
37 changes: 26 additions & 11 deletions Quotient/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@

#include "csapi/create_room.h"
#include "csapi/login.h"
#include "csapi/content-repo.h"

#include "e2ee/qolmoutboundsession.h"

#include "events/accountdataevents.h"

#include "jobs/jobhandle.h"

#include <QtCore/QDir>
#include <QtCore/QObject>
#include <QtCore/QSize>
#include <QtCore/QUrl>
#include <QtCore/QFuture>

#include <functional>

Expand All @@ -39,15 +38,15 @@ class User;
class ConnectionData;
class RoomEvent;

class GetVersionsJob;
class GetCapabilitiesJob;
class SyncJob;
class SyncData;
class RoomMessagesJob;
class PostReceiptJob;
class ForgetRoomJob;
class MediaThumbnailJob;
class JoinRoomJob;
class UploadContentJob;
class GetContentJob;
class DownloadFileJob;
class SendToDeviceJob;
class SendMessageJob;
Expand Down Expand Up @@ -395,9 +394,15 @@ class QUOTIENT_API Connection : public QObject {
}
};

//! Find out if capabilites are still loading from the server
//! Find out if homeserver capabilites have been loaded
Q_INVOKABLE bool capabilitiesReady() const;

[[deprecated("Use capabilitiesReady() instead; don't forget to negate the returned value")]]
Q_INVOKABLE bool loadingCapabilities() const;

//! Get the list of Matrix CS API spec versions supported by the homeserver
QStringList supportedMatrixSpecVersions() const;

//! \brief Get the room version recommended by the server
//!
//! Only works after server capabilities have been loaded.
Expand Down Expand Up @@ -523,8 +528,7 @@ class QUOTIENT_API Connection : public QObject {
template <typename JobT, typename... JobArgTs>
QUrl getUrlForApi(JobArgTs&&... jobArgs) const
{
return JobT::makeRequestUrl(homeserver(),
std::forward<JobArgTs>(jobArgs)...);
return JobT::makeRequestUrl(homeserverData(), std::forward<JobArgTs>(jobArgs)...);
}

//! \brief Start a local HTTP server and generate a single sign-on URL
Expand Down Expand Up @@ -652,8 +656,15 @@ public Q_SLOTS:
//! \since 0.7.2
void assumeIdentity(const QString& mxId, const QString& accessToken);

//! Explicitly request capabilities from the server
void reloadCapabilities();
//! \brief Request supported spec versions from the homeserver
//!
//! This call does not obtain room versions - use loadCapabilities() for that.
JobHandle<GetVersionsJob> loadVersions();

//! Request capabilities and room versions from the server
JobHandle<GetCapabilitiesJob> loadCapabilities();

[[deprecated("Use loadCapabilities() instead")]] void reloadCapabilities();

QFuture<void> logout();

Expand All @@ -676,8 +687,9 @@ public Q_SLOTS:
const QString& overrideContentType = {});
JobHandle<UploadContentJob> uploadFile(const QString& fileName,
const QString& overrideContentType = {});
GetContentJob* getContent(const QString& mediaId);
GetContentJob* getContent(const QUrl& url);
[[deprecated("Use downloadFile() instead")]] BaseJob* getContent(const QString& mediaId);
[[deprecated("Use downloadFile() instead")]] BaseJob* getContent(const QUrl& url);

// If localFilename is empty, a temporary file will be created
DownloadFileJob* downloadFile(const QUrl& url, const QString& localFilename = {});

Expand Down Expand Up @@ -910,6 +922,9 @@ public Q_SLOTS:
//! Access the underlying ConnectionData class
const ConnectionData* connectionData() const;

//! Get the homeserver data necessary to construct network requests
HomeserverData homeserverData() const;

//! \brief Get a Room object for the given id in the given state
//!
//! Use this method when you need a Room object in the local list
Expand Down
8 changes: 4 additions & 4 deletions Quotient/connection_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
#include "settings.h"
#include "syncdata.h"

#include "csapi/account-data.h"
#include "csapi/capabilities.h"
#include "csapi/logout.h"
#include "csapi/versions.h"
#include "csapi/wellknown.h"

#include "csapi/account-data.h"

#include <QtCore/QCoreApplication>

namespace Quotient {
Expand Down Expand Up @@ -51,8 +51,8 @@ class Q_DECL_HIDDEN Quotient::Connection::Private {
QMetaObject::Connection syncLoopConnection {};
int syncTimeout = -1;

GetCapabilitiesJob* capabilitiesJob = nullptr;
GetCapabilitiesJob::Capabilities capabilities;
GetVersionsJob::Response apiVersions{};
GetCapabilitiesJob::Capabilities capabilities{};

QVector<GetLoginFlowsJob::LoginFlow> loginFlows;

Expand Down
26 changes: 22 additions & 4 deletions Quotient/connectiondata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class ConnectionData::Private {
QString lastEvent;
QString userId;
QString deviceId;
QStringList supportedSpecVersions;
std::vector<QString> needToken;

mutable unsigned int txnCounter = 0;
Expand Down Expand Up @@ -102,6 +103,11 @@ QByteArray ConnectionData::accessToken() const { return d->accessToken; }

QUrl ConnectionData::baseUrl() const { return d->baseUrl; }

HomeserverData ConnectionData::homeserverData() const
{
return { d->baseUrl, d->supportedSpecVersions };
}

NetworkAccessManager* ConnectionData::nam() const
{
return NetworkAccessManager::instance();
Expand All @@ -111,8 +117,12 @@ void ConnectionData::setBaseUrl(QUrl baseUrl)
{
d->baseUrl = std::move(baseUrl);
qCDebug(MAIN) << "updated baseUrl to" << d->baseUrl;
if (!d->userId.isEmpty() && d->baseUrl.isValid())
NetworkAccessManager::addBaseUrl(d->userId, d->baseUrl);
if (!d->userId.isEmpty()) {
if (d->baseUrl.isValid())
NetworkAccessManager::addAccount(d->userId, d->baseUrl);
else
NetworkAccessManager::dropAccount(d->userId);
}
}

void ConnectionData::setToken(QByteArray token)
Expand All @@ -139,9 +149,9 @@ void ConnectionData::setUserId(const QString& userId)
{
if (d->baseUrl.isValid()) {
if (d->userId != userId)
NetworkAccessManager::dropBaseUrl(d->userId);
NetworkAccessManager::dropAccount(d->userId);
if (!userId.isEmpty())
NetworkAccessManager::addBaseUrl(userId, d->baseUrl);
NetworkAccessManager::addAccount(userId, d->baseUrl);
}
d->userId = userId;
}
Expand All @@ -151,6 +161,14 @@ void ConnectionData::setNeedsToken(const QString& requestName)
d->needToken.push_back(requestName);
}

void ConnectionData::setSupportedSpecVersions(QStringList versions)
{
qCInfo(MAIN).noquote() << "CS API versions:" << versions.join(u' ');
d->supportedSpecVersions = std::move(versions);
if (!ALARM(d->userId.isEmpty()) && !ALARM(!d->baseUrl.isValid()))
NetworkAccessManager::updateAccountSpecVersions(d->userId, d->supportedSpecVersions);
}

QString ConnectionData::lastEvent() const { return d->lastEvent; }

void ConnectionData::setLastEvent(QString identifier)
Expand Down
2 changes: 2 additions & 0 deletions Quotient/connectiondata.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ class QUOTIENT_API ConnectionData {
const QString& deviceId() const;
const QString& userId() const;
bool needsToken(const QString& requestName) const;
HomeserverData homeserverData() const;
Quotient::NetworkAccessManager *nam() const;

void setBaseUrl(QUrl baseUrl);
void setToken(QByteArray accessToken);
void setDeviceId(const QString& deviceId);
void setUserId(const QString& userId);
void setNeedsToken(const QString& requestName);
void setSupportedSpecVersions(QStringList versions);

QString lastEvent() const;
void setLastEvent(QString identifier);
Expand Down
14 changes: 7 additions & 7 deletions Quotient/csapi/account-data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ SetAccountDataJob::SetAccountDataJob(const QString& userId, const QString& type,
setRequestData({ toJson(content) });
}

QUrl GetAccountDataJob::makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& type)
QUrl GetAccountDataJob::makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl), makePath("/_matrix/client/v3", "/user/",
userId, "/account_data/", type));
return BaseJob::makeRequestUrl(hsData, makePath("/_matrix/client/v3", "/user/", userId,
"/account_data/", type));
}

GetAccountDataJob::GetAccountDataJob(const QString& userId, const QString& type)
Expand All @@ -32,12 +33,11 @@ SetAccountDataPerRoomJob::SetAccountDataPerRoomJob(const QString& userId, const
setRequestData({ toJson(content) });
}

QUrl GetAccountDataPerRoomJob::makeRequestUrl(QUrl baseUrl, const QString& userId,
QUrl GetAccountDataPerRoomJob::makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& roomId, const QString& type)
{
return BaseJob::makeRequestUrl(std::move(baseUrl),
makePath("/_matrix/client/v3", "/user/", userId, "/rooms/",
roomId, "/account_data/", type));
return BaseJob::makeRequestUrl(hsData, makePath("/_matrix/client/v3", "/user/", userId,
"/rooms/", roomId, "/account_data/", type));
}

GetAccountDataPerRoomJob::GetAccountDataPerRoomJob(const QString& userId, const QString& roomId,
Expand Down
7 changes: 4 additions & 3 deletions Quotient/csapi/account-data.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ class QUOTIENT_API GetAccountDataJob : public BaseJob {
//!
//! This function can be used when a URL for GetAccountDataJob
//! is necessary but the job itself isn't.
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& type);
static QUrl makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& type);

// Result properties

Expand Down Expand Up @@ -104,8 +105,8 @@ class QUOTIENT_API GetAccountDataPerRoomJob : public BaseJob {
//!
//! This function can be used when a URL for GetAccountDataPerRoomJob
//! is necessary but the job itself isn't.
static QUrl makeRequestUrl(QUrl baseUrl, const QString& userId, const QString& roomId,
const QString& type);
static QUrl makeRequestUrl(const HomeserverData& hsData, const QString& userId,
const QString& roomId, const QString& type);

// Result properties

Expand Down
Loading