290 lines
7.9 KiB
C++
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;
|
||
|
}
|