new class to store string key-values on disk, will use for downloaded file index

This commit is contained in:
Blue 2019-09-11 18:03:52 +03:00
parent 0574d6f72b
commit 1df49583fb
6 changed files with 257 additions and 2 deletions

View File

@ -15,6 +15,7 @@ set(squawkCORE_SRC
rosteritem.cpp rosteritem.cpp
contact.cpp contact.cpp
conference.cpp conference.cpp
storage.cpp
) )
# Tell CMake to create the helloworld executable # Tell CMake to create the helloworld executable

View File

@ -100,6 +100,30 @@ public:
std::string account; std::string account;
}; };
class Exist:
public Utils::Exception
{
public:
Exist(const std::string& acc, const std::string& p_key):Exception(), account(acc), key(p_key){}
std::string getMessage() const{return "An attempt to insert element " + key + " to database " + account + " but it already has an element with given id";}
private:
std::string account;
std::string key;
};
class Unknown:
public Utils::Exception
{
public:
Unknown(const std::string& acc, const std::string& message):Exception(), account(acc), msg(message){}
std::string getMessage() const{return "Unknown error on database " + account + ": " + msg;}
private:
std::string account;
std::string msg;
};
private: private:
bool opened; bool opened;
bool fromTheBeginning; bool fromTheBeginning;

View File

@ -25,7 +25,8 @@
Core::Squawk::Squawk(QObject* parent): Core::Squawk::Squawk(QObject* parent):
QObject(parent), QObject(parent),
accounts(), accounts(),
amap() amap(),
files("files")
{ {
} }
@ -42,7 +43,7 @@ Core::Squawk::~Squawk()
void Core::Squawk::stop() void Core::Squawk::stop()
{ {
qDebug("Stopping squawk core.."); qDebug("Stopping squawk core..");
files.close();
QSettings settings; QSettings settings;
settings.beginGroup("core"); settings.beginGroup("core");
settings.beginWriteArray("accounts"); settings.beginWriteArray("accounts");
@ -82,6 +83,7 @@ void Core::Squawk::start()
} }
settings.endArray(); settings.endArray();
settings.endGroup(); settings.endGroup();
files.open();
} }
void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map) void Core::Squawk::newAccountRequest(const QMap<QString, QVariant>& map)
@ -485,3 +487,15 @@ void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, co
itr->second->addRoomRequest(jid, nick, password, autoJoin); itr->second->addRoomRequest(jid, nick, password, autoJoin);
} }
void Core::Squawk::fileLocalPathRequest(const QString& messageId, const QString& url)
{
try {
QString path = files.getRecord(url);
emit fileLocalPathResponse(messageId, path);
} catch (Archive::NotFound e) {
emit fileLocalPathResponse(messageId, "");
} catch (Archive::Unknown e) {
qDebug() << "Error requesting file path:" << e.what();
emit fileLocalPathResponse(messageId, "");
}
}

View File

@ -28,6 +28,7 @@
#include "account.h" #include "account.h"
#include "../global.h" #include "../global.h"
#include "storage.h"
namespace Core namespace Core
{ {
@ -61,6 +62,7 @@ signals:
void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data); void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap<QString, QVariant>& data);
void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name);
void fileLocalPathResponse(const QString& messageId, const QString& path);
public slots: public slots:
void start(); void start();
@ -81,6 +83,7 @@ public slots:
void setRoomAutoJoin(const QString& account, const QString& jid, bool joined); void setRoomAutoJoin(const QString& account, const QString& jid, bool joined);
void addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin); void addRoomRequest(const QString& account, const QString& jid, const QString& nick, const QString& password, bool autoJoin);
void removeRoomRequest(const QString& account, const QString& jid); void removeRoomRequest(const QString& account, const QString& jid);
void fileLocalPathRequest(const QString& messageId, const QString& url);
private: private:
typedef std::deque<Account*> Accounts; typedef std::deque<Account*> Accounts;
@ -89,6 +92,7 @@ private:
Accounts accounts; Accounts accounts;
AccountsMap amap; AccountsMap amap;
Shared::Availability state; Shared::Availability state;
Storage files;
private: private:
void addAccount(const QString& login, const QString& server, const QString& password, const QString& name, const QString& resource); void addAccount(const QString& login, const QString& server, const QString& password, const QString& name, const QString& resource);

157
core/storage.cpp Normal file
View File

@ -0,0 +1,157 @@
/*
* 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 "storage.h"
Core::Storage::Storage(const QString& p_name):
name(p_name),
opened(false),
environment(),
base()
{
}
Core::Storage::~Storage()
{
close();
}
void Core::Storage::open()
{
if (!opened) {
mdb_env_create(&environment);
QString path(QStandardPaths::writableLocation(QStandardPaths::CacheLocation));
path += "/" + name;
QDir cache(path);
if (!cache.exists()) {
bool res = cache.mkpath(path);
if (!res) {
throw Archive::Directory(path.toStdString());
}
}
mdb_env_set_maxdbs(environment, 1);
mdb_env_set_mapsize(environment, 10UL * 1024UL * 1024UL);
mdb_env_open(environment, path.toStdString().c_str(), 0, 0664);
MDB_txn *txn;
mdb_txn_begin(environment, NULL, 0, &txn);
mdb_dbi_open(txn, "base", MDB_CREATE, &base);
mdb_txn_commit(txn);
opened = true;
}
}
void Core::Storage::close()
{
if (opened) {
mdb_dbi_close(environment, base);
mdb_env_close(environment);
opened = false;
}
}
void Core::Storage::addRecord(const QString& key, const QString& value)
{
if (!opened) {
throw Archive::Closed("addElement", name.toStdString());
}
const std::string& id = key.toStdString();
const std::string& val = value.toStdString();
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.c_str();
lmdbData.mv_size = val.size();
lmdbData.mv_data = (char*)val.c_str();
MDB_txn *txn;
mdb_txn_begin(environment, NULL, 0, &txn);
int rc;
rc = mdb_put(txn, base, &lmdbKey, &lmdbData, MDB_NOOVERWRITE);
if (rc != 0) {
mdb_txn_abort(txn);
if (rc == MDB_KEYEXIST) {
throw Archive::Exist(name.toStdString(), id);
} else {
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
}
} else {
mdb_txn_commit(txn);
}
}
QString Core::Storage::getRecord(const QString& key) const
{
if (!opened) {
throw Archive::Closed("addElement", name.toStdString());
}
const std::string& id = key.toStdString();
MDB_val lmdbKey, lmdbData;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.c_str();
MDB_txn *txn;
int rc;
mdb_txn_begin(environment, NULL, MDB_RDONLY, &txn);
rc = mdb_get(txn, base, &lmdbKey, &lmdbData);
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw Archive::NotFound(id, name.toStdString());
} else {
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
}
} else {
std::string sId((char*)lmdbData.mv_data, lmdbData.mv_size);
QString value(sId.c_str());
mdb_txn_abort(txn);
return value;
}
}
void Core::Storage::removeRecord(const QString& key)
{
if (!opened) {
throw Archive::Closed("addElement", name.toStdString());
}
const std::string& id = key.toStdString();
MDB_val lmdbKey;
lmdbKey.mv_size = id.size();
lmdbKey.mv_data = (char*)id.c_str();
MDB_txn *txn;
int rc;
mdb_txn_begin(environment, NULL, 0, &txn);
rc = mdb_del(txn, base, &lmdbKey, NULL);
if (rc) {
mdb_txn_abort(txn);
if (rc == MDB_NOTFOUND) {
throw Archive::NotFound(id, name.toStdString());
} else {
throw Archive::Unknown(name.toStdString(), mdb_strerror(rc));
}
} else {
mdb_txn_commit(txn);
}
}

55
core/storage.h Normal file
View File

@ -0,0 +1,55 @@
/*
* 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/>.
*/
#ifndef CORE_STORAGE_H
#define CORE_STORAGE_H
#include <QString>
#include <lmdb.h>
#include "archive.h"
namespace Core {
/**
* @todo write docs
*/
class Storage
{
public:
Storage(const QString& name);
~Storage();
void open();
void close();
void addRecord(const QString& key, const QString& value);
void removeRecord(const QString& key);
QString getRecord(const QString& key) const;
private:
QString name;
bool opened;
MDB_env* environment;
MDB_dbi base;
};
}
#endif // CORE_STORAGE_H