From fe5d8f74936f2c9aa9b8dbd89ef990724fe85dc9 Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 1 Dec 2022 22:03:49 +0300 Subject: [PATCH 1/3] update documentation --- HeartTests/units/abstractnodetest.cpp | 4 + HeartTests/units/bigdatatest.cpp | 4 + HeartTests/units/shedullertest.cpp | 6 + README.md | 160 ++++++++++++------------- src/heart.h | 134 +++++++++++++-------- src/public/abstractnode.h | 28 ++++- src/public/packages/abstractdata.cpp | 4 - src/public/packages/abstractdata.h | 77 ------------ src/public/packages/dbobject.cpp | 13 -- src/public/packages/dbobject.h | 23 ---- src/public/packages/dbobjectsrequest.h | 4 - 11 files changed, 197 insertions(+), 260 deletions(-) diff --git a/HeartTests/units/abstractnodetest.cpp b/HeartTests/units/abstractnodetest.cpp index fb83087a..6a689431 100644 --- a/HeartTests/units/abstractnodetest.cpp +++ b/HeartTests/units/abstractnodetest.cpp @@ -22,6 +22,10 @@ class TestingClient: public QH::AbstractNode { return _ping; } + NodeType nodeType() const override { + return NodeType::Node; + }; + protected slots: void receivePing(const QSharedPointer& ping) override { _ping = *ping; diff --git a/HeartTests/units/bigdatatest.cpp b/HeartTests/units/bigdatatest.cpp index 7da1feae..e7e4ff08 100644 --- a/HeartTests/units/bigdatatest.cpp +++ b/HeartTests/units/bigdatatest.cpp @@ -89,6 +89,10 @@ class TestingClientBigData: public QH::AbstractNode { _parser = addApiParser(); } + NodeType nodeType() const override { + return NodeType::Node; + }; + const QSharedPointer& parser() const { return _parser; } diff --git a/HeartTests/units/shedullertest.cpp b/HeartTests/units/shedullertest.cpp index b160b5f0..1f8ab572 100644 --- a/HeartTests/units/shedullertest.cpp +++ b/HeartTests/units/shedullertest.cpp @@ -18,6 +18,12 @@ class ShedullerestNode: public QH::AbstractNode { public: quint64 executedTime = 0; + + // AbstractNode interface +public: + NodeType nodeType() const override { + return NodeType::Node; + }; }; class TestTask: public QH::AbstractTask { diff --git a/README.md b/README.md index 5e852b22..23a02d82 100644 --- a/README.md +++ b/README.md @@ -10,20 +10,7 @@ This library consists of two levels (AbstractNode level and DataBaseNode level). - [X] Support ssl sockets - [X] Support initialize database - [X] Support work in database -- [ ] Support decentralized network mode -### AbstractNode level (0) -#### Description -The AbstractNode level implement only base functions of create a new work threads and parsing packages. -For more information see QuasarApp Heart documentation, QH namespace. - -### DataBaseNode level (1) -#### Description -The DataBaseNode level implement methods and packages for work with databases. This level using Qt classes for wrking with database, so for more information about suport databases see [Qt Documentation](https://doc.qt.io/qt-5/sql-driver.html). - -### NetworkNode level (2) -#### Description -This level is still in develop. ## Build and Include ### For cmake projects @@ -32,11 +19,14 @@ This level is still in develop. * git submodule add https://github.com/QuasarApp/Heart.git # add the repository of Heart into your repo like submodule * git submodule update --init --recursive * Include in your CMakeLists.txt file the main CMakeLists.txt file of Heart library - ``` cmake + + ```cmake add_subdirectory(Heart) ``` - * select requiriment build level for you project - ``` + + * select requirement build level for your project + + ```cmake set(HEART_BUILD_LVL 2) ``` where 1 - is code of build level @@ -57,6 +47,7 @@ This level is still in develop. ## Usage Create a own package class and override some basic methods. + ```cpp class MyPackage: public QH::AbstractData @@ -67,7 +58,7 @@ public: // override this method for validation your package class bool isValid() const { return AbstractData::isValid(); - }; / + }; // your data for for server of client std::string _data = ""; @@ -75,12 +66,10 @@ public: protected: // StreamBase interface override this methods for serialization your package QDataStream &fromStream(QDataStream &stream) { - AbstractData::fromStream(stream); stream >> _data; return stream; } QDataStream &toStream(QDataStream &stream) const { - AbstractData::toStream(stream); stream << _data; return stream; } @@ -88,84 +77,91 @@ protected: }; ``` -Create a server class and override parsePackage method for work with packages. +Create your parser api class. + +```cpp +* +* class MyParser: public QH::iParser { + public: + MyParser(QH::AbstractNode* parentNode): QH::iParser(parentNode) { + registerPackageType(); + data = new BigPackage(); + } + + // iParser interface + public: + + // override this method for processed received data. + ParserResult parsePackage(const Package &pkg, + const AbstractNodeInfo *sender) { + + auto parentResult = AbstractNode::parsePackage(pkg, sender); + if (parentResult != ParserResult::NotProcessed) { + return parentResult; + } + + auto result = commandHandler(this, &MyClass::processMyPackage, pkg, sender, pkgHeader); + if (result != QH::ParserResult::NotProcessed) { + return result; + } + + return ParserResult::NotProcessed; + } + + bool processMyPackage(const QSharedPointer &cardrequest, + const QH::AbstractNodeInfo *sender, const QH::Header &hdr) { + + BaseId requesterId = getSender(sender, &cardrequest); + + if (!cardrequest.isValid()) { + badRequest(sender->networkAddress(), hdr); + return ParserResult::Error; + } + + cardrequest._data = "responce for client " + + // responce only for servers. + if (nodeType() == QH::AbstractNode::NodeType::Server) + sendData(cardrequest, sender->networkAddress(), &pkg.hdr); + + return ParserResult::Processed; + } + + // This vesion of the parser (any digital value.) . + int version() const override {return 0;}; + QString parserId() const override {return "MyParser";}; + + }; +``` + +Create a server class and add supported parsers to work with packages. ```cpp class TestingServer: public QH::AbstractNode { - Q_OBJECT +Q_OBJECT public: TestingServer() { - registerPackageType(); + addApiParser(); } - -protected: - // override this method for processed received data. - ParserResult parsePackage(const Package &pkg, - const AbstractNodeInfo *sender) { - - auto parentResult = AbstractNode::parsePackage(pkg, sender); - if (parentResult != ParserResult::NotProcessed) { - return parentResult; - } - - auto result = commandHandler(this, &MyClass::processMyPackage, pkg, sender, pkgHeader); - if (result != QH::ParserResult::NotProcessed) { - return result; - } - - return ParserResult::NotProcessed; - } - - bool processMyPackage(const QSharedPointer &cardrequest, - const QH::AbstractNodeInfo *sender, const QH::Header &hdr) { - - BaseId requesterId = getSender(sender, &cardrequest); - - if (!cardrequest.isValid()) { - badRequest(sender->networkAddress(), hdr); - return ParserResult::Error; - } - - cardrequest._data = "responce for client " - - SendData(cardrequest, sender->networkAddress(), &pkg.hdr); - return ParserResult::Processed; + + QH::AbstractNode::NodeType nodeType() const override { + return QH::AbstractNode::NodeType::Server; } }; ``` -Create a client class and override parsePackage method for work with packages. +Create a client class and add supported parsers to work with packages. ```cpp class TestingClient: public QH::AbstractNode { - -protected: - // parsing incoming packages - ParserResult parsePackage(const Package &pkg, - const AbstractNodeInfo *sender) { - - auto parentResult = AbstractNode::parsePackage(pkg, sender); - if (parentResult != ParserResult::NotProcessed) { - return parentResult; - } - - if (MyPackage::command() == pkg.hdr.command) { - MyPackage obj(pkg); - - // print responce of server - std::cout << obj._data; - ... - return ParserResult::Processed; - } - // Do not forget return status of parsing packages - return ParserResult::NotProcessed; - +public: + TestingClient() { + addApiParser(); } - // sending request to server - bool sendMyPackage() { - Ping cmd; - return sendData(&cmd, address); + + QH::AbstractNode::NodeType nodeType() const override { + return QH::AbstractNode::NodeType::Client; } }; ``` diff --git a/src/heart.h b/src/heart.h index 555b8d20..4622db42 100644 --- a/src/heart.h +++ b/src/heart.h @@ -15,10 +15,14 @@ inline void initResources() { Q_INIT_RESOURCE(ProtockolResusces); } /** * @brief The QH namespace - QuasarApp Heart namespace. This namespace contains all classes of the Heart library. + * * Usage: - * 1. First one you need to create a package for transporting data betwin server and client. For this you need to do Inheritance with the - * QF::PKG::AbstrcatData class. So, You need to override 2 serialization methods of AbstrcatData and the copyFrom method. + * + * 1. First one, you need to create a package for transporting data between server and client. For this you need to do Inheritance with the + * QF::PKG::AbstrcatData class. + * * Example: The package for transporting text data. + * * \code{cpp} class MyPackage: public QH::AbstractData { @@ -46,18 +50,21 @@ class MyPackage: public QH::AbstractData }; * \endcode - * @note The method copyFrom is not necessary method so you can be skip it. Bud if you want override it then you need to override like in example, with check of object type. If you do not override this method or override it not correctly then copy data from another package do not work correctly. In base case method copy From not using, but it is necessary for DBObject class - * 2. You need to create a Server class. For this you need to do Inheritance with the QF::AbstrcatData class - * Example: + * 2. You need to create a ApiParserClass - The API parser class should be inherited of the iParser class and implement all business logics of your client - server app. + * + * Example: * \code{cpp} -class TestingServer: public QH::AbstractNode { -Q_OBJECT -public: - TestingServer() { - registerPackageType(); + * + * class MyParser: public QH::iParser { + public: + MyParser(QH::AbstractNode* parentNode): QH::iParser(parentNode) { + registerPackageType(); + data = new BigPackage(); } -protected: + // iParser interface + public: + // override this method for processed received data. ParserResult parsePackage(const Package &pkg, const AbstractNodeInfo *sender) { @@ -76,7 +83,7 @@ Q_OBJECT } bool processMyPackage(const QSharedPointer &cardrequest, - const QH::AbstractNodeInfo *sender, const QH::Header &hdr) { + const QH::AbstractNodeInfo *sender, const QH::Header &hdr) { BaseId requesterId = getSender(sender, &cardrequest); @@ -87,12 +94,40 @@ Q_OBJECT cardrequest._data = "responce for client " - SendData(cardrequest, sender->networkAddress(), &pkg.hdr); + // responce only for servers. + if (nodeType() == QH::AbstractNode::NodeType::Server) + sendData(cardrequest, sender->networkAddress(), &pkg.hdr); + return ParserResult::Processed; } + + // This vesion of the parser (any digital value.) . + int version() const override {return 0;}; + QString parserId() const override {return "MyParser";}; + + }; + \endcode + * + * + * 3. You need to create a Server class. For this, you need to do Inheritance with the QF::AbstrcatData class + +* Example: + +* \code{cpp} +class TestingServer: public QH::AbstractNode { +Q_OBJECT +public: + TestingServer() { + addApiParser(); + } + + QH::AbstractNode::NodeType nodeType() const override { + return QH::AbstractNode::NodeType::Server; + } }; * \endcode - * This is simple echo server for our client - server application. + * + * This is a simple echo server for our client - server application. * For Run this serve use method QF::AbstrcatData::run * * \code{cpp} @@ -101,55 +136,48 @@ Q_OBJECT testServer.run("127.0.0.1", 7777) } \endcode - * 3. Create a client application class. - * Client and server must be inheritance from QF::AbstrcatData class for support parsing packages. + + * 4. Create a client application class. + * Client and server must be inheritance from QF::AbstrcatData class to support parsing packages. * \code{cpp} class TestingClient: public QH::AbstractNode { - -protected: - // parsing incoming packages - ParserResult parsePackage(const Package &pkg, - const AbstractNodeInfo *sender) { - - auto parentResult = AbstractNode::parsePackage(pkg, sender); - if (parentResult != ParserResult::NotProcessed) { - return parentResult; - } - - if (MyPackage::command() == pkg.hdr.command) { - MyPackage obj(pkg); - - // print responce of server - std::cout << obj._data; - ... - return ParserResult::Processed; - } - // Do not forget return status of parsing packages - return ParserResult::NotProcessed; - +public: + TestingClient() { + addApiParser(); } - // sending request to server - bool sendMyPackage() { - Ping cmd; - return sendData(&cmd, address); + + QH::AbstractNode::NodeType nodeType() const override { + return QH::AbstractNode::NodeType::Client; } }; * \endcode * * The basic principle of the library. * - * Node - it is server or client implementation of any of AbstractNode class of it child classes. - * - The node receive raw data from another network connection. - * - After parsing a raw data the node convert a bytes array to QH::Package. - * - The Package create a new thread for working with received request, so, all working of package working in own threads. - * - Next, the Node invoke a QH::AbstractNode::parsePackage method. This method must be return QH::ParserResult. - * @note Do not forget invoke the super class parsePackage method. - * - The Last step it is invoke your override parsePackage method on your server or client class. - * IF you need to send responce then use a unsigned int sendData(PKG::AbstractData *resp, const HostAddress& addere, const Header *req = nullptr). - * - * Work scheme: - *\image html Async.svg width=800px + * Node - it is the server or client implementation of any AbstractNode child's classes. + * - The node receives raw data from another network connection. + * - After parsing a raw data, the node converts a bytes array to QH::Package. + * - The Package creates a new thread for working with received request, so, all working of package working in own threads. + * - Next, the Node invokes a QH::iParser::parsePackage method of selected parsers. This method must be return QH::ParserResult. + * - IF you need to send response then use a unsigned int sendData(PKG::AbstractData *resp, const HostAddress& addere, const Header *req = nullptr). + * + * **About parsers** + * + * The Parser it is an object that works with your packages. You can create multiple version's parser for compatibility between node versions. Node will select most actually version that known both nodes. For example, server known parsers with version 1, 2 and 3 but client can work only with 1 and 2, so nodes choose parser v2 because all nodes known about this parser version. + * + * You can create multiple types of the parsers. For example, you want to create an absolute new API and add it to the node. You need override + * Example: + * + * \code{cpp} + * TestingClient() { + addApiParser(); + addApiParser(); + addApiParser(); + addApiParser(); + + } + * \endcode */ namespace QH { /** diff --git a/src/public/abstractnode.h b/src/public/abstractnode.h index fa5e362d..71757e94 100644 --- a/src/public/abstractnode.h +++ b/src/public/abstractnode.h @@ -102,13 +102,13 @@ class Abstract; /** * @brief The AbstractNode class - Abstract implementation of node. * this implementation have a methods for send and receive data messages, - * and work with crypto method for crease a security connections betwin nodes. + * and work with crypto method for create a security connections betwin nodes. * AbstractNode - is thread save class. * - * @note For correctly working this class you should be register all you data types using the AbstractNode::registerPackageType method. + * @note For correctly working this class you should be register all you dataParser types using the AbstractNode::addApiParser method. * @see AbstractData - * @see AbstractNode::registerPackageType - * @see AbstractNode::parsePackage + * @see iParser + * @see AbstractNode::addApiParser */ class HEARTSHARED_EXPORT AbstractNode : public QTcpServer, public SoftDelete { @@ -116,6 +116,20 @@ class HEARTSHARED_EXPORT AbstractNode : public QTcpServer, public SoftDelete public: + /** + * @brief The NodeType enum contains types of the node. By default node contains only 3 types. + */ + enum NodeType: int { + /// Node with this type is general clints nodes. + Client = 0, + + /// Node with this ytpe is midle nodes that can works as a client and as servers. + Node = 1, + + /// This is node can works only as a public server + Server = 2 + }; + /** * @brief AbstractNode - Base constructor of node. * @param ptr - Pointrt to parent Qt object, the AbstractNode class is Q_OBJECT. @@ -124,6 +138,12 @@ class HEARTSHARED_EXPORT AbstractNode : public QTcpServer, public SoftDelete AbstractNode(QObject * ptr = nullptr); ~AbstractNode() override; + /** + * @brief nodeType This method should be return type of the serve. + * @return node type q qq + */ + virtual NodeType nodeType() const = 0; + /** * @brief run This method implement deployment a network node (server) on selected address. * @param addres This is network address of work node or server. diff --git a/src/public/packages/abstractdata.cpp b/src/public/packages/abstractdata.cpp index 0d6fd4ff..2dcf0d86 100644 --- a/src/public/packages/abstractdata.cpp +++ b/src/public/packages/abstractdata.cpp @@ -73,10 +73,6 @@ bool AbstractData::isValid() const { return true; } -bool AbstractData::copyFrom(const AbstractData *other) { - return other; -} - QString AbstractData::toString() const { return QString("Object: type:%0, command:%1"). arg(cmdString()). diff --git a/src/public/packages/abstractdata.h b/src/public/packages/abstractdata.h index 8926366e..0ce092af 100644 --- a/src/public/packages/abstractdata.h +++ b/src/public/packages/abstractdata.h @@ -74,63 +74,7 @@ namespace PKG { * \endcode * This is simple implementation of package for transport text data. * You need to override 2 serialization methods (fromStream and toStream). - * For add the copying functionality of you class, you need to override the copyFrom method. - * \code {cpp} - * class MyPackage: public QH::AbstractData -{ - QH_PACKAGE(MyPackage, "MyPackage") - ... - bool copyFrom(const AbstractData *other) { - if (!AbstractData::copyFrom(other)) - return false; - - auto otherObject = dynamic_cast(other); - if (!otherObject) - return false; - - this->_data = otherObject->_data; - return true; - }; - - // your data for for server of client - std::string _data = ""; - ... -}; - * \endcode - * This method copyFrom supports copying between parent and child classes. - * Consider the situation: - * Classes A > B > C - * - \code{cpp} - A * a = new A; - A * b = new B; - A * c = new C; - \endcode - * The situation when the classes have the same type. - * In this case, all object fields will be copied. - - \code{cpp} - b.copyFrom (b1) // true - c.copyFrom (c1) // true - \endcode - - * The situation when the class Requesting data to be copied is a child of the class that is requesting data to be copied. - \code{cpp} - b.copyFrom (a) // false - c.copyFrom (a) // false - \endcode - -* In this case, copying will be partially performed and the result of calling the copyFrom method will be false, since the data has not been copied for all members of the child class. -* The situation when the class Requesting data to be copied is the parent of the class from which data to be copied is requested. -* In this case, all possible data will be copied and returned true. - - \code{cpp} - a.copyFrom (b) // true - a.copyFrom (c) // true - \endcode - * That is why it is important that the implementation of the copyFrom method is exactly the same as shown in the example. - * If the implementation of this method differs from the example, the data will not be copied correctly. * @see AbstractNode */ class HEARTSHARED_EXPORT AbstractData : public StreamBase, public QuasarAppUtils::iHRO @@ -187,27 +131,6 @@ class HEARTSHARED_EXPORT AbstractData : public StreamBase, public QuasarAppUtils */ virtual bool isValid() const; - /** - * @brief copyFrom This method copyFrom supports copying between parent and child classes. - * @note The implementation of this method must be like a example: - * \code - bool copyFrom(const AbstractData *other) { - if (!AbstractData::copyFrom(other)) - return false; - - auto otherObject = dynamic_cast(other); - if (!otherObject) - return false; - - this->_data = otherObject->_data; - return true; - }; - * \endcode - * @param other - Pointer to anther object. - * @return True all members of current object is updated. - */ - virtual bool copyFrom(const AbstractData* other); - /** * @brief toString - Return a string implementation for this object. * @return String of object. diff --git a/src/public/packages/dbobject.cpp b/src/public/packages/dbobject.cpp index 17483c93..cba83484 100644 --- a/src/public/packages/dbobject.cpp +++ b/src/public/packages/dbobject.cpp @@ -236,15 +236,6 @@ DbAddress DBObject::dbAddress() const { return {table(), primaryValue()}; } -DBObject *DBObject::cloneRaw() const { - auto cloneObject = createDBObject(); - if (!cloneObject->copyFrom(this)) { - return nullptr; - } - - return cloneObject; -} - QString DBObject::toString() const { return AbstractData::toString() + QString(" %0").arg(dbAddress().toString()); @@ -317,10 +308,6 @@ bool DBObject::isValid() const { return table().size(); } -bool DBObject::copyFrom(const AbstractData * other) { - return AbstractData::copyFrom(other); -} - bool DBObject::isHaveAPrimaryKey() const { return primaryKey().size(); } diff --git a/src/public/packages/dbobject.h b/src/public/packages/dbobject.h index fb20bba0..a0f5a7d7 100644 --- a/src/public/packages/dbobject.h +++ b/src/public/packages/dbobject.h @@ -104,7 +104,6 @@ class HEARTSHARED_EXPORT DBObject : public AbstractData ~DBObject() override; bool isValid() const override; - bool copyFrom(const AbstractData * other) override; /** * @brief isHaveAPrimaryKey This method return true if this object has a primary key. @@ -327,28 +326,6 @@ class HEARTSHARED_EXPORT DBObject : public AbstractData */ DbAddress dbAddress() const; - /** - * @brief clone This method create a new object. The new Object is clone of current object. - * This method is template, so you can set needed type for result. - * \code{cpp} - * MyObject->clone(); - * \endcode - * @note If you want to get raw pointer to the clone object use a DBObject::cloneRaw method. - * @return The shared pointer to clone of current object. - */ - template - QSharedPointer clone() const { - return QSharedPointer(dynamic_cast(cloneRaw())); - } - - /** - * @brief cloneRaw This method return a raw pointer to clone of this object. - * @warning clone object do not removed automatically and may result in a memory leak. - * @note for get a shared pointer of clone object use the DBObject::clone method. - * @return The raw pointer to clone of this object. - */ - DBObject* cloneRaw() const; - QString toString() const override; /** diff --git a/src/public/packages/dbobjectsrequest.h b/src/public/packages/dbobjectsrequest.h index 4c6c4117..9ada7311 100644 --- a/src/public/packages/dbobjectsrequest.h +++ b/src/public/packages/dbobjectsrequest.h @@ -93,10 +93,6 @@ class DBObjectsRequest final: public DBObjectSet return true; }; - bool copyFrom(const AbstractData *) override { - return false; - }; - /** * @brief data This method return a list of getted objects. * @return list of const T * objects. From 1da863be76fb748266e739e472888f79326912d9 Mon Sep 17 00:00:00 2001 From: Andrei Yankovich Date: Thu, 1 Dec 2022 22:08:28 +0300 Subject: [PATCH 2/3] Update README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 23a02d82..de3927bc 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,6 @@ This library consists of two levels (AbstractNode level and DataBaseNode level). add_subdirectory(Heart) ``` - * select requirement build level for your project - - ```cmake - set(HEART_BUILD_LVL 2) - ``` where 1 - is code of build level 1 - AbstractNode From e3ec4b3ef44623cf8fa860813368e22e89e4870c Mon Sep 17 00:00:00 2001 From: EndrII Date: Thu, 1 Dec 2022 22:21:10 +0300 Subject: [PATCH 3/3] simple fixes --- src/heart.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/heart.h b/src/heart.h index 4622db42..69a98854 100644 --- a/src/heart.h +++ b/src/heart.h @@ -171,10 +171,10 @@ class TestingClient: public QH::AbstractNode { * * \code{cpp} * TestingClient() { - addApiParser(); - addApiParser(); - addApiParser(); - addApiParser(); + iParser::addApiParser(); + iParser::addApiParser(); + iParser::addApiParser(); + iParser::addApiParser(); } * \endcode