diff --git a/Heart/DataBaseSpace/database.cpp b/Heart/DataBaseSpace/database.cpp new file mode 100644 index 0000000..595d2c6 --- /dev/null +++ b/Heart/DataBaseSpace/database.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2018-2021 QuasarApp. + * Distributed under the lgplv3 software license, see the accompanying + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. +*/ + +#include "accesstoken.h" +#include "database.h" +#include "abstractnodeinfo.h" +#include "sqldbcache.h" +#include "sqldbwriter.h" +#include "websocketcontroller.h" +#include "asyncsqldbwriter.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dberrorcodes.h" +#include +#include +#include +#include +#include +#include +#include +#include "getsinglevalue.h" +#include "setsinglevalue.h" + +#define THIS_NODE "this_node_key" +namespace QH { +using namespace PKG; + +DataBase::DataBase() { + qRegisterMetaType>(); +} + +bool DataBase::initSqlDb(QString DBparamsFile, + ISqlDBCache *cache, + SqlDBWriter *writer) { + + initDefaultDbObjects(cache, writer); + + QVariantMap params; + _db->setSQLSources(SQLSources()); + + if (DBparamsFile.isEmpty()) { + params = defaultDbParams(); + + if (!_db->init(params)) { + return false; + } + + } else { + + if (!_db->init(DBparamsFile)) { + return false; + } + + } + + if (!upgradeDataBase()) { + QuasarAppUtils::Params::log("Failed to upgrade database", + QuasarAppUtils::Error); + return false; + } + + QuasarAppUtils::Params::log(QString("Database loaded from: %0").arg(dbLocation()), + QuasarAppUtils::Debug); + + return true; +} + +bool DataBase::isSqlInited() const { + return _db; +} + +bool DataBase::run() { + if (!isSqlInited() && !initSqlDb()) { + return false; + } + return true; +} + +bool DataBase::run(const QString &localNodeName) { + + if (localNodeName.isEmpty()) + return false; + + setLocalNodeName(localNodeName); + + if (!isSqlInited() && !initSqlDb()) { + return false; + } + + return true; +} + +void DataBase::stop() { + + if (db()) { + auto writer = _db->writer(); + _db->softDelete(); + _db = nullptr; + delete writer; + } +} + +DataBase::~DataBase() { +} + +void DataBase::initDefaultDbObjects(ISqlDBCache *cache, + SqlDBWriter *writer) { + if (!writer) { + writer = new AsyncSqlDBWriter(); + } + + if (!cache) { + cache = new SqlDB(); + } + + cache->setWriter(writer); + _db = cache; + + connect(_db, &ISqlDBCache::sigItemChanged, + this, &DataBase::handleObjectChanged, + Qt::DirectConnection); + + connect(_db, &ISqlDBCache::sigItemDeleted, + this, &DataBase::handleObjectDeleted, + Qt::DirectConnection); +} + + +bool DataBase::welcomeAddress(AbstractNodeInfo *) { + return true; +} + +bool DataBase::isBanned(const QVariant &node) const { + NetworkMember member(node); + auto objectFromDataBase = db()->getObject(member); + + return objectFromDataBase->trust() <= 0; +} + +QStringList DataBase::SQLSources() const{ + return { + DEFAULT_DB_INIT_FILE_PATH + }; +} + +QSet DataBase::systemTables() const { + return {"NetworkMembers", "MemberPermisions"}; +} + +bool DataBase::notifyObjectChanged(const QSharedPointer &item) { + + if (!item.dynamicCast()) { + return false; + } + + _webSocketWorker->handleItemChanged(item); + + return true; +} + +void DataBase::objectRemoved(const DbAddress &) { + +} + +void DataBase::objectChanged(const QSharedPointer &) { + +} + +DBPatchMap DataBase::dbPatches() const { + return {}; +} + +void DataBase::handleObjectChanged(const QSharedPointer &item) { + notifyObjectChanged(item.staticCast()); + objectChanged(item); + +} + +void DataBase::handleObjectDeleted(const DbAddress &item) { + objectRemoved(item); +} + +void DataBase::memberSubsribed(const QVariant &, unsigned int ) { + return; +} + +void DataBase::memberUnsubsribed(const QVariant &, unsigned int ) { + return; +} + +QString DataBase::dbLocation() const { + if (db() && db()->writer()) { + return db()->writer()->databaseLocation(); + } + + return ""; +} + +ISqlDBCache *DataBase::db() const { + return _db; +} + +bool DataBase::isForbidenTable(const QString &table) { + return systemTables().contains(table); +} + +bool DataBase::upgradeDataBase() { + auto patches = dbPatches(); + int actyalyVersion = patches.size(); + int currentVersion = 0; + + if (!db()) + return false; + + bool fsupportUpgrade = db()->doQuery("SELECT COUNT(*) FROM DataBaseAttributes", true); + + if (!fsupportUpgrade) { + + QuasarAppUtils::Params::log("The data base of application do not support soft upgrade. " + "Please remove database monyaly and restart application.", + QuasarAppUtils::Error); + return false; + } + + PKG::GetSingleValue request({"DataBaseAttributes", "version"}, "value", "name"); + + if (auto responce = _db->getObject(request)) { + currentVersion = responce->value().toInt(); + } + + bool fUpdated = false; + while (currentVersion < actyalyVersion) { + + auto patch = patches.value(currentVersion, {}); + + QString message; + message = "Upgrade data base!. to %0 versions"; + message = message.arg(currentVersion); + + QuasarAppUtils::Params::log(message, + QuasarAppUtils::Info); + + if (patch && !patch(db())) { + QuasarAppUtils::Params::log("Failed to " + message, + QuasarAppUtils::Error); + return false; + } + + currentVersion++; + fUpdated = true; + } + + if (fUpdated) { + auto updateVersionRequest = QSharedPointer::create( + DbAddress{"DataBaseAttributes", "version"}, + "value", currentVersion, "name"); + + if (!_db->insertIfExistsUpdateObject(updateVersionRequest, true)) { + QuasarAppUtils::Params::log("Failed to update version attribute", + QuasarAppUtils::Error); + return false; + } + } + + return true; +} + +const QString &DataBase::localNodeName() const { + return _localNodeName; +} + +void DataBase::setLocalNodeName(const QString &newLocalNodeName) { + _localNodeName = newLocalNodeName; +} + +QVariantMap DataBase::defaultDbParams() const { + + return { + {"DBDriver", "QSQLITE"}, + {"DBFilePath", DEFAULT_DB_PATH + "/" + localNodeName() + "/" + localNodeName() + "_" + DEFAULT_DB_NAME}, + }; +} + +DBOperationResult +QH::DataBase::getObject(const QVariant &requester, + const QH::DBObject &templateObj, + QSharedPointer &result) const { + + if (!_db && !result) { + return DBOperationResult::Unknown; + } + + DBOperationResult permisionResult = checkPermission(requester, templateObj.dbAddress(), + Permission::Read); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + + auto obj = _db->getObject(templateObj); + if (!obj || (obj->dbAddress() != templateObj.dbAddress())) { + return DBOperationResult::Unknown; + } + + result = obj; + return DBOperationResult::Allowed; +} + +DBOperationResult +DataBase::getObjects(const QVariant &requester, + const DBObject &templateObj, + QList> &result) const { + if (!_db) { + return DBOperationResult::Unknown; + } + + if (!_db->getAllObjects(templateObj, result)) { + return DBOperationResult::Unknown; + } + + for (const auto& obj: qAsConst(result)) { + if (!obj) + return DBOperationResult::Unknown; + + auto permisionResult = checkPermission(requester, obj->dbAddress(), + Permission::Read); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + } + + return DBOperationResult::Allowed; +} + +DBOperationResult +DataBase::updateObject(const QVariant &requester, + const QSharedPointer &saveObject) { + + if (!_db) { + return DBOperationResult::Unknown; + } + + auto permisionResult = checkPermission(requester, + saveObject->dbAddress(), + Permission::Write); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + + if (!_db->updateObject(saveObject)) { + return DBOperationResult::Unknown; + } + + return DBOperationResult::Allowed; +} + +DBOperationResult +DataBase::createObject(const QVariant &requester, + const QSharedPointer &obj) { + + if (!_db) { + return DBOperationResult::Unknown; + } + + if (isForbidenTable(obj->tableName())) { + return DBOperationResult::Forbidden; + } + + if (!_db->insertObject(obj)) { + return DBOperationResult::Unknown; + } + + if (!addUpdatePermission(requester, obj->dbAddress(), Permission::Write)) { + + _db->deleteObject(obj); + + return DBOperationResult::Forbidden; + } + + return DBOperationResult::Allowed; + +} + +DBOperationResult +DataBase::updateIfNotExistsCreateObject(const QVariant &requester, + const QSharedPointer &obj) { + + auto opResult = updateObject(requester, obj); + if (opResult != QH::DBOperationResult::Unknown) { + return opResult; + } + + return createObject(requester, obj); +} + +DBOperationResult +DataBase::changeObjects(const QVariant &requester, + const DBObject &templateObj, + const std::function &)> &changeAction) { + + DBOperationResult result = DBOperationResult::Unknown; + + if (!_db) { + return result; + } + + auto execWithCheck = [this, requester, &result, &changeAction] + (const QSharedPointer & obj) { + + result = checkPermission(requester, obj->dbAddress(), Permission::Update); + if (result != DBOperationResult::Allowed) { + return false; + } + + return changeAction(obj); + }; + + if (!db()->changeObjects(templateObj, execWithCheck)) { + return result; + } + + return result; +} + +QVariant DataBase::getSender(const AbstractNodeInfo *connectInfo, + const AbstractData *) const { + + auto info = dynamic_cast(connectInfo); + if (!info) + return {}; + + return info->id(); +} + +DBOperationResult +DataBase::checkPermission(const QVariant &requester, + const DbAddress &objectAddress, + const Permission& requarimentPermision) const { + + if (!requester.isValid()) + return DBOperationResult::Unknown; + + if (!_db) { + return DBOperationResult::Unknown; + } + + auto member = _db->getObjectRaw(NetworkMember{requester}); + if (!member) { + return DBOperationResult::Unknown; + } + + auto permision = + _db->getObject(MemberPermisionObject({requester, objectAddress})); + + if (!permision) { + + permision = _db->getObject(DefaultPermision({requester, objectAddress})); + if (!permision) + return DBOperationResult::Unknown; + } + + if (permision->permisions() < requarimentPermision) { + return DBOperationResult::Forbidden; + } + + return DBOperationResult::Allowed; +} + +bool DataBase::addUpdatePermission(const QVariant &member, + const DbAddress &objectAddress, + const Permission &permision, + const Permission &defaultPermision) const { + + if (!_db) { + return false; + } + + auto object = QSharedPointer::create(); + object->setKey(PermisionData(member, objectAddress)); + object->setPermisions(permision); + + if (!_db->insertObject(object) && !_db->updateObject(object)) { + return false; + } + + auto defaultPermisionObject = QSharedPointer::create(); + defaultPermisionObject->setKey(PermisionData({}, objectAddress)); + defaultPermisionObject->setPermisions(defaultPermision); + + if (!_db->insertObject(defaultPermisionObject) && + !_db->updateObject(defaultPermisionObject)) { + return false; + } + + return true; +} + +bool DataBase::removePermission(const QVariant &member, + const DbAddress &objectAddress) const { + + if (!_db) { + return false; + } + + auto object = QSharedPointer::create(); + object->setKey(PermisionData(member, objectAddress)); + + if (!_db->deleteObject(object)) { + return false; + } + + return true; +} + +DBOperationResult +DataBase::deleteObject(const QVariant &requester, + const QSharedPointer &dbObject) { + + if (!_db) { + return DBOperationResult::Unknown; + } + + auto permisionResult = checkPermission(requester, + dbObject->dbAddress(), + Permission::Write); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + + auto address = dbObject->dbAddress(); + if (!_db->deleteObject(dbObject)) { + return DBOperationResult::Unknown; + } + + return DBOperationResult::Allowed; +} + +} + diff --git a/Heart/DataBaseSpace/database.h b/Heart/DataBaseSpace/database.h new file mode 100644 index 0000000..2b7d529 --- /dev/null +++ b/Heart/DataBaseSpace/database.h @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2018-2021 QuasarApp. + * Distributed under the lgplv3 software license, see the accompanying + * Everyone is permitted to copy and distribute verbatim copies + * of this license document, but changing it is not allowed. +*/ + +#ifndef QH_DATABASE_H +#define QH_DATABASE_H + +#include "abstractnode.h" +#include +#include +#include + + +namespace QH { + +namespace PKG { +class WebSocket; +class ISubscribableData; + +} + +class ISqlDBCache; +class SqlDBWriter; +class WebSocketController; +class DbAddress; +class NodeId; +class iObjectProvider; + + +/** + * @brief DBPatch This is function that should be upgrade database. + * @see DBPatchMap + * @see DataBaseNode::dbPatch + */ +typedef std::function DBPatch; +/** + * @brief DBPatchMap This is list when index of list is version of database and value if function that should be upgrade database. + * @see DataBaseNode::dbPatch + * @see DBPatchMap + */ +typedef QList DBPatchMap; + +/** + * @brief The DataBase class is DataBase base implementation. + * This implementation contains methods for work with database. + * DataBaseNode is thread save class. + * @see DBObject + * @see DataBaseNode + */ +class HEARTSHARED_EXPORT DataBase +{ +public: + + DataBase(); + ~DataBase(); + + /** + * @brief intSqlDb This method initalize database of this node or server. + * @param DBparamsFile This is path to json file with all params of database. + * For more information of available parameters see the SqlDBWriter::defaultInitPararm method. + * @param cache This is pointer to the custom child of SqlDBCache class. + * IF you set nullptr value of this parameter then well be created a default SqlDBCache object. + * @param writer This is pointer tot the custom child of SqlDBWriter class. + * If you set nullptr value of this parameter then well be created a default AsyncSqlDbWriter object. + * @return True if the database initialized successful. + */ + virtual bool initSqlDb( QString DBparamsFile = "", + ISqlDBCache * cache = nullptr, + SqlDBWriter* writer = nullptr); + + /** + * @brief isSqlInited This method return true if database initialized successful. + * @return True if database initialized successful. + */ + bool isSqlInited() const; + + /** + * @brief run This method start and initialize the data base connection. + * @return true if finished successful else false. + */ + bool run(); + + /** + * @brief run This method is some as AbstractNode::run but set for node custom work folder. + * This maybe use for multiple deployment nodes on one host. + * @param localNodeName This is name of node and work folder of node. + */ + virtual bool run(const QString &localNodeName); + + void stop(); + + /** + * @brief defaultDbParams This method return default database parameters for this node. + * Override this method for set new default parameters. Or use json database parameters file in DataBaseNode::run. + * @return Map with all database parameters. + * For more information of available parameters see the SqlDBWriter::defaultInitPararm method. + */ + virtual QVariantMap defaultDbParams() const; + + /** + * @brief deleteObject This method delete object by database address. + * @note If you want to delete any object use only this method because this method check permission of requester to execute this action. + * @param requester This is pointer to network member that send this request. + * @param dbObject This is pointer to object of database to remove. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult deleteObject(const QVariant &requester, + const QSharedPointer &dbObject); + + /** + * @brief getObject This method try get an object by database address. + * @note If you want to get any object use only this method because this method check permission of requester to execute this action + * @param requester This is pointer to network member that send this request. + * @param templateObj This is pointer to object of database with data for generation the sql select request. + * @param result This is a shared pointer for save result of request. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult getObject(const QVariant &requester, + const PKG::DBObject &templateObj, + QSharedPointer &result) const; + + /** + * @brief getObjects This method try get objects by template object. + * @note If you want to get any objects use only this method because this method check permission of requester to execute this action + * @param requester This is pointer to network member that send this request. + * @param templateObj This is pointer to object of database with data for generation the sql select request. + * @param result This is reference to the list of result objects. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult getObjects(const QVariant &requester, + const PKG::DBObject &templateObj, + QList> &result) const; + + /** + * @brief updateObject This method try save or update database object. + * @note If you want to save or update any objects use only this method because this method check permission of requester to execute this action + * @param requester This is network mebmer that send this request. + * @param saveObject This is pointer to object of database for save or update. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult updateObject(const QVariant &requester, + const QSharedPointer &saveObject); + + /** + * @brief createObject This method create a new object in the database and add all permissions for the objects creator. + * @note If you want to create any objects use only this method because this method check permission of requester to execute this action + * @param requester This is network member that send this request. + * @param obj This is pointer to object of database for save or update. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult createObject(const QVariant &requester, + const QSharedPointer &obj); + + /** + * @brief updateIfNotExistsCreateObject This is wraper of the updateObject and createObjects methods. + * 1. Try update object + * 2. If object not exists Try create new object. + * 3. Return operation result + * @param requester This is network member that send this request. + * @param obj This is initializing object. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult updateIfNotExistsCreateObject(const QVariant &requester, + const QSharedPointer &obj); + + /** + * @brief changeObjects This is wrapper of the "ISqlDBCache::changeObjects" method. + * Key difference between a base method is checking of the permision for needed action. + * @note If you want to change any objects use only this method because this method check permission of requester to execute this action + * @param requester This is network member that send this request. + * @param templateObj This is pointer to object of database with data for generation the sql select request. + * @param changeAction This is action function for change all selected objects. + * @return result of operation (allow, forbidden, unknown). + * For more information about results see the DBOperationResult enum. + */ + DBOperationResult changeObjects(const QVariant &requester, + const PKG::DBObject &templateObj, + const std::function&)> &changeAction); + + + +protected: + + /** + * @brief localNodeName This method return local node name. + * + * @return local node name + */ + const QString &localNodeName() const; + + /** + * @brief setLocalNodeName This method sets new local name of database file. + * @note This method must be invoked before the DataBaseNode::initsqlDb and the DataBaseNode::run methods. + * @param newLocalNodeName This is new name of node object and node databae file. + * + */ + void setLocalNodeName(const QString &newLocalNodeName); + + /** + * @brief initDefaultDbObjects This method create a default cache and database writer objects if the input pointers is null + * Override this method for create a custom database objects for your node class. + * @note If you override this object then you no longer need to overload the run method to set your own controls. + * This method invoked automatically when you call the DataBaseNode::run method. + * @param cache This is Cache database object. + * @param writer This is Database writerObject. + */ + virtual void initDefaultDbObjects(ISqlDBCache *cache, SqlDBWriter *writer); + + /** + * @brief changeTrust This implementation of change trust is change trust node or user by self id. + * All changes of trust saving into local database. + * @param id This is id of user of other network member object. + * @param diff This is difference of trust. + * @return true if trust of user changed successful. + */ + virtual bool changeTrust(const QVariant &id, int diff); + + /** + * @brief memberSubsribed This method invoked when client with @a clientId subscribed on object with @a subscribeId. + * @param clientId This is id of the client member. + * @param subscribeId This is id of the subscribeObject. + */ + virtual void memberSubsribed(const QVariant &clientId, unsigned int subscribeId); + + /** + * @brief memberUnSubsribed This method invoked when client with @a clientId unsubsribed on object with @a subscribeId + * @param clientId This is id of the client member. + * @param subscribeId This is id of the subscribeObject. + */ + virtual void memberUnsubsribed(const QVariant &clientId, unsigned int subscribeId); + + /** + * @brief db This node return pointer to database object. + * @return The pointer to data base. + */ + ISqlDBCache* db() const; + + /** + * @brief getSender This method return id of requester. + * By Default base implementation get id from BaseNdoeInfo. + * override this method for correctly work of the DataBaseNode::ParsePacakge method. + * @param connectInfo This is info about connection. + * @param requestData This is data of request. + * @return id of requester member. + */ + virtual QVariant getSender(const AbstractNodeInfo *connectInfo, const PKG::AbstractData *requestData) const; + + /** + * @brief checkPermision This method check a permision of requester, to database object with objectAddress. + * Override this method if you have a custom database structure. + * @param requester This is user, node or another object of network + * @param objectAddress This is address to database object + * @param requarimentPermision This is needed permission for requester + * @return DBOperationResult::Alowed if permission granted. + * For more information about result see the DBOperationResult enum. + */ + virtual DBOperationResult checkPermission(const QVariant &requester, + const DbAddress& objectAddress, + const Permission& requarimentPermision) const; + + + /** + * @brief addUpdatePermission This method added or update permission for member. + * @warning This method do not have a validation. It is just change a NetworkMembers table, so use this carefully. + * @param member This is member id (user of node). + * @param objectAddress This is database object for which the permissions will be set. + * @param permision This is permission level. + * @param defaultPermision This is default permision for all of rest objects. By default This is Permission::Read + * @return true if method finished successful. + */ + virtual bool addUpdatePermission(const QVariant &member, + const DbAddress& objectAddress, + const Permission& permision, + const Permission& defaultPermision = Permission::Read) const; + + /** + * @brief removePermission This method use to removed permission for member. + * @warning This method do not have a validation. It is just change a NetworkMembers table, so use this carefully. + * @param member This is member id (user of node) + * @param objectAddress This is database object for which the permissions will be removed + * @return true if method finished successful. + */ + virtual bool removePermission(const QVariant &member, + const DbAddress& objectAddress) const; + + /** + * @brief dbLocation This method return location of nodes or clients database. + * @return path to the location of database. + */ + QString dbLocation() const; + + /** + * @brief welcomeAddress This method send to the node information about self. + * Override this method if you want send custom data to incoming connection. + * @param node This is info object of the peer node. + * @return true if all information sender successful. + */ + virtual bool welcomeAddress(AbstractNodeInfo *node); + + /** + * @brief isBanned This method check trust of node, if node trust is lover of 0 return true. + * @param member This is member of network (node, client or server). + * @return true if node is banned. + */ + bool isBanned(const QVariant &member) const; + + /** + * @brief SQLSources This method contains list of sqldatabase sources. + * This method will be invoked into initialize sql method and deploy sql database. + * + * All sql files will be deployed in QList order. + * + * By Default This method deploy next sql code: + * \code{sql} + * CREATE TABLE IF NOT EXISTS NetworkMembers ( + id VARCHAR(64) PRIMARY KEY NOT NULL, + authenticationData BLOB default NULL, + trust INTEGER default 0 + ); + + CREATE TABLE IF NOT EXISTS MemberPermisions ( + memberId VARCHAR(64) NOT NULL, + objectTable VARCHAR(100) NOT NULL, + objectId VARCHAR(64) NOT NULL, + lvl INTEGER NOT NULL, + + FOREIGN KEY(memberId) REFERENCES NetworkMembers(id) + ON UPDATE CASCADE + ON DELETE CASCADE + + ); + CREATE UNIQUE INDEX IF NOT EXISTS MemberPermisionsIndex ON MemberPermisions(memberId, objectTable, objectId); + + * \endcode + * For add own sql code just override this method, but do not forget invoke a base method of a parent class. + * + * Example: + * \code{cpp} + * return DataBaseNode::SQLSources() << "path/to/mySqlFile.sql"; + * \endcode + * + * @return the list to deploy sql files. + */ + virtual QStringList SQLSources() const; + + /** + * @brief systemTables This method return the set of tables that forbidden for users. + * By default is NetworkMembers and MemberPermisions tables. + * @return set of tables names. + */ + virtual QSet systemTables() const; + + /** + * @brief notifyObjectChanged This method send all subscriptions message with this object. + * @param item changed object. + * @return true if an item object sendible. + */ + bool notifyObjectChanged(const QSharedPointer &item); + + /** + * @brief objectRemoved This method invoked when object with @a address removed from database. + * Oberride this method for handle this event. Default implementation do nothing. + * @param address This is address of the deteted object. + */ + virtual void objectRemoved(const DbAddress& address); + + /** + * @brief objectChanged This method invoked when object with @a address changed in database. + * Override this method for handle this event. Default implementation do nothing. + * @param obj This is address of the changed object. + */ + virtual void objectChanged(const QSharedPointer& obj); + + /** + * @brief dbPatches This method should be return map with functions that upgrade production data base. + * Eeach function shoul be can upgrade databae from preview version to own version. + * **Example**: + * + * We have 4 version of data base {0, 1, 2, 3} each version should be contains own function for upgrade data base. + * Where the 0 version is first version of database. (genesis) + * + * @code{cpp} + * QH::DBPatchMap dbPatches() const { + QH::DBPatchMap result; + + result += [](const QH::iObjectProvider* database) -> bool { + // Some code for update from 0 to 1 + }; + + result += [](const QH::iObjectProvider* database) -> bool { + // Some code for update from 1 to 2 + }; + + result += [](const QH::iObjectProvider* database) -> bool { + // Some code for update from 2 to 3 + }; + + return result; + } + * @endcode + * + * @return Map of database pactches. + * + * @see DBPatchMap + * @see DBPatch + */ + virtual DBPatchMap dbPatches() const; + + +private: + /** + * @brief workWithSubscribe This method work with subscribe commnads. + * @param rec This is request data. + * @param address This is sender address. + * @return true if data parsed successful. + */ + bool workWithSubscribe(const PKG::WebSocket &rec, + const QVariant &clientOrNodeid, + const AbstractNodeInfo *sender); + + + bool isForbidenTable(const QString& table); + + /** + * @brief upgradeDataBase This method upgrade data base to actyaly database version. + * @note The last version of dbPatches is actyaly version. + * @return true if operation finished successful + */ + bool upgradeDataBase(); + + ISqlDBCache *_db = nullptr; + QString _localNodeName; + WebSocketController *_webSocketWorker = nullptr; + + + friend class WebSocketController; + +}; + + +} + +Q_DECLARE_METATYPE(QSharedPointer) +#endif // QH_DATABASE_H diff --git a/Heart/DataBaseSpace/databasenode.h b/Heart/DataBaseSpace/databasenode.h index 5cbae19..e4a82f3 100644 --- a/Heart/DataBaseSpace/databasenode.h +++ b/Heart/DataBaseSpace/databasenode.h @@ -454,7 +454,7 @@ protected: private slots: void handleObjectChanged(const QSharedPointer &item); - void handleObjectDeleted(const DbAddress &item); + void handleObjectDeleted(const QH::DbAddress &item); private: