squawk/core/components/urlstorage.cpp

290 lines
7.9 KiB
C++

/*
* Squawk messenger.
* Copyright (C) 2019 Yury Gubich <blue@macaw.me>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QStandardPaths>
#include <QDir>
#include <QDebug>
#include "urlstorage.h"
Core::UrlStorage::UrlStorage(const QString& p_name):
base(p_name),
urlToInfo(base.addStorage<QString, UrlInfo>("urlToInfo")),
pathToUrl(base.addStorage<QString, QString>("pathToUrl"))
{}
Core::UrlStorage::~UrlStorage() {
close();
}
void Core::UrlStorage::open() {
base.open();
}
void Core::UrlStorage::close() {
base.close();
}
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, bool overwrite) {
LMDBAL::TransactionID txn = base.beginTransaction();
try {
writeInfo(key, info, txn, overwrite);
base.commitTransaction(txn);
} catch (...) {
base.abortTransaction(txn);
throw;
}
}
void Core::UrlStorage::writeInfo(const QString& key, const Core::UrlStorage::UrlInfo& info, MDB_txn* txn, bool overwrite) {
if (overwrite)
urlToInfo->forceRecord(key, info, txn);
else
urlToInfo->addRecord(key, info, txn);
if (info.hasPath())
pathToUrl->forceRecord(info.getPath(), key, txn);
}
void Core::UrlStorage::addFile(const QString& url) {
addToInfo(url, "", "", "");
}
void Core::UrlStorage::addFile(const QString& url, const QString& path) {
addToInfo(url, "", "", "", path);
}
void Core::UrlStorage::addFile(const QString& url, const QString& account, const QString& jid, const QString& id) {
addToInfo(url, account, jid, id);
}
void Core::UrlStorage::addFile(const QString& url, const QString& path, const QString& account, const QString& jid, const QString& id) {
addToInfo(url, account, jid, id, path);
}
void Core::UrlStorage::addFile(const std::list<Shared::MessageInfo>& msgs, const QString& url, const QString& path) {
UrlInfo info (path, msgs);
writeInfo(url, info, true);
}
QString Core::UrlStorage::addMessageAndCheckForPath(const QString& url, const QString& account, const QString& jid, const QString& id){
return addToInfo(url, account, jid, id).getPath();
}
Core::UrlStorage::UrlInfo Core::UrlStorage::addToInfo(
const QString& url,
const QString& account,
const QString& jid,
const QString& id,
const QString& path
) {
UrlInfo info;
LMDBAL::TransactionID txn = base.beginTransaction();
try {
urlToInfo->getRecord(url, info, txn);
} catch (const LMDBAL::NotFound& e) {
} catch (...) {
base.abortTransaction(txn);
throw;
}
bool pathChange = false;
bool listChange = false;
if (path != "-s") {
if (info.getPath() != path) {
info.setPath(path);
pathChange = true;
}
}
if (account.size() > 0 && jid.size() > 0 && id.size() > 0)
listChange = info.addMessage(account, jid, id);
if (pathChange || listChange) {
try {
writeInfo(url, info, txn, true);
base.commitTransaction(txn);
} catch (...) {
base.abortTransaction(txn);
throw;
}
} else {
base.abortTransaction(txn);
}
return info;
}
std::list<Shared::MessageInfo> Core::UrlStorage::setPath(const QString& url, const QString& path) {
std::list<Shared::MessageInfo> list;
LMDBAL::TransactionID txn = base.beginTransaction();
UrlInfo info;
try {
urlToInfo->getRecord(url, info, txn);
info.getMessages(list);
} catch (const LMDBAL::NotFound& e) {
} catch (...) {
base.abortTransaction(txn);
throw;
}
info.setPath(path);
try {
writeInfo(url, info, txn, true);
base.commitTransaction(txn);
} catch (...) {
base.abortTransaction(txn);
throw;
}
return list;
}
std::list<Shared::MessageInfo> Core::UrlStorage::removeFile(const QString& url) {
std::list<Shared::MessageInfo> list;
LMDBAL::TransactionID txn = base.beginTransaction();
UrlInfo info;
try {
urlToInfo->getRecord(url, info, txn);
urlToInfo->removeRecord(url);
info.getMessages(list);
if (info.hasPath())
pathToUrl->removeRecord(info.getPath());
base.commitTransaction(txn);
} catch (...) {
base.abortTransaction(txn);
throw;
}
return list;
}
std::list<Shared::MessageInfo> Core::UrlStorage::deletedFile(const QString& path) {
std::list<Shared::MessageInfo> list;
LMDBAL::TransactionID txn = base.beginTransaction();
try {
QString url = pathToUrl->getRecord(path, txn);
pathToUrl->removeRecord(path);
UrlInfo info = urlToInfo->getRecord(url, txn);
info.getMessages(list);
info.setPath(QString());
urlToInfo->changeRecord(url, info, txn);
base.commitTransaction(txn);
} catch (...) {
base.abortTransaction(txn);
throw;
}
return list;
}
QString Core::UrlStorage::getUrl(const QString& path) {
return pathToUrl->getRecord(path);
}
std::pair<QString, std::list<Shared::MessageInfo>> Core::UrlStorage::getPath(const QString& url) {
UrlInfo info = urlToInfo->getRecord(url);
std::list<Shared::MessageInfo> container;
info.getMessages(container);
return std::make_pair(info.getPath(), container);
}
Core::UrlStorage::UrlInfo::UrlInfo():
localPath(),
messages() {}
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path):
localPath(path),
messages() {}
Core::UrlStorage::UrlInfo::UrlInfo(const QString& path, const std::list<Shared::MessageInfo>& msgs):
localPath(path),
messages(msgs) {}
Core::UrlStorage::UrlInfo::~UrlInfo() {}
bool Core::UrlStorage::UrlInfo::addMessage(const QString& acc, const QString& jid, const QString& id) {
for (const Shared::MessageInfo& info : messages) {
if (info.account == acc && info.jid == jid && info.messageId == id) {
return false;
}
}
messages.emplace_back(acc, jid, id);
return true;
}
void Core::UrlStorage::UrlInfo::serialize(QDataStream& data) const {
data << localPath;
std::list<Shared::MessageInfo>::size_type size = messages.size();
data << quint32(size);
for (const Shared::MessageInfo& info : messages) {
data << info.account;
data << info.jid;
data << info.messageId;
}
}
QDataStream & operator << (QDataStream& in, const Core::UrlStorage::UrlInfo& info) {
info.serialize(in);
return in;
}
QDataStream & operator >> (QDataStream& out, Core::UrlStorage::UrlInfo& info) {
info.deserialize(out);
return out;
}
void Core::UrlStorage::UrlInfo::deserialize(QDataStream& data) {
data >> localPath;
quint32 size;
data >> size;
for (quint32 i = 0; i < size; ++i) {
messages.emplace_back();
Shared::MessageInfo& info = messages.back();
data >> info.account;
data >> info.jid;
data >> info.messageId;
}
}
void Core::UrlStorage::UrlInfo::getMessages(std::list<Shared::MessageInfo>& container) const {
for (const Shared::MessageInfo& info : messages)
container.emplace_back(info);
}
QString Core::UrlStorage::UrlInfo::getPath() const {
return localPath;
}
bool Core::UrlStorage::UrlInfo::hasPath() const {
return localPath.size() > 0;
}
void Core::UrlStorage::UrlInfo::setPath(const QString& path) {
localPath = path;
}