aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2017-11-26 10:21:55 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2017-11-26 10:21:55 +0900
commitca1d23cf72d4f902dc2da6be0faf93774a6c5583 (patch)
tree4d1264fcf395e48c5c7f21eb0c784ace3dd59f3c
parentab3680f61222a1e915cf6fc4e14f6892c9c99341 (diff)
downloadlibquotient-ca1d23cf72d4f902dc2da6be0faf93774a6c5583.tar.gz
libquotient-ca1d23cf72d4f902dc2da6be0faf93774a6c5583.zip
Make connectToServer/connectWithToken auto-resolve HS if needed
"Needed" means when the current HS URL is invalid even by its outlooks. If it is just inaccessible, no attempt to fix things will be made. This breaks compatibility with previous library behaviour because connectWithToken historically has been fully synchronous and clients depend on that. connectWithToken _may_ work synchronously if HS URL is good enough; but this is no more guaranteed. Moreover, in the future the server will be probed via /versions before working, so connectWithToken will become entirely asynchronous.
-rw-r--r--connection.cpp83
-rw-r--r--connection.h25
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;
};