aboutsummaryrefslogtreecommitdiff
path: root/lib/connection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/connection.cpp')
-rw-r--r--lib/connection.cpp133
1 files changed, 53 insertions, 80 deletions
diff --git a/lib/connection.cpp b/lib/connection.cpp
index 3d635a7e..9372acd5 100644
--- a/lib/connection.cpp
+++ b/lib/connection.cpp
@@ -39,7 +39,6 @@
#include <QtNetwork/QDnsLookup>
#include <QtCore/QFile>
#include <QtCore/QDir>
-#include <QtCore/QFileInfo>
#include <QtCore/QStandardPaths>
#include <QtCore/QStringBuilder>
#include <QtCore/QElapsedTimer>
@@ -65,10 +64,6 @@ HashT erase_if(HashT& hashMap, Pred pred)
return removals;
}
-#ifndef TRIM_RAW_DATA
-#define TRIM_RAW_DATA 65535
-#endif
-
class Connection::Private
{
public:
@@ -228,8 +223,7 @@ void Connection::doConnectToServer(const QString& user, const QString& password,
});
connect(loginJob, &BaseJob::failure, this,
[this, loginJob] {
- emit loginError(loginJob->errorString(),
- loginJob->rawData(TRIM_RAW_DATA));
+ emit loginError(loginJob->errorString(), loginJob->rawDataSample());
});
}
@@ -306,7 +300,7 @@ void Connection::sync(int timeout)
connect( job, &SyncJob::retryScheduled, this,
[this,job] (int retriesTaken, int nextInMilliseconds)
{
- emit networkError(job->errorString(), job->rawData(TRIM_RAW_DATA),
+ emit networkError(job->errorString(), job->rawDataSample(),
retriesTaken, nextInMilliseconds);
});
connect( job, &SyncJob::failure, this, [this, job] {
@@ -315,14 +309,14 @@ void Connection::sync(int timeout)
{
qCWarning(SYNCJOB)
<< "Sync job failed with ContentAccessError - login expired?";
- emit loginError(job->errorString(), job->rawData(TRIM_RAW_DATA));
+ emit loginError(job->errorString(), job->rawDataSample());
}
else
- emit syncError(job->errorString(), job->rawData(TRIM_RAW_DATA));
+ emit syncError(job->errorString(), job->rawDataSample());
});
}
-void Connection::onSyncSuccess(SyncData &&data) {
+void Connection::onSyncSuccess(SyncData &&data, bool fromCache) {
d->data->setLastEvent(data.nextBatch());
for (auto&& roomData: data.takeRoomData())
{
@@ -343,7 +337,7 @@ void Connection::onSyncSuccess(SyncData &&data) {
}
if ( auto* r = provideRoom(roomData.roomId, roomData.joinState) )
{
- r->updateData(std::move(roomData));
+ r->updateData(std::move(roomData), fromCache);
if (d->firstTimeRooms.removeOne(r))
emit loadedRoomState(r);
}
@@ -422,9 +416,10 @@ PostReceiptJob* Connection::postReceipt(Room* room, RoomEvent* event) const
return callApi<PostReceiptJob>(room->id(), "m.read", event->id());
}
-JoinRoomJob* Connection::joinRoom(const QString& roomAlias)
+JoinRoomJob* Connection::joinRoom(const QString& roomAlias,
+ const QStringList& serverNames)
{
- auto job = callApi<JoinRoomJob>(roomAlias);
+ auto job = callApi<JoinRoomJob>(roomAlias, serverNames);
connect(job, &JoinRoomJob::success,
this, [this, job] { provideRoom(job->roomId(), JoinState::Join); });
return job;
@@ -1063,47 +1058,54 @@ void Connection::setHomeserver(const QUrl& url)
emit homeserverChanged(homeserver());
}
-static constexpr int CACHE_VERSION_MAJOR = 8;
-static constexpr int CACHE_VERSION_MINOR = 0;
+void Connection::saveRoomState(Room* r) const
+{
+ Q_ASSERT(r);
+ if (!d->cacheState)
+ return;
+
+ QFile outRoomFile { stateCachePath() % SyncData::fileNameForRoom(r->id()) };
+ if (outRoomFile.open(QFile::WriteOnly))
+ {
+ QJsonDocument json { r->toJson() };
+ auto data = d->cacheToBinary ? json.toBinaryData()
+ : json.toJson(QJsonDocument::Compact);
+ outRoomFile.write(data.data(), data.size());
+ qCDebug(MAIN) << "Room state cache saved to" << outRoomFile.fileName();
+ } else {
+ qCWarning(MAIN) << "Error opening" << outRoomFile.fileName()
+ << ":" << outRoomFile.errorString();
+ }
+}
-void Connection::saveState(const QUrl &toFile) const
+void Connection::saveState() const
{
if (!d->cacheState)
return;
QElapsedTimer et; et.start();
- QFileInfo stateFile {
- toFile.isEmpty() ? stateCachePath() : toFile.toLocalFile()
- };
- if (!stateFile.dir().exists())
- stateFile.dir().mkpath(".");
-
- QFile outfile { stateFile.absoluteFilePath() };
- if (!outfile.open(QFile::WriteOnly))
+ QFile outFile { stateCachePath() % "state.json" };
+ if (!outFile.open(QFile::WriteOnly))
{
- qCWarning(MAIN) << "Error opening" << stateFile.absoluteFilePath()
- << ":" << outfile.errorString();
+ qCWarning(MAIN) << "Error opening" << outFile.fileName()
+ << ":" << outFile.errorString();
qCWarning(MAIN) << "Caching the rooms state disabled";
d->cacheState = false;
return;
}
- QJsonObject rootObj;
+ QJsonObject rootObj {
+ { QStringLiteral("cache_version"), QJsonObject {
+ { QStringLiteral("major"), SyncData::cacheVersion().first },
+ { QStringLiteral("minor"), SyncData::cacheVersion().second }
+ }}};
{
QJsonObject rooms;
QJsonObject inviteRooms;
for (const auto* i : roomMap()) // Pass on rooms in Leave state
- {
- if (i->joinState() == JoinState::Invite)
- inviteRooms.insert(i->id(), i->toJson());
- else
- rooms.insert(i->id(), i->toJson());
- QElapsedTimer et1; et1.start();
- QCoreApplication::processEvents();
- if (et1.elapsed() > 1)
- qCDebug(PROFILER) << "processEvents() borrowed" << et1;
- }
+ (i->joinState() == JoinState::Invite ? inviteRooms : rooms)
+ .insert(i->id(), QJsonValue::Null);
QJsonObject roomObj;
if (!rooms.isEmpty())
@@ -1126,63 +1128,35 @@ void Connection::saveState(const QUrl &toFile) const
QJsonObject {{ QStringLiteral("events"), accountDataEvents }});
}
- QJsonObject versionObj;
- versionObj.insert("major", CACHE_VERSION_MAJOR);
- versionObj.insert("minor", CACHE_VERSION_MINOR);
- rootObj.insert("cache_version", versionObj);
-
QJsonDocument json { rootObj };
auto data = d->cacheToBinary ? json.toBinaryData() :
json.toJson(QJsonDocument::Compact);
qCDebug(PROFILER) << "Cache for" << userId() << "generated in" << et;
- outfile.write(data.data(), data.size());
- qCDebug(MAIN) << "State cache saved to" << outfile.fileName();
+ outFile.write(data.data(), data.size());
+ qCDebug(MAIN) << "State cache saved to" << outFile.fileName();
}
-void Connection::loadState(const QUrl &fromFile)
+void Connection::loadState()
{
if (!d->cacheState)
return;
QElapsedTimer et; et.start();
- QFile file {
- fromFile.isEmpty() ? stateCachePath() : fromFile.toLocalFile()
- };
- if (!file.exists())
- {
- qCDebug(MAIN) << "No state cache file found";
- return;
- }
- if(!file.open(QFile::ReadOnly))
- {
- qCWarning(MAIN) << "file " << file.fileName() << "failed to open for read";
- return;
- }
- QByteArray data = file.readAll();
- auto jsonDoc = d->cacheToBinary ? QJsonDocument::fromBinaryData(data) :
- QJsonDocument::fromJson(data);
- if (jsonDoc.isNull())
- {
- qCWarning(MAIN) << "Cache file broken, discarding";
+ SyncData sync { stateCachePath() % "state.json" };
+ if (sync.nextBatch().isEmpty()) // No token means no cache by definition
return;
- }
- auto actualCacheVersionMajor =
- jsonDoc.object()
- .value("cache_version").toObject()
- .value("major").toInt();
- if (actualCacheVersionMajor < CACHE_VERSION_MAJOR)
+
+ if (!sync.unresolvedRooms().isEmpty())
{
- qCWarning(MAIN)
- << "Major version of the cache file is" << actualCacheVersionMajor
- << "but" << CACHE_VERSION_MAJOR << "required; discarding the cache";
+ qCWarning(MAIN) << "State cache incomplete, discarding";
return;
}
-
- SyncData sync;
- sync.parseJson(jsonDoc);
- onSyncSuccess(std::move(sync));
+ // TODO: to handle load failures, instead of the above block:
+ // 1. Do initial sync on failed rooms without saving the nextBatch token
+ // 2. Do the sync across all rooms as normal
+ onSyncSuccess(std::move(sync), true);
qCDebug(PROFILER) << "*** Cached state for" << userId() << "loaded in" << et;
}
@@ -1190,8 +1164,7 @@ QString Connection::stateCachePath() const
{
auto safeUserId = userId();
safeUserId.replace(':', '_');
- return QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- % '/' % safeUserId % "_state.json";
+ return cacheLocation(safeUserId);
}
bool Connection::cacheState() const