diff options
-rw-r--r-- | connection.cpp | 83 | ||||
-rw-r--r-- | connection.h | 25 |
2 files changed, 89 insertions, 19 deletions
diff --git a/connection.cpp b/connection.cpp index bb9cdd32..78ef9754 100644 --- a/connection.cpp +++ b/connection.cpp @@ -65,6 +65,9 @@ class Connection::Private SyncJob* syncJob = nullptr; bool cacheState = true; + + void connectWithToken(const QString& user, const QString& accessToken, + const QString& deviceId); }; Connection::Connection(const QUrl& server, QObject* parent) @@ -123,7 +126,6 @@ void Connection::resolveServer(const QString& mxidOrDomain) dns->setType(QDnsLookup::SRV); dns->setName("_matrix._tcp." + domain); - dns->lookup(); connect(dns, &QDnsLookup::finished, [this,dns,maybeBaseUrl]() { QUrl baseUrl { maybeBaseUrl }; if (dns->error() == QDnsLookup::NoError && @@ -142,33 +144,81 @@ void Connection::resolveServer(const QString& mxidOrDomain) emit resolved(); dns->deleteLater(); }); + dns->lookup(); } void Connection::connectToServer(const QString& user, const QString& password, const QString& initialDeviceName, const QString& deviceId) { - auto loginJob = callApi<LoginJob>(QStringLiteral("m.login.password"), user, - /*medium*/ "", /*address*/ "", password, /*token*/ "", + checkAndConnect(user, + [=] { + doConnectToServer(user, password, initialDeviceName, deviceId); + }); +} +void Connection::doConnectToServer(const QString& user, const QString& password, + const QString& initialDeviceName, + const QString& deviceId) +{ + auto loginJob = callApi<LoginJob>(QStringLiteral("m.login.password"), + user, /*medium*/ "", /*address*/ "", password, /*token*/ "", deviceId, initialDeviceName); - connect( loginJob, &BaseJob::success, [=] () { - connectWithToken(loginJob->user_id(), loginJob->access_token(), - loginJob->device_id()); - }); - connect( loginJob, &BaseJob::failure, [=] () { - emit loginError(loginJob->errorString()); - }); + connect(loginJob, &BaseJob::success, this, + [=] { + d->connectWithToken(loginJob->user_id(), loginJob->access_token(), + loginJob->device_id()); + }); + connect(loginJob, &BaseJob::failure, this, + [=] { + emit loginError(loginJob->errorString()); + }); } void Connection::connectWithToken(const QString& userId, - const QString& accessToken, const QString& deviceId) + const QString& accessToken, + const QString& deviceId) +{ + checkAndConnect(userId, + [=] { d->connectWithToken(userId, accessToken, deviceId); }); +} + +void Connection::Private::connectWithToken(const QString& user, + const QString& accessToken, + const QString& deviceId) { - d->userId = userId; - d->data->setToken(accessToken.toLatin1()); - d->data->setDeviceId(deviceId); - qCDebug(MAIN) << "Using server" << d->data->baseUrl() << "by user" << userId + userId = user; + data->setToken(accessToken.toLatin1()); + data->setDeviceId(deviceId); + qCDebug(MAIN) << "Using server" << data->baseUrl() << "by user" + << userId << "from device" << deviceId; - emit connected(); + emit q->connected(); + +} + +void Connection::checkAndConnect(const QString& userId, + std::function<void()> connectFn) +{ + if (d->data->baseUrl().isValid()) + { + connectFn(); + return; + } + // Not good to go, try to fix the homeserver URL. + if (userId.startsWith('@') && userId.indexOf(':') != -1) + { + // The below construct makes a single-shot connection that triggers + // on the signal and then self-disconnects. + // NB: doResolveServer can emit resolveError, so this is a part of + // checkAndConnect function contract. + QMetaObject::Connection connection; + connection = connect(this, &Connection::homeserverChanged, + this, [=] { connectFn(); disconnect(connection); }); + resolveServer(userId); + } else + emit resolveError( + tr("%1 is an invalid homeserver URL") + .arg(d->data->baseUrl().toString())); } void Connection::logout() @@ -565,3 +615,4 @@ void Connection::setCacheState(bool newValue) emit cacheStateChanged(); } } + diff --git a/connection.h b/connection.h index 999dcd71..256dbd5f 100644 --- a/connection.h +++ b/connection.h @@ -27,6 +27,8 @@ #include <functional> +class QDnsLookup; + namespace QMatrixClient { class Room; @@ -162,10 +164,10 @@ namespace QMatrixClient void resolveServer(const QString& mxidOrDomain); void connectToServer(const QString& user, const QString& password, - const QString& initialDeviceName, - const QString& deviceId = {}); + const QString& initialDeviceName, + const QString& deviceId = {}); void connectWithToken(const QString& userId, const QString& accessToken, - const QString& deviceId); + const QString& deviceId); /** @deprecated Use stopSync() instead */ void disconnectFromServer() { stopSync(); } @@ -307,6 +309,23 @@ namespace QMatrixClient class Private; Private* d; + /** + * A single entry for functions that need to check whether the + * homeserver is valid before running. May either execute connectFn + * synchronously or asynchronously (if tryResolve is true and + * a DNS lookup is initiated); in case of errors, emits resolveError + * if the homeserver URL is not valid and cannot be resolved from + * userId. + * + * @param userId - fully-qualified MXID to resolve HS from + * @param connectFn - a function to execute once the HS URL is good + */ + void checkAndConnect(const QString& userId, + std::function<void()> connectFn); + void doConnectToServer(const QString& user, const QString& password, + const QString& initialDeviceName, + const QString& deviceId = {}); + static room_factory_t createRoom; static user_factory_t createUser; }; |