summary refs log tree commit diff
path: root/src/Cache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/Cache.cc')
-rw-r--r--src/Cache.cc283
1 files changed, 148 insertions, 135 deletions
diff --git a/src/Cache.cc b/src/Cache.cc
index a9699276..01df492c 100644
--- a/src/Cache.cc
+++ b/src/Cache.cc
@@ -37,194 +37,207 @@ Cache::Cache(const QString &userId)
   , isMounted_{ false }
   , userId_{ userId }
 {
-	auto statePath = QString("%1/%2/state")
-				 .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
-				 .arg(QString::fromUtf8(userId_.toUtf8().toHex()));
+        auto statePath = QString("%1/%2/state")
+                           .arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
+                           .arg(QString::fromUtf8(userId_.toUtf8().toHex()));
 
-	bool isInitial = !QFile::exists(statePath);
+        bool isInitial = !QFile::exists(statePath);
 
-	env_ = lmdb::env::create();
-	env_.set_mapsize(128UL * 1024UL * 1024UL); /* 128 MB */
-	env_.set_max_dbs(1024UL);
+        env_ = lmdb::env::create();
+        env_.set_mapsize(128UL * 1024UL * 1024UL); /* 128 MB */
+        env_.set_max_dbs(1024UL);
 
-	if (isInitial) {
-		qDebug() << "[cache] First time initializing LMDB";
+        if (isInitial) {
+                qDebug() << "[cache] First time initializing LMDB";
 
-		if (!QDir().mkpath(statePath)) {
-			throw std::runtime_error(
-				("Unable to create state directory:" + statePath).toStdString().c_str());
-		}
-	}
+                if (!QDir().mkpath(statePath)) {
+                        throw std::runtime_error(
+                          ("Unable to create state directory:" + statePath).toStdString().c_str());
+                }
+        }
 
-	try {
-		env_.open(statePath.toStdString().c_str());
-	} catch (const lmdb::error &e) {
-		if (e.code() != MDB_VERSION_MISMATCH && e.code() != MDB_INVALID) {
-			throw std::runtime_error("LMDB initialization failed" + std::string(e.what()));
-		}
+        try {
+                env_.open(statePath.toStdString().c_str());
+        } catch (const lmdb::error &e) {
+                if (e.code() != MDB_VERSION_MISMATCH && e.code() != MDB_INVALID) {
+                        throw std::runtime_error("LMDB initialization failed" +
+                                                 std::string(e.what()));
+                }
 
-		qWarning() << "Resetting cache due to LMDB version mismatch:" << e.what();
+                qWarning() << "Resetting cache due to LMDB version mismatch:" << e.what();
 
-		QDir stateDir(statePath);
+                QDir stateDir(statePath);
 
-		for (const auto &file : stateDir.entryList(QDir::NoDotAndDotDot)) {
-			if (!stateDir.remove(file))
-				throw std::runtime_error(("Unable to delete file " + file).toStdString().c_str());
-		}
+                for (const auto &file : stateDir.entryList(QDir::NoDotAndDotDot)) {
+                        if (!stateDir.remove(file))
+                                throw std::runtime_error(
+                                  ("Unable to delete file " + file).toStdString().c_str());
+                }
 
-		env_.open(statePath.toStdString().c_str());
-	}
+                env_.open(statePath.toStdString().c_str());
+        }
 
-	auto txn = lmdb::txn::begin(env_);
-	stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
-	roomDb_ = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
+        auto txn = lmdb::txn::begin(env_);
+        stateDb_ = lmdb::dbi::open(txn, "state", MDB_CREATE);
+        roomDb_  = lmdb::dbi::open(txn, "rooms", MDB_CREATE);
 
-	txn.commit();
+        txn.commit();
 
-	isMounted_ = true;
+        isMounted_ = true;
 }
 
 void
-Cache::insertRoomState(const QString &roomid, const RoomState &state)
+Cache::setState(const QString &nextBatchToken, const QMap<QString, RoomState> &states)
 {
-	if (!isMounted_)
-		return;
-
-	auto txn = lmdb::txn::begin(env_);
-
-	auto stateEvents = QJsonDocument(state.serialize()).toBinaryData();
-	auto id = roomid.toUtf8();
-
-	lmdb::dbi_put(txn, roomDb_, lmdb::val(id.data(), id.size()), lmdb::val(stateEvents.data(), stateEvents.size()));
-
-	for (const auto &membership : state.memberships) {
-		lmdb::dbi membersDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
-
-		// The user_id this membership event relates to, is used
-		// as the index on the membership database.
-		auto key = membership.stateKey().toUtf8();
-		auto memberEvent = QJsonDocument(membership.serialize()).toBinaryData();
-
-		switch (membership.content().membershipState()) {
-		// We add or update (e.g invite -> join) a new user to the membership list.
-		case events::Membership::Invite:
-		case events::Membership::Join: {
-			lmdb::dbi_put(txn,
-				      membersDb,
-				      lmdb::val(key.data(), key.size()),
-				      lmdb::val(memberEvent.data(), memberEvent.size()));
-			break;
-		}
-		// We remove the user from the membership list.
-		case events::Membership::Leave:
-		case events::Membership::Ban: {
-			lmdb::dbi_del(txn,
-				      membersDb,
-				      lmdb::val(key.data(), key.size()),
-				      lmdb::val(memberEvent.data(), memberEvent.size()));
-			break;
-		}
-		case events::Membership::Knock: {
-			qWarning() << "Skipping knock membership" << roomid << key;
-			break;
-		}
-		}
-	}
-
-	txn.commit();
+        if (!isMounted_)
+                return;
+
+        auto txn = lmdb::txn::begin(env_);
+
+        setNextBatchToken(txn, nextBatchToken);
+
+        for (auto it = states.constBegin(); it != states.constEnd(); it++)
+                insertRoomState(txn, it.key(), it.value());
+
+        txn.commit();
+}
+
+void
+Cache::insertRoomState(lmdb::txn &txn, const QString &roomid, const RoomState &state)
+{
+        auto stateEvents = QJsonDocument(state.serialize()).toBinaryData();
+        auto id          = roomid.toUtf8();
+
+        lmdb::dbi_put(txn,
+                      roomDb_,
+                      lmdb::val(id.data(), id.size()),
+                      lmdb::val(stateEvents.data(), stateEvents.size()));
+
+        for (const auto &membership : state.memberships) {
+                lmdb::dbi membersDb =
+                  lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
+
+                // The user_id this membership event relates to, is used
+                // as the index on the membership database.
+                auto key         = membership.stateKey().toUtf8();
+                auto memberEvent = QJsonDocument(membership.serialize()).toBinaryData();
+
+                switch (membership.content().membershipState()) {
+                // We add or update (e.g invite -> join) a new user to the membership list.
+                case events::Membership::Invite:
+                case events::Membership::Join: {
+                        lmdb::dbi_put(txn,
+                                      membersDb,
+                                      lmdb::val(key.data(), key.size()),
+                                      lmdb::val(memberEvent.data(), memberEvent.size()));
+                        break;
+                }
+                // We remove the user from the membership list.
+                case events::Membership::Leave:
+                case events::Membership::Ban: {
+                        lmdb::dbi_del(txn,
+                                      membersDb,
+                                      lmdb::val(key.data(), key.size()),
+                                      lmdb::val(memberEvent.data(), memberEvent.size()));
+                        break;
+                }
+                case events::Membership::Knock: {
+                        qWarning() << "Skipping knock membership" << roomid << key;
+                        break;
+                }
+                }
+        }
 }
 
 QMap<QString, RoomState>
 Cache::states()
 {
-	QMap<QString, RoomState> states;
+        QMap<QString, RoomState> states;
 
-	auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
-	auto cursor = lmdb::cursor::open(txn, roomDb_);
+        auto txn    = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+        auto cursor = lmdb::cursor::open(txn, roomDb_);
 
-	std::string room;
-	std::string stateData;
+        std::string room;
+        std::string stateData;
 
-	// Retrieve all the room names.
-	while (cursor.get(room, stateData, MDB_NEXT)) {
-		auto roomid = QString::fromUtf8(room.data(), room.size());
-		auto json = QJsonDocument::fromBinaryData(QByteArray(stateData.data(), stateData.size()));
+        // Retrieve all the room names.
+        while (cursor.get(room, stateData, MDB_NEXT)) {
+                auto roomid = QString::fromUtf8(room.data(), room.size());
+                auto json =
+                  QJsonDocument::fromBinaryData(QByteArray(stateData.data(), stateData.size()));
 
-		RoomState state;
-		state.parse(json.object());
+                RoomState state;
+                state.parse(json.object());
 
-		auto memberDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
-		QMap<QString, events::StateEvent<events::MemberEventContent>> members;
+                auto memberDb = lmdb::dbi::open(txn, roomid.toStdString().c_str(), MDB_CREATE);
+                QMap<QString, events::StateEvent<events::MemberEventContent>> members;
 
-		auto memberCursor = lmdb::cursor::open(txn, memberDb);
+                auto memberCursor = lmdb::cursor::open(txn, memberDb);
 
-		std::string memberId;
-		std::string memberContent;
+                std::string memberId;
+                std::string memberContent;
 
-		while (memberCursor.get(memberId, memberContent, MDB_NEXT)) {
-			auto userid = QString::fromUtf8(memberId.data(), memberId.size());
-			auto data =
-				QJsonDocument::fromBinaryData(QByteArray(memberContent.data(), memberContent.size()));
+                while (memberCursor.get(memberId, memberContent, MDB_NEXT)) {
+                        auto userid = QString::fromUtf8(memberId.data(), memberId.size());
+                        auto data   = QJsonDocument::fromBinaryData(
+                          QByteArray(memberContent.data(), memberContent.size()));
 
-			try {
-				events::StateEvent<events::MemberEventContent> member;
-				member.deserialize(data.object());
-				members.insert(userid, member);
-			} catch (const DeserializationException &e) {
-				qWarning() << e.what();
-				qWarning() << "Fault while parsing member event" << data.object();
-				continue;
-			}
-		}
+                        try {
+                                events::StateEvent<events::MemberEventContent> member;
+                                member.deserialize(data.object());
+                                members.insert(userid, member);
+                        } catch (const DeserializationException &e) {
+                                qWarning() << e.what();
+                                qWarning() << "Fault while parsing member event" << data.object();
+                                continue;
+                        }
+                }
 
-		qDebug() << members.size() << "members for" << roomid;
+                qDebug() << members.size() << "members for" << roomid;
 
-		state.memberships = members;
-		states.insert(roomid, state);
-	}
+                state.memberships = members;
+                states.insert(roomid, state);
+        }
 
-	qDebug() << "Retrieved" << states.size() << "rooms";
+        qDebug() << "Retrieved" << states.size() << "rooms";
 
-	cursor.close();
+        cursor.close();
 
-	txn.commit();
+        txn.commit();
 
-	return states;
+        return states;
 }
 
 void
-Cache::setNextBatchToken(const QString &token)
+Cache::setNextBatchToken(lmdb::txn &txn, const QString &token)
 {
-	auto txn = lmdb::txn::begin(env_);
-	auto value = token.toUtf8();
-
-	lmdb::dbi_put(txn, stateDb_, NEXT_BATCH_KEY, lmdb::val(value.data(), value.size()));
+        auto value = token.toUtf8();
 
-	txn.commit();
+        lmdb::dbi_put(txn, stateDb_, NEXT_BATCH_KEY, lmdb::val(value.data(), value.size()));
 }
 
 bool
-Cache::isInitialized()
+Cache::isInitialized() const
 {
-	auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
-	lmdb::val token;
+        auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+        lmdb::val token;
 
-	bool res = lmdb::dbi_get(txn, stateDb_, NEXT_BATCH_KEY, token);
+        bool res = lmdb::dbi_get(txn, stateDb_, NEXT_BATCH_KEY, token);
 
-	txn.commit();
+        txn.commit();
 
-	return res;
+        return res;
 }
 
 QString
-Cache::nextBatchToken()
+Cache::nextBatchToken() const
 {
-	auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
-	lmdb::val token;
+        auto txn = lmdb::txn::begin(env_, nullptr, MDB_RDONLY);
+        lmdb::val token;
 
-	lmdb::dbi_get(txn, stateDb_, NEXT_BATCH_KEY, token);
+        lmdb::dbi_get(txn, stateDb_, NEXT_BATCH_KEY, token);
 
-	txn.commit();
+        txn.commit();
 
-	return QString::fromUtf8(token.data(), token.size());
+        return QString::fromUtf8(token.data(), token.size());
 }