From 1df49583fbb63ea6276de00163cc939f5c5dc81d Mon Sep 17 00:00:00 2001 From: blue Date: Wed, 11 Sep 2019 18:03:52 +0300 Subject: [PATCH] new class to store string key-values on disk, will use for downloaded file index --- core/CMakeLists.txt | 1 + core/archive.h | 24 +++++++ core/squawk.cpp | 18 ++++- core/squawk.h | 4 ++ core/storage.cpp | 157 ++++++++++++++++++++++++++++++++++++++++++++ core/storage.h | 55 ++++++++++++++++ 6 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 core/storage.cpp create mode 100644 core/storage.h diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index f35f5b9..a4db750 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -15,6 +15,7 @@ set(squawkCORE_SRC rosteritem.cpp contact.cpp conference.cpp + storage.cpp ) # Tell CMake to create the helloworld executable diff --git a/core/archive.h b/core/archive.h index 380e52d..58a5f8d 100644 --- a/core/archive.h +++ b/core/archive.h @@ -100,6 +100,30 @@ public: 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: bool opened; bool fromTheBeginning; diff --git a/core/squawk.cpp b/core/squawk.cpp index 66b7101..905dbe5 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -25,7 +25,8 @@ Core::Squawk::Squawk(QObject* parent): QObject(parent), accounts(), - amap() + amap(), + files("files") { } @@ -42,7 +43,7 @@ Core::Squawk::~Squawk() void Core::Squawk::stop() { qDebug("Stopping squawk core.."); - + files.close(); QSettings settings; settings.beginGroup("core"); settings.beginWriteArray("accounts"); @@ -82,6 +83,7 @@ void Core::Squawk::start() } settings.endArray(); settings.endGroup(); + files.open(); } void Core::Squawk::newAccountRequest(const QMap& map) @@ -485,3 +487,15 @@ void Core::Squawk::addRoomRequest(const QString& account, const QString& jid, co 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, ""); + } +} diff --git a/core/squawk.h b/core/squawk.h index cdf4d84..9208dbf 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -28,6 +28,7 @@ #include "account.h" #include "../global.h" +#include "storage.h" namespace Core { @@ -61,6 +62,7 @@ signals: void addRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void changeRoomParticipant(const QString& account, const QString& jid, const QString& name, const QMap& data); void removeRoomParticipant(const QString& account, const QString& jid, const QString& name); + void fileLocalPathResponse(const QString& messageId, const QString& path); public slots: void start(); @@ -81,6 +83,7 @@ public slots: 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 removeRoomRequest(const QString& account, const QString& jid); + void fileLocalPathRequest(const QString& messageId, const QString& url); private: typedef std::deque Accounts; @@ -89,6 +92,7 @@ private: Accounts accounts; AccountsMap amap; Shared::Availability state; + Storage files; private: void addAccount(const QString& login, const QString& server, const QString& password, const QString& name, const QString& resource); diff --git a/core/storage.cpp b/core/storage.cpp new file mode 100644 index 0000000..8f6c17c --- /dev/null +++ b/core/storage.cpp @@ -0,0 +1,157 @@ +/* + * Squawk messenger. + * Copyright (C) 2019 Yury Gubich + * + * 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 . + */ + +#include +#include + +#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); + } +} diff --git a/core/storage.h b/core/storage.h new file mode 100644 index 0000000..9fe64ca --- /dev/null +++ b/core/storage.h @@ -0,0 +1,55 @@ +/* + * Squawk messenger. + * Copyright (C) 2019 Yury Gubich + * + * 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 . + */ + +#ifndef CORE_STORAGE_H +#define CORE_STORAGE_H + +#include +#include + +#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