diff --git a/.gitignore b/.gitignore index ef2bc5b..2394a34 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,10 @@ ui_*.h *.jsc Makefile* *build-* + +Heart/build/ +HeartTests/build/ + ServerProtocol/build/ ClientProtocol/build/ ProtocolTests/build/ diff --git a/.gitmodules b/.gitmodules index e5e4750..44502c6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "QuasarAppLib"] path = QuasarAppLib url = https://github.com/QuasarApp/QuasarAppLib.git -[submodule "openssl-cmake"] - path = openssl-cmake - url = https://github.com/QuasarApp/openssl-cmake.git +[submodule "Heart/Qt-Secret"] + path = Heart/Qt-Secret + url = https://github.com/QuasarApp/Qt-Secret.git diff --git a/CMakeLists.txt b/CMakeLists.txt index b0074df..98d5e8b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,15 +5,26 @@ # of this license document, but changing it is not allowed. # -cmake_minimum_required(VERSION 3.1) -project(MainNetworkProtocol) +cmake_minimum_required(VERSION 3.10) +project(Heart) +if(TARGET ${PROJECT_NAME}) + message("The ${PROJECT_NAME} arledy included in main Project") + return() +endif() + +find_package(Qt5 COMPONENTS Core Test REQUIRED) +if(NOT DEFINED BUILD_LVL) + set(BUILD_LVL 2) +endif() include(QuasarAppLib/CMake/ccache.cmake) # Add sub directories add_subdirectory(QuasarAppLib) -add_subdirectory(openssl-cmake) -add_subdirectory(NetworkProtocol) -add_subdirectory(ProtocolTests) +add_subdirectory(Heart) +add_subdirectory(HeartTests) +include(QuasarAppLib/CMake/QuasarAppCITargets.cmake) +initAll() +addDoc(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/doxygen.conf) diff --git a/Heart/AbstractSpace/Diagrams/async.qmodel b/Heart/AbstractSpace/Diagrams/async.qmodel new file mode 100644 index 0000000..cab728d --- /dev/null +++ b/Heart/AbstractSpace/Diagrams/async.qmodel @@ -0,0 +1,1533 @@ +<?xml version="1.0" encoding="UTF-8"?> +<qmt> + <project> + <uid>{1974d1c6-c7fd-48c9-8716-2963ce55ae17}</uid> + <root-package> + <instance> + <MPackage> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{1b070744-3368-47f3-a6d5-cba2dcf13046}</uid> + </MElement> + </base-MElement> + <name>ASync</name> + <children> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{86c65e6e-c6f3-4bdf-bf60-d469507385f7}</uid> + <target> + <instance type="MPackage"> + <MPackage> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{86c65e6e-c6f3-4bdf-bf60-d469507385f7}</uid> + <flags>1</flags> + </MElement> + </base-MElement> + <name>AbstractSpace</name> + <children> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{40b050a2-cbb3-434a-9820-a0408dd9cc65}</uid> + <target> + <instance type="MComponent"> + <MComponent> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{40b050a2-cbb3-434a-9820-a0408dd9cc65}</uid> + <flags>1</flags> + </MElement> + </base-MElement> + <name>Abstractnode</name> + </MObject> + </base-MObject> + </MComponent> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{8545c84f-1e54-4c66-89cc-144f97258d62}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{8545c84f-1e54-4c66-89cc-144f97258d62}</uid> + </MElement> + </base-MElement> + <name>Query Requests</name> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{a70d4258-8d62-43ef-b4e7-1692461ccf90}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{a70d4258-8d62-43ef-b4e7-1692461ccf90}</uid> + </MElement> + </base-MElement> + <name>Query Ansvers</name> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{afca4323-c099-43df-bcf7-7a27bbc1f446}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{afca4323-c099-43df-bcf7-7a27bbc1f446}</uid> + </MElement> + </base-MElement> + <name>ParsePackages</name> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{e7079bb7-d428-4713-a2f3-57f9a3375122}</uid> + <target> + <instance type="MClass"> + <MClass> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{e7079bb7-d428-4713-a2f3-57f9a3375122}</uid> + <flags>1</flags> + </MElement> + </base-MElement> + <name>AbstractNode</name> + </MObject> + </base-MObject> + <namespace>NP</namespace> + </MClass> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{8f375085-5620-4004-9ae7-7e32c43feea5}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{8f375085-5620-4004-9ae7-7e32c43feea5}</uid> + </MElement> + </base-MElement> + <name>The parse package method</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{cf56cda1-41e3-489b-86a2-86339b791932}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{cf56cda1-41e3-489b-86a2-86339b791932}</uid> + </MElement> + </base-MElement> + <a>{8f375085-5620-4004-9ae7-7e32c43feea5}</a> + <b>{1373dedb-4ef1-4be0-9460-0ba97d459b90}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{6a3d28a1-2c8e-409a-b753-7dc67d47e018}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{6a3d28a1-2c8e-409a-b753-7dc67d47e018}</uid> + </MElement> + </base-MElement> + <a>{8f375085-5620-4004-9ae7-7e32c43feea5}</a> + <b>{bf0a2ec5-b735-486d-a6fe-c6eb9d5015a2}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{0f996b7d-48da-4943-a892-7366c1f9b281}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{0f996b7d-48da-4943-a892-7366c1f9b281}</uid> + </MElement> + </base-MElement> + <a>{8f375085-5620-4004-9ae7-7e32c43feea5}</a> + <b>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{4d4021b6-9181-4f94-9c09-4156208757e8}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{4d4021b6-9181-4f94-9c09-4156208757e8}</uid> + </MElement> + </base-MElement> + <a>{8f375085-5620-4004-9ae7-7e32c43feea5}</a> + <b>{40d2a713-bd35-4771-8c50-37751fe5189f}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{f24ea0a9-3593-416e-a111-88940ce34f49}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{f24ea0a9-3593-416e-a111-88940ce34f49}</uid> + </MElement> + </base-MElement> + <name>The receive requests queue</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{fddcabd3-67ca-4a34-be6b-4260bcb3061d}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{fddcabd3-67ca-4a34-be6b-4260bcb3061d}</uid> + </MElement> + </base-MElement> + <a>{f24ea0a9-3593-416e-a111-88940ce34f49}</a> + <b>{5de24217-86bc-4d17-af6e-f04b85f06dd0}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{1373dedb-4ef1-4be0-9460-0ba97d459b90}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{1373dedb-4ef1-4be0-9460-0ba97d459b90}</uid> + </MElement> + </base-MElement> + <name>The send data quese</name> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{5de24217-86bc-4d17-af6e-f04b85f06dd0}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{5de24217-86bc-4d17-af6e-f04b85f06dd0}</uid> + </MElement> + </base-MElement> + <name>The creqate new thread method</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{9e47f596-226e-40b4-8924-2d7a94598965}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{9e47f596-226e-40b4-8924-2d7a94598965}</uid> + </MElement> + </base-MElement> + <a>{5de24217-86bc-4d17-af6e-f04b85f06dd0}</a> + <b>{8f375085-5620-4004-9ae7-7e32c43feea5}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{65d31fce-4ab2-480f-ba4e-c7d9ef88ec5a}</uid> + <target> + <instance type="MComponent"> + <MComponent> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{65d31fce-4ab2-480f-ba4e-c7d9ef88ec5a}</uid> + <stereotypes> + <qlist> + <item>database</item> + </qlist> + </stereotypes> + </MElement> + </base-MElement> + <name>The node local database</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{d5513e8f-8603-4a7f-b2ff-701ef575832b}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{d5513e8f-8603-4a7f-b2ff-701ef575832b}</uid> + </MElement> + </base-MElement> + <a>{65d31fce-4ab2-480f-ba4e-c7d9ef88ec5a}</a> + <b>{1de1752c-e400-4b0e-ad11-09545278d17a}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MComponent> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{bf0a2ec5-b735-486d-a6fe-c6eb9d5015a2}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{bf0a2ec5-b735-486d-a6fe-c6eb9d5015a2}</uid> + </MElement> + </base-MElement> + <name>The database query queue</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{bb488713-7f01-4415-a0bf-2cb4cbe178ec}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{bb488713-7f01-4415-a0bf-2cb4cbe178ec}</uid> + </MElement> + </base-MElement> + <a>{bf0a2ec5-b735-486d-a6fe-c6eb9d5015a2}</a> + <b>{65d31fce-4ab2-480f-ba4e-c7d9ef88ec5a}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{1de1752c-e400-4b0e-ad11-09545278d17a}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{1de1752c-e400-4b0e-ad11-09545278d17a}</uid> + </MElement> + </base-MElement> + <name>The database query responce </name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{980d3496-d03f-41e8-991a-99acf90eccce}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{980d3496-d03f-41e8-991a-99acf90eccce}</uid> + </MElement> + </base-MElement> + <a>{1de1752c-e400-4b0e-ad11-09545278d17a}</a> + <b>{8f375085-5620-4004-9ae7-7e32c43feea5}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{73f9a73d-09fb-4229-ac05-3660187042ad}</uid> + <target> + <instance type="MClass"> + <MClass> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{73f9a73d-09fb-4229-ac05-3660187042ad}</uid> + <stereotypes> + <qlist> + <item>control</item> + </qlist> + </stereotypes> + </MElement> + </base-MElement> + <name>Reactor</name> + </MObject> + </base-MObject> + </MClass> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{6edf2143-f2a9-4105-aa4b-002be4c94598}</uid> + <target> + <instance type="MComponent"> + <MComponent> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{6edf2143-f2a9-4105-aa4b-002be4c94598}</uid> + </MElement> + </base-MElement> + <name>Resources</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{40cd4b53-4259-4a9c-b431-567256b55a89}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{40cd4b53-4259-4a9c-b431-567256b55a89}</uid> + </MElement> + </base-MElement> + <a>{6edf2143-f2a9-4105-aa4b-002be4c94598}</a> + <b>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MComponent> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</uid> + </MElement> + </base-MElement> + <name>The read access resource method</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{70b4c7b3-c196-4773-808a-4379f43951ce}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{70b4c7b3-c196-4773-808a-4379f43951ce}</uid> + </MElement> + </base-MElement> + <a>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</a> + <b>{8f375085-5620-4004-9ae7-7e32c43feea5}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{40d2a713-bd35-4771-8c50-37751fe5189f}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{40d2a713-bd35-4771-8c50-37751fe5189f}</uid> + </MElement> + </base-MElement> + <name>The write access resource method</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{cea9150d-5e52-45de-91d6-a4e449e02b7f}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{cea9150d-5e52-45de-91d6-a4e449e02b7f}</uid> + </MElement> + </base-MElement> + <a>{40d2a713-bd35-4771-8c50-37751fe5189f}</a> + <b>{6edf2143-f2a9-4105-aa4b-002be4c94598}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{00b549d9-14df-49f9-88c5-f6f17429cf68}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{00b549d9-14df-49f9-88c5-f6f17429cf68}</uid> + </MElement> + </base-MElement> + <a>{40d2a713-bd35-4771-8c50-37751fe5189f}</a> + <b>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </children> + </MObject> + </base-MObject> + </MPackage> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{0ab10749-acf2-4e9e-b842-70cad3fc4fe3}</uid> + <target> + <instance type="MCanvasDiagram"> + <MCanvasDiagram> + <base-MDiagram> + <MDiagram> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{0ab10749-acf2-4e9e-b842-70cad3fc4fe3}</uid> + </MElement> + </base-MElement> + <name>Async</name> + </MObject> + </base-MObject> + <elements> + <qlist> + <item> + <instance type="DSwimlane"> + <DSwimlane> + <base-DElement> + <DElement> + <uid>{2395da40-7373-418f-8c2d-d91a7b380768}</uid> + </DElement> + </base-DElement> + <pos>850</pos> + </DSwimlane> + </instance> + </item> + <item> + <instance type="DAnnotation"> + <DAnnotation> + <base-DElement> + <DElement> + <uid>{d11cc136-9832-4aec-abe0-03c63f7094a0}</uid> + </DElement> + </base-DElement> + <text>New Thread</text> + <pos>x:1214;y:20</pos> + <rect>x:0;y:0;w:131;h:35</rect> + <auto-sized>false</auto-sized> + <visual-role>1</visual-role> + </DAnnotation> + </instance> + </item> + <item> + <instance type="DAnnotation"> + <DAnnotation> + <base-DElement> + <DElement> + <uid>{0e0c334c-818f-4c92-9e29-c031cf2ce1c7}</uid> + </DElement> + </base-DElement> + <text>Main Thread</text> + <pos>x:345;y:20</pos> + <rect>x:0;y:0;w:130.203;h:35</rect> + <auto-sized>false</auto-sized> + <visual-role>1</visual-role> + </DAnnotation> + </instance> + </item> + <item> + <instance type="DClass"> + <DClass> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{bd8919c0-bcf8-42fa-8676-7f2861b755a3}</uid> + </DElement> + </base-DElement> + <object>{e7079bb7-d428-4713-a2f3-57f9a3375122}</object> + <context>AbstractSpace</context> + <name>AbstractNode</name> + <pos>x:390;y:560</pos> + <rect>x:-330;y:-380;w:660;h:760</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <namespace>NP</namespace> + <show-all-members>true</show-all-members> + </DClass> + </instance> + </item> + <item> + <instance type="DSwimlane"> + <DSwimlane> + <base-DElement> + <DElement> + <uid>{9c9b85d3-f59f-4779-9d17-eecf5bbe10b2}</uid> + </DElement> + </base-DElement> + <pos>847</pos> + </DSwimlane> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</uid> + </DElement> + </base-DElement> + <object>{8f375085-5620-4004-9ae7-7e32c43feea5}</object> + <context>AbstractSpace</context> + <name>The parse package method</name> + <pos>x:1250;y:410</pos> + <rect>x:-160;y:-230;w:320;h:460</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{20b03ae8-9739-4586-9194-7b7e782d3fc2}</uid> + </DElement> + </base-DElement> + <object>{f24ea0a9-3593-416e-a111-88940ce34f49}</object> + <context>AbstractSpace</context> + <name>The receive requests queue</name> + <pos>x:390;y:320</pos> + <rect>x:-210;y:-25;w:420;h:50</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{2daf0614-b530-4b06-b55c-728d9fbd31c9}</uid> + </DElement> + </base-DElement> + <object>{1373dedb-4ef1-4be0-9460-0ba97d459b90}</object> + <context>AbstractSpace</context> + <name>The send data quese</name> + <pos>x:390;y:480</pos> + <rect>x:-210;y:-25;w:420;h:50</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{050ed47c-af5b-4682-a3fa-acf6fd9bef76}</uid> + </DElement> + </base-DElement> + <object>{5de24217-86bc-4d17-af6e-f04b85f06dd0}</object> + <context>AbstractSpace</context> + <name>The creqate new thread method</name> + <pos>x:390;y:400</pos> + <rect>x:-210;y:-25;w:420;h:50</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{370f4db6-c64f-456c-8347-cb224eede005}</uid> + </DElement> + </base-DElement> + <object>{fddcabd3-67ca-4a34-be6b-4260bcb3061d}</object> + <a>{20b03ae8-9739-4586-9194-7b7e782d3fc2}</a> + <b>{050ed47c-af5b-4682-a3fa-acf6fd9bef76}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{07029368-3504-405d-8f65-9427efc3d7e4}</uid> + </DElement> + </base-DElement> + <object>{9e47f596-226e-40b4-8924-2d7a94598965}</object> + <a>{050ed47c-af5b-4682-a3fa-acf6fd9bef76}</a> + <b>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{6e9a48e7-7922-472c-a9a5-096b550f7b38}</uid> + </DElement> + </base-DElement> + <object>{cf56cda1-41e3-489b-86a2-86339b791932}</object> + <a>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</a> + <b>{2daf0614-b530-4b06-b55c-728d9fbd31c9}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DComponent"> + <DComponent> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{b3e457d3-9253-4426-8ed3-7f74da75c214}</uid> + </DElement> + </base-DElement> + <object>{65d31fce-4ab2-480f-ba4e-c7d9ef88ec5a}</object> + <stereotypes> + <qlist> + <item>database</item> + </qlist> + </stereotypes> + <context>AbstractSpace</context> + <name>The node local database</name> + <pos>x:-205;y:585</pos> + <rect>x:-170;y:-130;w:340;h:260</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + </DComponent> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{9d146685-5100-4a63-b8bd-a046bac771d4}</uid> + </DElement> + </base-DElement> + <object>{bf0a2ec5-b735-486d-a6fe-c6eb9d5015a2}</object> + <context>AbstractSpace</context> + <name>The database query queue</name> + <pos>x:390;y:620</pos> + <rect>x:-210;y:-25;w:420;h:50</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{93fdf02a-73f5-45eb-9670-ab53850ff8e1}</uid> + </DElement> + </base-DElement> + <object>{1de1752c-e400-4b0e-ad11-09545278d17a}</object> + <context>AbstractSpace</context> + <name>The database query responce </name> + <pos>x:390;y:560</pos> + <rect>x:-210;y:-25;w:420;h:50</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{13f182c2-05e1-47d8-95e8-43935f14efad}</uid> + </DElement> + </base-DElement> + <object>{bb488713-7f01-4415-a0bf-2cb4cbe178ec}</object> + <a>{9d146685-5100-4a63-b8bd-a046bac771d4}</a> + <b>{b3e457d3-9253-4426-8ed3-7f74da75c214}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{e434b177-2e13-451b-9e75-fa5bbfa2b5d4}</uid> + </DElement> + </base-DElement> + <object>{d5513e8f-8603-4a7f-b2ff-701ef575832b}</object> + <a>{b3e457d3-9253-4426-8ed3-7f74da75c214}</a> + <b>{93fdf02a-73f5-45eb-9670-ab53850ff8e1}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{318f0dbe-2a94-4ba2-938a-a6124524149f}</uid> + </DElement> + </base-DElement> + <object>{980d3496-d03f-41e8-991a-99acf90eccce}</object> + <a>{93fdf02a-73f5-45eb-9670-ab53850ff8e1}</a> + <b>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{7e188553-1343-499b-9a3a-ee744ba82255}</uid> + </DElement> + </base-DElement> + <object>{6a3d28a1-2c8e-409a-b753-7dc67d47e018}</object> + <a>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</a> + <b>{9d146685-5100-4a63-b8bd-a046bac771d4}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DClass"> + <DClass> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{2345e06d-8b72-4e2f-af25-292d24b9ace0}</uid> + </DElement> + </base-DElement> + <object>{73f9a73d-09fb-4229-ac05-3660187042ad}</object> + <stereotypes> + <qlist> + <item>control</item> + </qlist> + </stereotypes> + <context>AbstractSpace</context> + <name>Reactor</name> + <pos>x:700;y:215</pos> + <rect>x:-75;y:-75;w:150;h:150</rect> + <auto-sized>false</auto-sized> + <visual-role>7</visual-role> + </DObject> + </base-DObject> + </DClass> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{c839657e-fc23-401a-9a2e-3f382ba23c00}</uid> + </DElement> + </base-DElement> + <object>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</object> + <name>IncommingData</name> + <pos>x:1250;y:815</pos> + <rect>x:-160;y:-125;w:320;h:250</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{b4494e04-29bc-4a92-b70b-47bd9105a420}</uid> + </DElement> + </base-DElement> + <object>{0f996b7d-48da-4943-a892-7366c1f9b281}</object> + <a>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</a> + <b>{c839657e-fc23-401a-9a2e-3f382ba23c00}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DComponent"> + <DComponent> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{4528e67d-57d8-49d8-a199-f5952fee44dc}</uid> + </DElement> + </base-DElement> + <object>{6edf2143-f2a9-4105-aa4b-002be4c94598}</object> + <context>AbstractSpace</context> + <name>Resources</name> + <pos>x:275;y:775</pos> + <rect>x:-95;y:-85;w:190;h:170</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + </DComponent> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{9ca6020c-5ca9-40ae-8241-b73042ba903e}</uid> + </DElement> + </base-DElement> + <object>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</object> + <context>AbstractSpace</context> + <name>The read access resource method</name> + <pos>x:495;y:825</pos> + <rect>x:-100;y:-35;w:200;h:70</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DItem"> + <DItem> + <base-DObject> + <DObject> + <base-DElement> + <DElement> + <uid>{92eb5579-50a4-4998-9562-6b5b3e87cd74}</uid> + </DElement> + </base-DElement> + <object>{40d2a713-bd35-4771-8c50-37751fe5189f}</object> + <context>AbstractSpace</context> + <name>The write access resource method</name> + <pos>x:495;y:725</pos> + <rect>x:-100;y:-35;w:200;h:70</rect> + <auto-sized>false</auto-sized> + <visual-role>0</visual-role> + </DObject> + </base-DObject> + <shape-editable>false</shape-editable> + </DItem> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{21d44974-21d3-4313-971e-ef4f6f7e6e87}</uid> + </DElement> + </base-DElement> + <object>{70b4c7b3-c196-4773-808a-4379f43951ce}</object> + <a>{9ca6020c-5ca9-40ae-8241-b73042ba903e}</a> + <b>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{6e3a6e67-72d1-4b47-bf87-fbc84e21eeaa}</uid> + </DElement> + </base-DElement> + <object>{4d4021b6-9181-4f94-9c09-4156208757e8}</object> + <a>{23685ca4-7c6a-414e-9ef5-3326d1089b89}</a> + <b>{92eb5579-50a4-4998-9562-6b5b3e87cd74}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{95b4600e-1953-4913-93aa-e2cc66b7fbb5}</uid> + </DElement> + </base-DElement> + <object>{cea9150d-5e52-45de-91d6-a4e449e02b7f}</object> + <a>{92eb5579-50a4-4998-9562-6b5b3e87cd74}</a> + <b>{4528e67d-57d8-49d8-a199-f5952fee44dc}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{7271e4c8-ec7e-4b94-9b1c-0d5e0306e4d8}</uid> + </DElement> + </base-DElement> + <object>{40cd4b53-4259-4a9c-b431-567256b55a89}</object> + <a>{4528e67d-57d8-49d8-a199-f5952fee44dc}</a> + <b>{9ca6020c-5ca9-40ae-8241-b73042ba903e}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{a5b780b8-5ec5-4c6a-8953-309a8c42ba76}</uid> + </DElement> + </base-DElement> + <object>{e26d62d4-6936-49c9-80ff-eb212b121fed}</object> + <a>{c839657e-fc23-401a-9a2e-3f382ba23c00}</a> + <b>{9ca6020c-5ca9-40ae-8241-b73042ba903e}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DDependency"> + <DDependency> + <base-DRelation> + <DRelation> + <base-DElement> + <DElement> + <uid>{0f7155a8-8c30-4702-96c6-19b1c9551c35}</uid> + </DElement> + </base-DElement> + <object>{00b549d9-14df-49f9-88c5-f6f17429cf68}</object> + <a>{92eb5579-50a4-4998-9562-6b5b3e87cd74}</a> + <b>{c839657e-fc23-401a-9a2e-3f382ba23c00}</b> + </DRelation> + </base-DRelation> + </DDependency> + </instance> + </item> + <item> + <instance type="DSwimlane"> + <DSwimlane> + <base-DElement> + <DElement> + <uid>{af7cc666-5e8e-4f97-9b57-3888b2009fa1}</uid> + </DElement> + </base-DElement> + <pos>10</pos> + </DSwimlane> + </instance> + </item> + <item> + <instance type="DAnnotation"> + <DAnnotation> + <base-DElement> + <DElement> + <uid>{5bf725ef-8090-4a3e-b7fb-25dd65b64da1}</uid> + </DElement> + </base-DElement> + <text>Local Storagge</text> + <pos>x:-250;y:15</pos> + <rect>x:0;y:0;w:123.438;h:35</rect> + <visual-role>1</visual-role> + </DAnnotation> + </instance> + </item> + </qlist> + </elements> + <last-modified>1596271151387</last-modified> + <toolbarid>General</toolbarid> + </MDiagram> + </base-MDiagram> + </MCanvasDiagram> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{94da9025-f1f6-4091-bebe-80acdd46e633}</uid> + <target> + <instance type="MPackage"> + <MPackage> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{94da9025-f1f6-4091-bebe-80acdd46e633}</uid> + </MElement> + </base-MElement> + <name>Создать пакет</name> + </MObject> + </base-MObject> + </MPackage> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</uid> + <target> + <instance type="MItem"> + <MItem> + <base-MObject> + <MObject> + <base-MElement> + <MElement> + <uid>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</uid> + </MElement> + </base-MElement> + <name>IncommingData</name> + <relations> + <handles> + <handles> + <qlist> + <item> + <handle> + <uid>{1cc78f12-2952-490e-952c-d76d678671a3}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{1cc78f12-2952-490e-952c-d76d678671a3}</uid> + </MElement> + </base-MElement> + <a>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</a> + <b>{8f375085-5620-4004-9ae7-7e32c43feea5}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + <item> + <handle> + <uid>{e26d62d4-6936-49c9-80ff-eb212b121fed}</uid> + <target> + <instance type="MDependency"> + <MDependency> + <base-MRelation> + <MRelation> + <base-MElement> + <MElement> + <uid>{e26d62d4-6936-49c9-80ff-eb212b121fed}</uid> + </MElement> + </base-MElement> + <a>{84ebdf50-06cb-4925-96dc-0f99b01e3c1f}</a> + <b>{ebf2dda3-0bb1-45e1-ae30-409baca6ee35}</b> + </MRelation> + </base-MRelation> + </MDependency> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </relations> + </MObject> + </base-MObject> + </MItem> + </instance> + </target> + </handle> + </item> + </qlist> + </handles> + </handles> + </children> + </MObject> + </base-MObject> + </MPackage> + </instance> + </root-package> + </project> +</qmt> diff --git a/Heart/AbstractSpace/Diagrams/header.h b/Heart/AbstractSpace/Diagrams/header.h new file mode 100644 index 0000000..e69de29 diff --git a/Heart/AbstractSpace/abstractnode.cpp b/Heart/AbstractSpace/abstractnode.cpp new file mode 100644 index 0000000..704a1c7 --- /dev/null +++ b/Heart/AbstractSpace/abstractnode.cpp @@ -0,0 +1,1030 @@ +/* + * Copyright (C) 2018-2020 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 "abstractnode.h" +#include "datasender.h" +#include "ping.h" +#include "qsecretrsa2048.h" +#include "workstate.h" +#include <QHostInfo> +#include <QSslCertificate> +#include <QSslKey> +#include <QSslSocket> +#include <badrequest.h> +#include <qrsaencryption.h> +#include <quasarapp.h> +#include <openssl/rsa.h> +#include <openssl/x509.h> +#include <openssl/pem.h> +#include <QMetaObject> +#include <QtConcurrent> +#include <closeconnection.h> + +namespace NP { + +AbstractNode::AbstractNode(SslMode mode, QObject *ptr): + QTcpServer(ptr) { + + _mode = mode; + + _dataSender = new DataSender(); + + setMode(_mode); +} + +bool AbstractNode::run(const QString &addres, unsigned short port) { + HostAddress adr(addres, port); + if (addres.isEmpty()) { + adr = HostAddress{QHostAddress::Any}; + } + + if (!listen(adr)) { + QuasarAppUtils::Params::log("Run fail " + this->errorString(), + QuasarAppUtils::Error); + return false; + } + + return true; +} + +void AbstractNode::stop() { + close(); + + QMutexLocker locer(&_connectionsMutex); + for (auto &&i : _connections) { + i->disconnect(); + } + + for (auto it: _workers) { + if (!it->isFinished()) + it->cancel(); + } +} + +AbstractNodeInfo *AbstractNode::getInfoPtr(const HostAddress &id) { + QMutexLocker locer(&_connectionsMutex); + + if (!_connections.contains(id)) { + return nullptr; + } + + return dynamic_cast<AbstractNodeInfo*>(_connections[id]); +} + +// fix me, if getInfoPtr invoced in an another thread and in some time main thread remove this object then +// this method return invalid object and application crashed. +const AbstractNodeInfo *AbstractNode::getInfoPtr(const HostAddress &id) const { + QMutexLocker locer(&_connectionsMutex); + + if (!_connections.contains(id)) { + return nullptr; + } + + return dynamic_cast<AbstractNodeInfo*>(_connections[id]); +} + +void AbstractNode::ban(const HostAddress &target) { + auto info = getInfoPtr(target); + if (info) + info->ban(); + +} + +void AbstractNode::unBan(const HostAddress &target) { + QMutexLocker locer(&_connectionsMutex); + + if (!_connections.contains(target) || _connections[target]) { + return; + } + + _connections[target]->unBan(); +} + +bool AbstractNode::connectToHost(const HostAddress &address, SslMode mode) { + QTcpSocket *socket; + if (mode == SslMode::NoSSL) { + socket = new QTcpSocket(nullptr); + } else { + socket = new QSslSocket(nullptr); + } + + if (!registerSocket(socket, &address)) { + return false; + } + + socket->connectToHost(address, address.port()); + + return true; +} + +bool AbstractNode::connectToHost(const QString &domain, unsigned short port, SslMode mode) { + QHostInfo::lookupHost(domain, [this, port, mode, domain](QHostInfo info) { + + if (info.error() != QHostInfo::NoError) { + QuasarAppUtils::Params::log("The domain name :" + domain + " has error: " + info.errorString(), + QuasarAppUtils::Error); + return; + } + + if (info.addresses().size() > 1) { + QuasarAppUtils::Params::log("The domain name :" + domain + " has more 1 ip addresses.", + QuasarAppUtils::Warning); + } + + + if (!connectToHost(HostAddress{info.addresses().first(), port}, mode)) { + return; + } + + auto hostObject = getInfoPtr(HostAddress{info.addresses().first(), port}); + + if (!hostObject) { + QuasarAppUtils::Params::log("The domain name :" + domain + " has connected bud not have network object!", + QuasarAppUtils::Error); + return; + } + + hostObject->setInfo(info); + }); + + return true; +} + +void AbstractNode::addNode(const HostAddress &nodeAdderess) { + + QMetaObject::invokeMethod(this, + "connectNodePrivate", + Qt::QueuedConnection, + Q_ARG(NP::HostAddress, nodeAdderess)); + +} + +void AbstractNode::removeNode(const HostAddress &nodeAdderess) { + + for (int status = static_cast<int>(NodeCoonectionStatus::NotConnected); + status < static_cast<int>(NodeCoonectionStatus::Confirmed); ++status) { + + takeFromQueue(nodeAdderess, static_cast<NodeCoonectionStatus>(status)); + } + + if (AbstractNodeInfo *ptr = getInfoPtr(nodeAdderess)) { + + if (ptr->isLocal()) { + ptr->disconnect(); + } else { + QTimer::singleShot(WAIT_CONFIRM_TIME, this, + std::bind(&AbstractNode::handleForceRemoveNode, this, nodeAdderess)); + } + } +} + +HostAddress AbstractNode::address() const { + return HostAddress{serverAddress(), serverPort()}; +} + +AbstractNode::~AbstractNode() { + // delete _nodeKeys; + stop(); +} + +QSslConfiguration AbstractNode::getSslConfig() const { + return _ssl; +} + +bool AbstractNode::generateRSAforSSL(EVP_PKEY *pkey) const { + RSA * rsa = nullptr; + if (!pkey) { + return false; + } + + if (!RSA_generate_key_ex(rsa, 2048, nullptr, nullptr)) { + return false; + } + + q_check_ptr(rsa); + if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) + return false; + + return true; +} + +bool AbstractNode::generateSslDataPrivate(const SslSrtData &data, QSslCertificate& r_srt, QSslKey& r_key) { + + EVP_PKEY *pkey = EVP_PKEY_new(); + + if (!generateRSAforSSL(pkey)) { + return false; + } + + X509 * x509 = nullptr; + X509_NAME * name = nullptr; + BIO * bp_public = nullptr, * bp_private = nullptr; + const char *buffer = nullptr; + int size; + + x509 = X509_new(); + q_check_ptr(x509); + ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); + X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time + X509_gmtime_adj(X509_get_notAfter(x509), data.endTime); // not after a year from this point + X509_set_pubkey(x509, pkey); + name = X509_get_subject_name(x509); + q_check_ptr(name); + + unsigned char *C = reinterpret_cast<unsigned char *>(data.country.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, C, -1, -1, 0); + + unsigned char *O = reinterpret_cast<unsigned char *>(data.organization.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, O, -1, -1, 0); + + unsigned char *CN = reinterpret_cast<unsigned char *>(data.commonName.toLatin1().data()); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, CN, -1, -1, 0); + + X509_set_issuer_name(x509, name); + X509_sign(x509, pkey, EVP_sha256()); + bp_private = BIO_new(BIO_s_mem()); + q_check_ptr(bp_private); + if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1) { + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free_all(bp_private); + qCritical("PEM_write_bio_PrivateKey"); + return false; + + } + + bp_public = BIO_new(BIO_s_mem()); + q_check_ptr(bp_public); + if(PEM_write_bio_X509(bp_public, x509) != 1){ + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + qCritical("PEM_write_bio_PrivateKey"); + return false; + + } + + size = static_cast<int>(BIO_get_mem_data(bp_public, &buffer)); + q_check_ptr(buffer); + + r_srt = QSslCertificate(QByteArray(buffer, size)); + + if(r_srt.isNull()) { + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + qCritical("Failed to generate a random client certificate"); + return false; + + } + + size = static_cast<int>(BIO_get_mem_data(bp_private, &buffer)); + q_check_ptr(buffer); + r_key = QSslKey(QByteArray(buffer, size), QSsl::Rsa); + if(r_key.isNull()) { + EVP_PKEY_free(pkey); + X509_free(x509); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + qCritical("Failed to generate a random private key"); + return false; + + } + + EVP_PKEY_free(pkey); // this will also free the rsa key + X509_free(x509); + BIO_free_all(bp_public); + BIO_free_all(bp_private); + + return true; +} + +QSslConfiguration AbstractNode::selfSignedSslConfiguration() { + QSslConfiguration res = QSslConfiguration::defaultConfiguration(); + + QSslKey pkey; + QSslCertificate crt; + SslSrtData sslData; + + if (!generateSslDataPrivate(sslData, crt, pkey)) { + + QuasarAppUtils::Params::log("fail to create ssl certificate. node svitch to InitFromSystem mode", + QuasarAppUtils::Warning); + + return res; + } + + res.setPrivateKey(pkey); + res.setLocalCertificate(crt); + + return res; +} + +AbstractNodeInfo *AbstractNode::createNodeInfo(QAbstractSocket *socket, + const HostAddress* clientAddress) const { + return new AbstractNodeInfo(socket, clientAddress); +} + +bool AbstractNode::registerSocket(QAbstractSocket *socket, const HostAddress* clientAddress) { + + if (connectionsCount() >= maxPendingConnections()) { + return false; + } + + auto info = createNodeInfo(socket, clientAddress); + + _connectionsMutex.lock(); + HostAddress cliAddress; + if (clientAddress) + cliAddress = *clientAddress; + else + cliAddress = info->networkAddress(); + + info->setIsLocal(clientAddress); + + _connections[cliAddress] = info; + + _connectionsMutex.unlock(); + + connect(socket, &QAbstractSocket::readyRead, this, &AbstractNode::avelableBytes); + connect(socket, &QAbstractSocket::disconnected, this, &AbstractNode::handleDisconnected, + Qt::QueuedConnection); + + connect(socket, &QAbstractSocket::connected, this, &AbstractNode::handleConnected, + Qt::QueuedConnection); + + if (info->isConnected()) { + socket->connected(); + } + + + // check node confirmed + QTimer::singleShot(WAIT_TIME, this, + std::bind(&AbstractNode::handleCheckConfirmendOfNode, this, cliAddress)); + + connectionRegistered(info); + + return true; +} + +ParserResult AbstractNode::parsePackage(const Package &pkg, + const AbstractNodeInfo *sender) { + + if (!(sender && sender->isValid())) { + QuasarAppUtils::Params::log("sender socket is not valid!", + QuasarAppUtils::Error); + return ParserResult::Error; + } + + if (!pkg.isValid()) { + QuasarAppUtils::Params::log("incomming package is not valid!", + QuasarAppUtils::Error); + changeTrust(sender->networkAddress(), CRITICAL_ERROOR); + return ParserResult::Error; + } + + if (H_16<Ping>() == pkg.hdr.command) { + Ping cmd(pkg); + + if (!cmd.ansver()) { + cmd.setAnsver(true); + sendData(&cmd, sender->networkAddress(), &pkg.hdr); + } + + incomingData(&cmd, sender->networkAddress()); + return ParserResult::Processed; + } else if (H_16<BadRequest>() == pkg.hdr.command) { + BadRequest cmd(pkg); + + incomingData(&cmd, sender->networkAddress()); + emit requestError(cmd.err()); + + return ParserResult::Processed; + + } else if (H_16<CloseConnection>() == pkg.hdr.command) { + + if (sender->isLocal()) { + removeNode(sender->networkAddress()); + } + return ParserResult::Processed; + } + + return ParserResult::NotProcessed; +} + +bool AbstractNode::sendPackage(const Package &pkg, QAbstractSocket *target) const { + if (!pkg.isValid()) { + return false; + } + + if (!target || !target->isValid()) { + QuasarAppUtils::Params::log("destination server not valid!", + QuasarAppUtils::Error); + return false; + } + + if (!target->waitForConnected()) { + QuasarAppUtils::Params::log("no connected to server! " + target->errorString(), + QuasarAppUtils::Error); + return false; + } + + return QMetaObject::invokeMethod(const_cast<DataSender*>(_dataSender), + "sendPackagePrivate", + Qt::QueuedConnection, + Q_ARG(QByteArray, pkg.toBytes()), + Q_ARG(void*, target)); + +} + +bool AbstractNode::sendData(AbstractData *resp, + const HostAddress &addere, + const Header *req) { + + if (!resp || !resp->prepareToSend()) { + return false; + } + + return sendData(const_cast<const AbstractData*>(resp), addere, req); +} + +bool AbstractNode::sendData(const AbstractData *resp, + const HostAddress &addere, + const Header *req) { + auto client = getInfoPtr(addere); + + if (!client) { + QuasarAppUtils::Params::log("Response not sent because client == null", + QuasarAppUtils::Error); + return false; + } + + if (!resp) { + return false; + } + + Package pkg; + bool convert = false; + if (req) { + convert = resp->toPackage(pkg, req->command); + } else { + convert = resp->toPackage(pkg); + } + + if (!convert) { + QuasarAppUtils::Params::log("Response not sent because dont create package from object", + QuasarAppUtils::Error); + return false; + } + + if (!sendPackage(pkg, client->sct())) { + QuasarAppUtils::Params::log("Response not sent!", + QuasarAppUtils::Error); + return false; + } + + return true; +} + +void AbstractNode::badRequest(const HostAddress &address, const Header &req, + const QString msg) { + auto client = getInfoPtr(address); + + if (!client) { + + QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" + " because client == null", + QuasarAppUtils::Error); + return; + } + + if (!changeTrust(address, REQUEST_ERROR)) { + + QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" + " because trust not changed", + QuasarAppUtils::Error); + + return; + } + + auto bad = BadRequest(msg); + if (!sendData(&bad, address, &req)) { + return; + } + + QuasarAppUtils::Params::log("Bad request sendet to adderess: " + + client->sct()->peerAddress().toString(), + QuasarAppUtils::Info); +} + +WorkState AbstractNode::getWorkState() const { + WorkState state; + + state.setConnectionCount(connectionsCount()); + state.setMaxConnectionCount(maxPendingConnections()); + state.setBanedList(banedList()); + + return state; + +} + +QString AbstractNode::pareseResultToString(const ParserResult &parseResult) const { + switch (parseResult) + { + case ParserResult::Processed: + return "Processed"; + case ParserResult::NotProcessed: + return "NotProcessed"; + + default: return "Error"; + } +} + +QString AbstractNode::getWorkStateString() const { + if (isListening()) { + if (connectionsCount() >= maxPendingConnections()) + return "overload"; + else { + return "Work"; + } + } + + return "Not running"; +} + +QString AbstractNode::connectionState() const { + return QString("%0 / %1").arg(connectionsCount()).arg(maxPendingConnections()); +} + +QList<HostAddress> AbstractNode::banedList() const { + QList<HostAddress> list = {}; + + QMutexLocker locer(&_connectionsMutex); + + for (auto i = _connections.begin(); i != _connections.end(); ++i) { + if (i.value()->isBanned()) { + list.push_back(i.key()); + } + } + + return list; +} + +int AbstractNode::connectionsCount() const { + int count = 0; + + QMutexLocker locer(&_connectionsMutex); + + for (auto i : _connections) { + if (i->isConnected()) { + count++; + } + } + return count; +} + +int AbstractNode::confirmendCount() const { + int count = 0; + + QMutexLocker locer(&_connectionsMutex); + + for (auto i : _connections) { + if (i->status() == NodeCoonectionStatus::Confirmed) { + count++; + } + } + return count; +} + +bool AbstractNode::ping(const HostAddress &address) { + Ping cmd; + return sendData(&cmd, address); + +} + +bool AbstractNode::isBanned(QAbstractSocket *socket) const { + auto info = getInfoPtr(HostAddress{socket->peerAddress(), socket->peerPort()}); + + if (!(info && info->isValid())) { + return false; + } + + return info->isBanned(); +} + +void AbstractNode::incomingConnection(qintptr handle) { + + if (_mode == SslMode::NoSSL) { + incomingTcp(handle); + } else { + incomingSsl(handle); + } +} + +bool AbstractNode::changeTrust(const HostAddress &id, int diff) { + auto ptr = getInfoPtr(id); + if (!ptr) { + return false; + } + + auto objTrust = ptr->trust(); + + if (objTrust >= static_cast<int>(TrustNode::Undefined)) { + return false; + } + + if (objTrust <= static_cast<int>(TrustNode::Baned)) { + return false; + } + + ptr->setTrust(objTrust + diff); + return true; +} + +void AbstractNode::incomingSsl(qintptr socketDescriptor) { + QSslSocket *socket = new QSslSocket; + + socket->setSslConfiguration(_ssl); + + if (!isBanned(socket) && socket->setSocketDescriptor(socketDescriptor)) { + connect(socket, &QSslSocket::encrypted, [this, socket](){ + if (!registerSocket(socket)) { + socket->deleteLater(); + } + }); + + connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), + [socket](const QList<QSslError> &errors){ + + for (auto &error : errors) { + QuasarAppUtils::Params::log(error.errorString(), QuasarAppUtils::Error); + } + + socket->deleteLater(); + }); + + socket->startServerEncryption(); + } else { + delete socket; + } +} + +void AbstractNode::incomingTcp(qintptr socketDescriptor) { + QTcpSocket *socket = new QTcpSocket(); + if (socket->setSocketDescriptor(socketDescriptor) && !isBanned(socket)) { + if (!registerSocket(socket)) { + delete socket; + } + } else { + delete socket; + } +} + + +void AbstractNode::avelableBytes() { + + auto client = dynamic_cast<QAbstractSocket*>(sender()); + + if (!client) { + return; + } + + auto id = HostAddress{client->peerAddress(), client->peerPort()}; + + if (!_connections.contains(id)) { + return; + } + + auto &pkg = _receiveData[id]._pkg; + auto &hdrArray = _receiveData[id]._hdrArray; + + int workIndex = 0; + auto array = client->readAll(); + + // concat with old data of header. + array.insert(0, hdrArray); + hdrArray.clear(); + + while (array.size() > workIndex) { + + unsigned int workSize = array.size() - workIndex; + + if (pkg.hdr.isValid()) { + // CASE 1: The Package data is still not collected, but the header is already collected. performs full or partial filling of packet data. + + unsigned int dataLength = std::min(pkg.hdr.size - pkg.data.size(), + array.size() - workIndex); + pkg.data.append(array.mid(workIndex + sizeof(Header), dataLength)); + + workIndex += dataLength; + + + } else if (workSize >= sizeof(Header)) { + + // CASE 2: The header and package still do not exist and the amount of data allows you to create a new header. A header is created and will fill in all or part of the package data. + + pkg.reset(); + + memcpy(&pkg.hdr, + array.data() + workIndex, sizeof(Header)); + + unsigned int dataLength = std::min(static_cast<unsigned long>(pkg.hdr.size), + array.size() - sizeof(Header) - workIndex); + + pkg.data.append(array.mid(workIndex + sizeof(Header), dataLength)); + workIndex += sizeof(Header) + dataLength; + + } else { + // CASE 3: There is not enough data to initialize the header. The data will be placed in temporary storage and will be processed the next time the data is received. + + unsigned char dataLength = array.size() - workIndex; + hdrArray += array.mid(workIndex, dataLength); + workIndex += dataLength; + } + + if (pkg.isValid()) { + newWork(pkg, getInfoPtr(id), id); + } else { + QuasarAppUtils::Params::log("Invalid Package received. " + pkg.toString(), + QuasarAppUtils::Warning); + } + + if (pkg.data.size() >= pkg.hdr.size) { + pkg.reset(); + } + } +} + +/// @todo create a new system of drop error nodes. +/// if node closed by error then this node need to reconnect. bud if node longer time in disconnect statuse then drop this node. +/// +void AbstractNode::handleDisconnected() { + auto _sender = dynamic_cast<QTcpSocket*>(sender()); + + if (_sender) { + // log error + + auto ptr = getInfoPtr(HostAddress{_sender->peerAddress(), _sender->peerPort()}); + if (!ptr) { + QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" + " address not valid", + QuasarAppUtils::Error); + return; + } + + ptr->setStatus(NodeCoonectionStatus::NotConnected); + nodeStatusChanged(ptr->networkAddress(), NodeCoonectionStatus::NotConnected); + ptr->disconnect(); + + return; + } + + QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" + "dynamic_cast fail!", + QuasarAppUtils::Error); +} + +void AbstractNode::handleConnected() { + + auto _sender = dynamic_cast<QTcpSocket*>(sender()); + + if (_sender) { + + auto ptr = getInfoPtr(HostAddress{_sender->peerAddress(), _sender->peerPort()}); + + if (!ptr) { + QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" + " address not valid", + QuasarAppUtils::Error); + return; + } + + ptr->setStatus(NodeCoonectionStatus::Connected); + nodeStatusChanged(ptr->networkAddress(), NodeCoonectionStatus::Connected); + + return; + } + + QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" + "dynamic_cast fail!", + QuasarAppUtils::Error); +} + +void AbstractNode::nodeConfirmet(const HostAddress& node) { + + auto ptr = getInfoPtr(node); + + if (!ptr) { + QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" + " address not valid", + QuasarAppUtils::Error); + } + + ptr->setStatus(NodeCoonectionStatus::Confirmed); + nodeStatusChanged(ptr->networkAddress(), NodeCoonectionStatus::Confirmed); +} + +void AbstractNode::handleCheckConfirmendOfNode(HostAddress node) { + checkConfirmendOfNode(node); +} + +void AbstractNode::handleWorkerStoped() { + auto senderObject = dynamic_cast<QFutureWatcher <bool>*>(sender()); + + if (senderObject) { + _workers.remove(senderObject); + delete senderObject; + } +} + +void AbstractNode::handleForceRemoveNode(HostAddress node) { + AbstractNodeInfo* info = getInfoPtr(node); + if (info) { + info->disconnect(); + } +} + +bool AbstractNode::listen(const HostAddress &address) { + return QTcpServer::listen(address, address.port()); +} + +void AbstractNode::connectNodePrivate(HostAddress address) { + connectToHost(address, _mode); +} + +void AbstractNode::newWork(const Package &pkg, const AbstractNodeInfo *sender, + const HostAddress& id) { + + if (!sender) + return; + + if (_packageManager.contains(pkg.hdr.hash)) { + return; + } + + auto executeObject = [pkg, sender, id, this]() { + ParserResult parseResult = parsePackage(pkg, sender); + + _packageManager.processed(pkg, static_cast<char>(parseResult)); + + if (parseResult != ParserResult::Processed) { + auto message = QString("Package not parsed! %0 result: %1"). + arg(pkg.toString()). + arg(pareseResultToString(parseResult)); + + QuasarAppUtils::Params::log(message, QuasarAppUtils::Warning); + + if (parseResult == ParserResult::NotProcessed) { + changeTrust(id, REQUEST_ERROR); + } + + return false; + } + + _confirmNodeMutex.lock(); + + bool fConfirmed = sender->confirmData(); + if (fConfirmed && sender->status() != NodeCoonectionStatus::Confirmed) { + nodeConfirmet(id); + } + + _confirmNodeMutex.unlock(); + + + return true; + }; + + auto worker = new QFutureWatcher <bool>(); + worker->setFuture(QtConcurrent::run(executeObject)); + _workers.insert(worker); + + connect(worker, &QFutureWatcher<bool>::finished, + this, &AbstractNode::handleWorkerStoped); +} + +SslMode AbstractNode::getMode() const { + return _mode; +} + +bool AbstractNode::setMode(const SslMode &mode) { + + if (_mode == mode) { + return true; + } + + if (isListening()) { + return false; + } + + _mode = mode; + + switch (_mode) { + case SslMode::InitFromSystem: { + _ssl = QSslConfiguration::defaultConfiguration(); + break; + + } + case SslMode::InitSelfSigned: { + _ssl = selfSignedSslConfiguration(); + break; + + } + default: { + _ssl = QSslConfiguration(); + break; + } + + } + + return true; + +} + +void AbstractNode::incomingData(AbstractData *pkg, const HostAddress &sender) { + Q_UNUSED(pkg) + Q_UNUSED(sender) + +} + +QHash<HostAddress, AbstractNodeInfo *> AbstractNode::connections() const { + return _connections; +} + +void AbstractNode::connectionRegistered(const AbstractNodeInfo *info) { + Q_UNUSED(info); +} + +void AbstractNode::pushToQueue(const std::function<void()>& action, + const HostAddress &node, + NodeCoonectionStatus triggerStatus) { + + _actionCacheMutex.lock(); + _actionCache[node][triggerStatus].push_back(action); + _actionCacheMutex.unlock(); + +} + +QList<std::function<void ()> > +AbstractNode::takeFromQueue(const HostAddress &node, + NodeCoonectionStatus triggerStatus) { + + _actionCacheMutex.lock(); + + auto list = _actionCache[node][triggerStatus]; + _actionCache[node].remove(triggerStatus); + + if (_actionCache[node].size() == 0) + _actionCache.remove(node); + + _actionCacheMutex.unlock(); + + return list; +} + +void AbstractNode::nodeStatusChanged(const HostAddress &node, NodeCoonectionStatus status) { + + auto list = takeFromQueue(node, status); + + for (const auto &action : list) { + action(); + } + + if (status == NodeCoonectionStatus::NotConnected) { + nodeDisconnected(node); + } else if (status == NodeCoonectionStatus::Connected) { + nodeConnected(node); + } else if (status == NodeCoonectionStatus::Confirmed) { + nodeConfirmend(node); + } +} + +void AbstractNode::nodeConfirmend(const HostAddress &node) { + Q_UNUSED(node); +} + +void AbstractNode::nodeConnected(const HostAddress &node) { + Q_UNUSED(node); +} + +void AbstractNode::nodeDisconnected(const HostAddress &node) { + Q_UNUSED(node); +} + +void AbstractNode::checkConfirmendOfNode(const HostAddress &node) { + auto info = getInfoPtr(node); + + if(!info) + return; + + if (info->status() != NodeCoonectionStatus::Confirmed) { + removeNode(node); + } +} + +} diff --git a/Heart/AbstractSpace/abstractnode.h b/Heart/AbstractSpace/abstractnode.h new file mode 100644 index 0000000..7e55f17 --- /dev/null +++ b/Heart/AbstractSpace/abstractnode.h @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTNODE_H +#define ABSTRACTNODE_H + +#include "abstractnodeinfo.h" +#include <openssl/evp.h> + +#include <QAbstractSocket> +#include <QFutureWatcher> +#include <QMutex> +#include <QSslConfiguration> +#include <QTcpServer> +#include <QTimer> +#include "abstractdata.h" +#include "workstate.h" + +#include "cryptopairkeys.h" +#include "icrypto.h" +#include "heart_global.h" +#include "receivedata.h" +#include "packagemanager.h" + +class QSslCertificate; +class QSslKey; +class QSslConfiguration; + +namespace NP { + +class DataSender; + +/** + * @brief The ParserResult enum + * Error - parser detect a errorob package + * NotProcessed - the parser does not know what to do with the package or has not finished processing it. + * Processed - the parser finished processing correctly + */ +enum class ParserResult { + /// parser detect a errorob package + Error = 0, + /// the parser does not know what to do with the package or has not finished processing it. + NotProcessed = 1, + /// the parser finished processing correctly + Processed = 2 +}; + +enum class SslMode { + NoSSL, + InitFromSystem, + InitSelfSigned +}; + +/** + * @brief The SslSrtData struct + */ +struct SslSrtData { + QString country = "BY"; + QString organization = "QuasarApp"; + QString commonName = "Dev"; + long long endTime = 31536000L; //1 year +}; + + +#define CRITICAL_ERROOR -50 +#define LOGICK_ERROOR -20 +#define REQUEST_ERROR -5 + +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. + * AbstractNode - is thread save class + */ +class NETWORKPROTOCOLSHARED_EXPORT AbstractNode : public QTcpServer +{ + Q_OBJECT + +public: + + /** + * @brief AbstractNode + * @param ssl + * @param ptr + */ + AbstractNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr); + ~AbstractNode() override; + + /** + * @brief run + * @param addres - If address is empty then serve weel be listen all addreses of all interfaces + * @param port + * @return true if all good + */ + virtual bool run(const QString& addres, unsigned short port); + + /** + * @brief stop stop this node and close all connections. + */ + virtual void stop(); + + /** + * @brief getInfo + * @param id of selected node + * @return pointer to information about node. if address not found return nullpt + */ + virtual AbstractNodeInfo* getInfoPtr(const HostAddress &id); + + /** + * @brief getInfoPtr + * @param id peer adders + * @return pointer to information about node. if address not found return nullpt + */ + virtual const AbstractNodeInfo* getInfoPtr(const HostAddress &id) const; + + /** + * @brief ban + * @param target id of ban node + */ + virtual void ban(const HostAddress& target); + + /** + * @brief unBan + * @param target id of unban node + */ + virtual void unBan(const HostAddress& target); + + /** + * @brief connectToHost - connect to host node + * @param address - address of node + * @param mode - mode see SslMode + */ + virtual bool connectToHost(const HostAddress &address, SslMode mode = SslMode::NoSSL); + + /** + * @brief connectToHost - connect to host node. this method find ip address of domain befor connecting + * @param domain: address of node + * @param port - port of node + * @param mode - mode see SslMode + */ + virtual bool connectToHost(const QString &domain, unsigned short port, SslMode mode = SslMode::NoSSL); + + /** + * @brief addNode - add new node for connect + * @param nodeAdderess - the network addres of a new node. + */ + void addNode(const HostAddress& nodeAdderess); + + /** + * @brief removeNode - remove node + * @param nodeAdderess - the adddress of removed node. + */ + void removeNode(const HostAddress& nodeAdderess); + + /** + * @brief address - address of this node + * @return return current adders + */ + HostAddress address() const; + + /** + * @brief getSslConfig - configuration of this node. + * @return current ssl configuration on this nod + */ + QSslConfiguration getSslConfig() const; + + /** + * @brief getMode + * @return + */ + SslMode getMode() const; + + /** + * @brief getWorkState + * @return + */ + virtual WorkState getWorkState() const; + + /** + * @brief pareseResultToString + * @return string of pareseresult + */ + QString pareseResultToString(const ParserResult& parseResult) const; + + /** + * @brief connectionsCount - return count fo connections (nodes with status connected) + * @return + */ + int connectionsCount() const; + + /** + * @brief connectionsCount - return count of nodes with status confirmend + * @return + */ + int confirmendCount() const; + + /** + * @brief ping - ping address for testing + * @param address - address of other node + * @return true if ping sendet + */ + bool ping( const HostAddress& address); + +signals: + void requestError(QString msg); + +protected: + + /** + * @brief generateRSAforSSL + * @param pkey - + * @return + */ + virtual bool generateRSAforSSL(EVP_PKEY* pkey) const; + + /** + * @brief generateSslData - generate new ssl data + * @param data - sign data + * @param r_srt - result srt + * @param r_key - result private key + * @return true if all good + */ + virtual bool generateSslDataPrivate(const SslSrtData& data, QSslCertificate& r_srt, QSslKey& r_key); + + /** + * @brief selfSignedSslConfiguration + * @return generate new keys and use it + */ + virtual QSslConfiguration selfSignedSslConfiguration(); + + /** + * @brief createNodeInfo + * @return nodeinfo for new connection + * override this metho for set your own nodeInfo objects; + */ + virtual AbstractNodeInfo* createNodeInfo(QAbstractSocket *socket, + const HostAddress *clientAddress = nullptr) const; + + /** + * @brief registerSocket - this method registration new socket + * @param socket - socket pointer + * @param incoming - host address of socket. by default is nullptr. + * Set this value for nodes created on this host + * @return return true if the scoeket has been registered successful + */ + virtual bool registerSocket(QAbstractSocket *socket, const HostAddress* address = nullptr); + + /** + * @brief parsePackage + * @param pkg + * @param sender + * @return item of ParserResult () + */ + virtual ParserResult parsePackage(const Package &pkg, const AbstractNodeInfo* sender); + + /** + * @brief sendPackage + * @param pkg + * @param target + * @return + */ + virtual bool sendPackage(const Package &pkg, QAbstractSocket *target) const; + + /** + * @brief sendData send data package to address and prepare object to sending. + * @param resp - pointer to sendet object + * @param address - target addres for sending + * @param req - header of request + * @return true if data sendet succesful. + */ + virtual bool sendData(AbstractData *resp, const HostAddress& addere, + const Header *req = nullptr); + + /** + * @brief sendData this is some as a sendData(AbstractData *resp ...) exept this method not prepare object for sending. + * @param resp - pointer to sendet object + * @param address - target addres for sending + * @param req - header of request + * @return true if data sendet succesful. + */ + virtual bool sendData(const AbstractData *resp, const HostAddress& addere, + const Header *req = nullptr); + + /** + * @brief badRequestu + * @param address + * @param req + * @param msg - message of error + */ + virtual void badRequest(const HostAddress &address, const Header &req, + const QString msg = ""); + + /** + * @brief getWorkStateString + * @return string of work state + */ + virtual QString getWorkStateString() const; + + /** + * @brief connectionState + * @return string with count users state + */ + virtual QString connectionState() const; + + /** + * @brief banedList + * @return list of baned nodes + */ + QList<HostAddress> banedList() const; + + /** + * @brief isBanned + * @param socket + * @return + */ + bool isBanned(QAbstractSocket* socket) const; + + /** + * @brief incomingConnection + * @param handle + */ + void incomingConnection(qintptr handle) override; + + /** + * @brief changeTrust change trust of connected node + * @param id - id of select node + * @param diff + * @return true if all good + */ + virtual bool changeTrust(const HostAddress& id, int diff); + + /** + * @brief incomingConnection for ssl sockets + * @param handle - handle of socket + */ + virtual void incomingSsl(qintptr handle); + + /** + * @brief incomingConnection for tcp sockets + * @param handle - handle of socket + */ + virtual void incomingTcp(qintptr handle); + + + /** + * @brief setMode - invoke this method befor run method + * @param mode + */ + bool setMode(const SslMode &mode); + + /** + * @brief incomingData - this signal invoked when node get command or ansver + * @param pkg - get package (in this implementation it is only the Ping command) + * @param sender - sender of the package + * @note override this method for get a signals. + */ + virtual void incomingData(AbstractData* pkg, + const HostAddress& sender); + + /** + * @brief connections - return hash map of all connections of this node. + * @return + */ + QHash<HostAddress, AbstractNodeInfo*> connections() const; + + /** + * @brief connectionRegistered Override this method for get registered incoming connections. + * @param info - connection information. + */ + virtual void connectionRegistered(const AbstractNodeInfo *info); + + /** + * @brief nodeStatusChanged - This method invoked when status of node chganged. + * Base implementation do nothing. Override this method for add own functionality. + * @param node - address of changed node. + * @param status - new status of node. + * + */ + void nodeStatusChanged(const HostAddress& node, NodeCoonectionStatus status); + + /** + * @brief nodeConfirmend - thim method invocked when the node status changed to "confirmend" + * default implementatio do nothing + * @param node - the address of changed node + */ + virtual void nodeConfirmend(const HostAddress& node); + + /** + * @brief nodeConnected thim method invocked when the node status changed to "connected" + * default implementatio do nothing + * @param node + */ + virtual void nodeConnected(const HostAddress& node); + + /** + * @brief nodeConnected thim method invocked when the node status changed to "disconnected" + * default implementatio do nothing + * @param node + */ + virtual void nodeDisconnected(const HostAddress& node); + + + /** + * @brief pushToQueue - This method add action to queue. When the node status will be equal 'triggerStatus' then node run a action method. + * @param node - node. + * @param action - lyamda function with action. + * @param triggerStatus - node status. + */ + void pushToQueue(const std::function<void ()> &action, + const HostAddress& node, + NodeCoonectionStatus triggerStatus); + + /** + * @brief takeFromQueue - take the list of actions of node. after invoke take elements will be removed. + * @param node - node + * @param triggerStatus - status of node + * @return list o actions + */ + QList<std::function<void ()>> takeFromQueue(const HostAddress& node, + NodeCoonectionStatus triggerStatus); +private slots: + + void avelableBytes(); + void handleDisconnected(); + void handleConnected(); + void handleCheckConfirmendOfNode(HostAddress node); + + /** + * @brief handleWorkerStoped + */ + void handleWorkerStoped(); + + /** + * @brief handleForceRemoveNode - force remove connection. + * @param node + */ + void handleForceRemoveNode(HostAddress node); + + /** + * @brief connectNodePrivate + */ + void connectNodePrivate(NP::HostAddress); + +private: + + /** + @note just disaable listen method in the node objects. + */ + bool listen(const HostAddress& address = HostAddress::Any); + + /** + * @brief newWork - this method it is wraper of the parsePackage method. + * the newWork invoke a parsePackage in the new thread. + * @param pkg + * @param sender + */ + void newWork(const Package &pkg, const AbstractNodeInfo* sender, const HostAddress &id); + + + /** + * @brief nodeConfirmet - this metthod invoked when node is confirment. + * @param sender - node with new status; + */ + void nodeConfirmet(const HostAddress &node); + + /** + * @brief checkConfirmendOfNode - this method remove old not confirmed node. + * @param node - node address + */ + void checkConfirmendOfNode(const HostAddress& node); + + SslMode _mode; + QSslConfiguration _ssl; + QHash<HostAddress, AbstractNodeInfo*> _connections; + QHash<HostAddress, ReceiveData> _receiveData; + + QHash<HostAddress, QHash<NodeCoonectionStatus, QList<std::function<void()>>>> _actionCache; + + DataSender * _dataSender = nullptr; + + QSet<QFutureWatcher <bool>*> _workers; + + PackageManager _packageManager; + + + mutable QMutex _connectionsMutex; + mutable QMutex _actionCacheMutex; + mutable QMutex _confirmNodeMutex; + + friend class WebSocketController; + + +}; + +} +#endif // ABSTRACTNODE_H diff --git a/Heart/AbstractSpace/abstractnodeinfo.cpp b/Heart/AbstractSpace/abstractnodeinfo.cpp new file mode 100644 index 0000000..861429d --- /dev/null +++ b/Heart/AbstractSpace/abstractnodeinfo.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018-2020 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 "abstractnodeinfo.h" +#include <hostaddress.h> +#include <QAbstractSocket> +#include <QDataStream> +#include <QHostInfo> + +namespace NP { + +AbstractNodeInfo::AbstractNodeInfo(QAbstractSocket *sct, + const HostAddress *address) { + setSct(sct); + if (address) + setNetworkAddress(*address); + +} + +AbstractNodeInfo::~AbstractNodeInfo() {} + +QAbstractSocket *AbstractNodeInfo::sct() const { + return _sct; +} + +void AbstractNodeInfo::disconnect() { + if (_sct) { + _sct->close(); + _sct->deleteLater(); + _sct = nullptr; + } +} + +void AbstractNodeInfo::ban() { + _trust = static_cast<int>(TrustNode::Baned); + disconnect(); +} + +bool AbstractNodeInfo::isBanned() const { + return _trust < 1; +} + +void AbstractNodeInfo::unBan() { + _trust = static_cast<int>(TrustNode::Restore); +} + +void AbstractNodeInfo::setSct(QAbstractSocket *sct) { + _sct = sct; + if (_sct && !_sct->peerAddress().isNull()) { + setNetworkAddress(HostAddress{_sct->peerAddress(), _sct->peerPort()}); + } +} + +void AbstractNodeInfo::setIsLocal(bool isLocal) { + _isLocal = isLocal; +} + +NodeCoonectionStatus AbstractNodeInfo::status() const { + return _status; +} + +void AbstractNodeInfo::setStatus(const NodeCoonectionStatus &status) { + _status = status; +} + +bool AbstractNodeInfo::confirmData() const { + return _status != NodeCoonectionStatus::NotConnected; +} + +bool AbstractNodeInfo::isLocal() const { + return _isLocal; +} + +HostAddress AbstractNodeInfo::networkAddress() const { + if (isValid() && _sct->isValid()) + return HostAddress{_sct->peerAddress(), _sct->peerPort()}; + + return _networkAddress; +} + +void AbstractNodeInfo::setNetworkAddress(const HostAddress &networkAddress) { + + if (!networkAddress.isNull()) { + _networkAddress = networkAddress; + + QHostInfo::lookupHost(_networkAddress.toString(), [this] (QHostInfo info){ + if (dynamic_cast<AbstractNodeInfo*>(this)) { + setInfo(info); + } + }); + } +} + +void AbstractNodeInfo::setInfo(const QHostInfo &info) { + if (!_info) + _info = new QHostInfo(); + + *_info = info; +} + +QHostInfo *AbstractNodeInfo::info() const { + return _info; +} + +int AbstractNodeInfo::trust() const { + return _trust; +} + +void AbstractNodeInfo::setTrust(int trust) { + _trust = trust; + + if (isBanned()) { + disconnect(); + } +} + +bool AbstractNodeInfo::isValid() const { + return _sct; +} + +bool AbstractNodeInfo::isConnected() const { + return isValid() && _sct->isOpen(); +} + +QDataStream &AbstractNodeInfo::fromStream(QDataStream &stream) { + stream >> _networkAddress; + return stream; +} + +QDataStream &AbstractNodeInfo::toStream(QDataStream &stream) const { + stream << _networkAddress; + return stream; +} + +uint qHash(NodeCoonectionStatus status) { + return static_cast<uint>(status); +} + +} diff --git a/Heart/AbstractSpace/abstractnodeinfo.h b/Heart/AbstractSpace/abstractnodeinfo.h new file mode 100644 index 0000000..c9d636b --- /dev/null +++ b/Heart/AbstractSpace/abstractnodeinfo.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTNODEINFO_H +#define ABSTRACTNODEINFO_H +#include "hostaddress.h" +#include "heart_global.h" + +#include <hostaddress.h> + + +class QAbstractSocket; +class QHostInfo; + +namespace NP { + +/** + * @brief The TrustNode enum + */ +enum class TrustNode: unsigned char { + /// undefined node + Undefined = 0xFF, + + /// general trust of node + Default = 100, + + /// this trusted of unbaned nodes + Restore = 20, + + /// node with this trusted is forbidden + Baned = 0 +}; + +/** + * @brief The AbstractNodeState enum - This is status of known nodes. + */ +enum class NodeCoonectionStatus: int { + /// This node not sent data about its envirement + NotConnected, + /// The node with this status has already sent data about its environment. + Connected, + /// The node confirmend. Node with it status sent a information + /// requarement for confirm in to this node object. + Confirmed, +}; + +uint qHash(NodeCoonectionStatus status); + +/** + * @brief The AbstractNodeInfo class + */ +class NETWORKPROTOCOLSHARED_EXPORT AbstractNodeInfo +{ + +public: + + /** + * @brief AbstractNodeInfo + * @param sct socket of connection + * @param address - address of socket + */ + AbstractNodeInfo(QAbstractSocket *sct = nullptr, + const HostAddress* address = nullptr); + + /** + * @brief ~AbstractNodeInfo + */ + virtual ~AbstractNodeInfo(); + + /** + * @brief sct + * @return return socket of connection + */ + QAbstractSocket *sct() const; + + /** + * @brief disconnect disconnect from host + */ + virtual void disconnect(); + + /** + * @brief ban this node + */ + virtual void ban(); + + /** + * @brief isBanned + * @return true if node baned + */ + virtual bool isBanned() const; + + /** + * @brief unBan + */ + virtual void unBan(); + + /** + * @brief trust + * @return rtust + */ + virtual int trust() const; + + /** + * @brief setTrust manual set value of trust + * @param trust - new value + */ + virtual void setTrust(int trust); + + /** + * @brief isValid + * @return true if all data valid + */ + virtual bool isValid() const; + + /** + * @brief isConnected + * @return true if the socket connected + */ + virtual bool isConnected() const; + + /** + * @brief fromStream + * @param stream + * @return stream + */ + virtual QDataStream& fromStream(QDataStream& stream); + + /** + * @brief toStream + * @param stream + * @return stream + */ + virtual QDataStream& toStream(QDataStream& stream) const; + + /** + * @brief info + * @return Host info of this node + */ + QHostInfo *info() const; + + /** + * @brief setInfo - set new temp info for this node + * @param info + */ + void setInfo(const QHostInfo &info); + + /** + * @brief networkAddress + * @return network adderess of node + */ + HostAddress networkAddress() const; + + /** + * @brief setNetworkAddress - update network address + * @param networkAddress - new address + */ + void setNetworkAddress(const HostAddress &networkAddress); + + /** + * @brief status - status of node connection + * @return connection status + */ + NodeCoonectionStatus status() const; + + /** + * @brief setStatus - set new value of status node + * @param status - new status + */ + void setStatus(const NodeCoonectionStatus &status); + + /** + * @brief confirmData - check all data of node and return true if node is confirmed + * @return true if node is confirmed + */ + virtual bool confirmData() const; + + /** + * @brief isLocal - return true if connectuion opened on this node. + * @return + */ + bool isLocal() const; + + /** + * @brief setIsLocal - set local status for this Node. + * @param isLocal + */ + void setIsLocal(bool isLocal); + +protected: + /** + * @brief setSct + * @param sct + */ + void setSct(QAbstractSocket *sct); + +private: + + QHostInfo *_info = nullptr; + HostAddress _networkAddress; + + QAbstractSocket *_sct = nullptr; + int _trust = static_cast<int>(TrustNode::Default); + NodeCoonectionStatus _status = NodeCoonectionStatus::NotConnected; + bool _isLocal = false; + +}; + +} +#endif // ABSTRACTNODEINFO_H diff --git a/Heart/AbstractSpace/atomicmetatypes.h b/Heart/AbstractSpace/atomicmetatypes.h new file mode 100644 index 0000000..7eccb42 --- /dev/null +++ b/Heart/AbstractSpace/atomicmetatypes.h @@ -0,0 +1,9 @@ +#ifndef ATOMICMETATYPES_H +#define ATOMICMETATYPES_H +#include <QMetaType> + +Q_DECLARE_METATYPE(const bool*) +Q_DECLARE_METATYPE(bool*) + + +#endif // ATOMICMETATYPES_H diff --git a/Heart/AbstractSpace/config.h b/Heart/AbstractSpace/config.h new file mode 100644 index 0000000..bd19572 --- /dev/null +++ b/Heart/AbstractSpace/config.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018-2020 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 CONFIG_H +#define CONFIG_H +#include <QStandardPaths> + + +// network settings +#define LOCAL_SERVER "127.0.0.1" + +#define DEFAULT_PORT 3090 +#define WAIT_CONFIRM_TIME 30000 // 30000 msec = 30 sec + +// Data Base settings +#define DEFAULT_DB_NAME "Storage.sqlite" +#define DEFAULT_DB_PATH QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) +#define DEFAULT_DB_INIT_FILE_PATH ":/sql/DataBaseSpace/Res/BaseDB.sql" +#define DEFAULT_UPDATE_INTERVAL 3600000 // 1 hour + +// Transport Protockol settings +#define ROUTE_COUNT_LIMIT 1000 +#define TRANSPORT_PACKAGES_CACHE 1000 + +// Node Settings +#define PACKAGE_CACHE_SIZE 1000 + +// Other settings +#ifdef RELEASE_BUILD + #define WAIT_TIME 30000 + #define WAIT_RESPOCE_TIME 10000 +#else + #define WAIT_TIME 300000000 + #define WAIT_RESPOCE_TIME 100000000 +#endif + +#endif // CONFIG_H diff --git a/Heart/AbstractSpace/cryptopairkeys.cpp b/Heart/AbstractSpace/cryptopairkeys.cpp new file mode 100644 index 0000000..44846e8 --- /dev/null +++ b/Heart/AbstractSpace/cryptopairkeys.cpp @@ -0,0 +1,73 @@ +#include "cryptopairkeys.h" + +#include <QDataStream> +namespace NP { +CryptoPairKeys::CryptoPairKeys() { + +} + +CryptoPairKeys::CryptoPairKeys(const QByteArray &pubKey, const QByteArray &privKey) { + setPrivKey(privKey); + setPublicKey(pubKey); + setBits(privKey.size() * 8); +} + +bool CryptoPairKeys::isValid() const { + return _privKey.size() && _publicKey.size() && !(_bits % 8) && _bits > 1; +} + +QByteArray CryptoPairKeys::privKey() const { + return _privKey; +} + +void CryptoPairKeys::setPrivKey(const QByteArray &privKey) { + _privKey = privKey; +} + +QByteArray CryptoPairKeys::publicKey() const { + return _publicKey; +} + +void CryptoPairKeys::setPublicKey(const QByteArray &publicKey) { + _publicKey = publicKey; +} + +int CryptoPairKeys::bits() const { + return _bits; +} + +void CryptoPairKeys::setBits(int bits) { + _bits = bits; +} + +QDataStream &CryptoPairKeys::fromStream(QDataStream &stream) { + + stream >> _publicKey; + stream >> _privKey; + stream >> _bits; + + return stream; +} + +QDataStream &CryptoPairKeys::toStream(QDataStream &stream) const { + stream << _publicKey; + stream << _privKey; + stream << _bits; + + return stream; + +} + +bool operator ==(const CryptoPairKeys &left, const CryptoPairKeys &right) { + return !(left != right); +} + +bool operator !=(const CryptoPairKeys &left, const CryptoPairKeys &right) { + return left._privKey != right._privKey || left._publicKey != right._publicKey; +} + +uint qHash(const CryptoPairKeys &value) { + return qHash(value.privKey()); +} + +} diff --git a/Heart/AbstractSpace/cryptopairkeys.h b/Heart/AbstractSpace/cryptopairkeys.h new file mode 100644 index 0000000..1283eb0 --- /dev/null +++ b/Heart/AbstractSpace/cryptopairkeys.h @@ -0,0 +1,59 @@ +#ifndef CRYPTOPAIRKEYS_H +#define CRYPTOPAIRKEYS_H + +#include "streambase.h" + + +namespace NP { + +/** + * @brief The CryptoPairKeys class contains pair keys. + */ +class NETWORKPROTOCOLSHARED_EXPORT CryptoPairKeys: public StreamBase +{ +public: + CryptoPairKeys(); + CryptoPairKeys(const QByteArray& pubKey, const QByteArray& privKey); + + /** + * @brief isValid + * @return true if this objcet contains pair keys + */ + bool isValid() const; + + QByteArray privKey() const; + void setPrivKey(const QByteArray &privKey); + + QByteArray publicKey() const; + void setPublicKey(const QByteArray &publicKey); + + /** + * @brief bits + * @return bits size of keys pair + */ + int bits() const; + + /** + * @brief setBits + * @param bits + */ + void setBits(int bits); + + friend bool operator != (const CryptoPairKeys& left, const CryptoPairKeys& right); + friend bool operator == (const CryptoPairKeys& left, const CryptoPairKeys& right); + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream); + QDataStream &toStream(QDataStream &stream) const; + +private: + QByteArray _privKey; + QByteArray _publicKey; + + int _bits; +}; + + uint qHash(const CryptoPairKeys& value); +} +#endif // CRYPTOPAIRKEYS_H diff --git a/Heart/AbstractSpace/datasender.cpp b/Heart/AbstractSpace/datasender.cpp new file mode 100644 index 0000000..24c2015 --- /dev/null +++ b/Heart/AbstractSpace/datasender.cpp @@ -0,0 +1,19 @@ +#include "datasender.h" +#include <QAbstractSocket> +#include <quasarapp.h> +#include <QThread> + +namespace NP { + +DataSender::DataSender() { +} + +void NP::DataSender::sendPackagePrivate(QByteArray array, void *target) const { + auto ptr = static_cast<QAbstractSocket*>(target); + if (array.size() != ptr->write(array)) { + QuasarAppUtils::Params::log("not writed data to socket", QuasarAppUtils::Error); + } + +} + +} diff --git a/Heart/AbstractSpace/datasender.h b/Heart/AbstractSpace/datasender.h new file mode 100644 index 0000000..87bcd42 --- /dev/null +++ b/Heart/AbstractSpace/datasender.h @@ -0,0 +1,29 @@ +#ifndef DATASENDER_H +#define DATASENDER_H + +#include <QObject> + +class QAbstractSocket; + +namespace NP { + +/** + * @brief The DataSender class - this class create a queue for sendet data to network. + * work on a main thread + */ +class DataSender: public QObject +{ + Q_OBJECT +public: + DataSender(); + +public slots: + /** + * @brief sendPackagePrivate + * @param array + * @param target + */ + void sendPackagePrivate(QByteArray array, void *target) const; +}; +} +#endif // DATASENDER_H diff --git a/Heart/AbstractSpace/header.cpp b/Heart/AbstractSpace/header.cpp new file mode 100644 index 0000000..ec2d306 --- /dev/null +++ b/Heart/AbstractSpace/header.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018-2020 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 "header.h" + +#include <QString> + +namespace NP { +Header::Header() { + reset(); +} + +bool Header::isValid() const { + return command && size && hash; +} + +void Header::reset() { + size = 0; + command = 0; + triggerHash = 0; + hash = 0; +} + +QString Header::toString() const { + return QString("Header description: Size - %0, Command - %1, hash - %2, triggerHash - %3"). + arg(size).arg(command).arg(QString::number(hash, 16)).arg(QString::number(triggerHash, 16)); +} +} diff --git a/Heart/AbstractSpace/header.h b/Heart/AbstractSpace/header.h new file mode 100644 index 0000000..fe84141 --- /dev/null +++ b/Heart/AbstractSpace/header.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTHEADER_H +#define ABSTRACTHEADER_H +#include "heart_global.h" + + +namespace NP { +/** + * @brief The Header struct 12 byte + */ +#pragma pack(push, 1) +struct NETWORKPROTOCOLSHARED_EXPORT Header{ + /** + * @brief size - size of package data (not header) + */ + unsigned short size; + + /** + * @brief command of pacage + */ + unsigned short command; + + /** + * @brief hash - is uniqueue id of a package. id calc with CRC32 function fo Qt implamentation. qHash(QByteArray) + */ + unsigned int hash; + + /** + * @brief triggerHash - this is hash of request package that this package has been responded + * the server should write to which command it responds + */ + unsigned int triggerHash; + + /** + * @brief Header default constructor + */ + Header(); + ~Header() = default; + + /** + * @brief isValid + * @return true if header is valid + */ + bool isValid() const; + + + /** + * @brief reset - reset all data and set for header invalid status + */ + void reset(); + + /** + * @brief toString - return string of header of package + * @return + */ + QString toString() const; + +}; +#pragma pack(pop) + +} + + + +#endif // ABSTRACTHEADER_H diff --git a/Heart/AbstractSpace/hostaddress.cpp b/Heart/AbstractSpace/hostaddress.cpp new file mode 100644 index 0000000..e80a991 --- /dev/null +++ b/Heart/AbstractSpace/hostaddress.cpp @@ -0,0 +1,60 @@ +#include "hostaddress.h" +#include <QDataStream> +#include <quasarapp.h> +namespace NP { + +HostAddress::HostAddress() { + +} + +HostAddress::HostAddress(const QHostAddress &other, int port): + QHostAddress(other) { + setPort(port); +} + +HostAddress::HostAddress(const QString &other, int port): + QHostAddress(other) { + setPort(port); +} + +HostAddress::HostAddress(const QHostAddress::SpecialAddress &other, int port): + QHostAddress(other) { + setPort(port); +} + +HostAddress::HostAddress(const HostAddress &other): + QHostAddress(*static_cast<const HostAddress*>(&other)) { + + setPort(other.port()); +} + +unsigned short HostAddress::port() const { + return _port; +} + +void HostAddress::setPort(unsigned short port) { + debug_assert(port); + + _port = port; +} + +QDataStream &operator >>(QDataStream &stream, HostAddress &address) { + stream >> static_cast<QHostAddress&>(address); + stream >> address._port; + + return stream; +} + +QDataStream &operator <<(QDataStream &stream, const HostAddress &address) { + + stream << static_cast<const QHostAddress&>(address); + stream << address._port; + + return stream; +} + +uint qHash(const HostAddress &address) { + return qHash(QString("%1:%2").arg(address.toString()).arg(address.port())); +} + +} diff --git a/Heart/AbstractSpace/hostaddress.h b/Heart/AbstractSpace/hostaddress.h new file mode 100644 index 0000000..a09c732 --- /dev/null +++ b/Heart/AbstractSpace/hostaddress.h @@ -0,0 +1,39 @@ +#ifndef HOSTADDRESS_H +#define HOSTADDRESS_H +#include "heart_global.h" + +#include <QHostAddress> +#include "config.h" + +namespace NP { + +/** + * @brief The HostAddress class - this is Wraper of QHostAddress + */ +class NETWORKPROTOCOLSHARED_EXPORT HostAddress: public QHostAddress +{ +public: + explicit HostAddress(); + explicit HostAddress(const QHostAddress& other, int port = DEFAULT_PORT); + explicit HostAddress(const QString& other, int port = DEFAULT_PORT); + HostAddress(const SpecialAddress& other, int port = DEFAULT_PORT); + + HostAddress(const HostAddress& other); + + + unsigned short port() const; + void setPort(unsigned short port); + + friend QDataStream& operator << (QDataStream& stream, const HostAddress& address); + friend QDataStream& operator >> (QDataStream& stream, HostAddress& address); + +private: + unsigned short _port = 0; +}; + +uint qHash(const HostAddress& address); +} + +Q_DECLARE_METATYPE(NP::HostAddress); + +#endif // HOSTADDRESS_H diff --git a/Heart/AbstractSpace/icrypto.cpp b/Heart/AbstractSpace/icrypto.cpp new file mode 100644 index 0000000..fb2cddf --- /dev/null +++ b/Heart/AbstractSpace/icrypto.cpp @@ -0,0 +1,10 @@ +#include "icrypto.h" + + +namespace NP { + +ICrypto::ICrypto() = default; + +ICrypto::~ICrypto() = default; + +} diff --git a/Heart/AbstractSpace/icrypto.h b/Heart/AbstractSpace/icrypto.h new file mode 100644 index 0000000..698c797 --- /dev/null +++ b/Heart/AbstractSpace/icrypto.h @@ -0,0 +1,95 @@ +#ifndef ICRYPTO_H +#define ICRYPTO_H + +#include <QList> +#include <QThread> +#include "heart_global.h" +#include <QByteArray> +#include <QHash> +#include <QSet> +#define RAND_KEY "" + +class QMutex; + +namespace NP { + +class CryptoPairKeys; + +/** + * @brief The ICrypto class provide cryptografu functionality. + * this is interface for decaration of KeyStorage classes. + */ +class NETWORKPROTOCOLSHARED_EXPORT ICrypto +{ + +public: + ICrypto(); + virtual ~ICrypto(); + + /** + * @brief isValid + * @return true if the crypto object is valid. + */ + virtual bool isValid() const = 0; + + + /** + * @brief crypt + * @param data - pointer to data array for crypting. + * @note data as ben changed after call this method. + * @param publicKey - key for crypting data + * @return true if function finished seccussful + */ + virtual bool crypt(QByteArray *data, const QByteArray& publicKey) = 0; + + /** + * @brief decrypt + * @param cryptedData - pointer to data array for decrypting. + * @note cryptedData as ben changed after call this method. + * @param privateKey + * @return true if function finished seccussful + */ + virtual bool decrypt(QByteArray *cryptedData, const QByteArray& privateKey) = 0; + + /** + * @brief sign + * @param data - pointer to data array for signed. + * @note data as ben changed after call this method. + * @param privateKey + * @return true if function finished seccussful + */ + virtual bool sign(QByteArray* data, const QByteArray& privateKey) = 0; + + /** + * @brief extractSign - extract sign from signed byteArray + * @param data - signed message. + * @return return array of sign. + */ + virtual QByteArray extractSign(const QByteArray& data) = 0; + + /** + * @brief concatSign + * @param data - message data + * @return signed message + */ + virtual QByteArray concatSign(const QByteArray& data, const QByteArray& sign) = 0; + + /** + * @brief check + * @param publicKey + * @return true if function finished seccussful and signedData is valid. + */ + virtual bool check(const QByteArray& signedData, const QByteArray& publicKey) = 0; + + /** + * @brief generate a new key. Default implementation do nothing. + * @note Override this method for create of new class with new keys type. + * @param genesis + * @return crypto pair keys + */ + virtual CryptoPairKeys generate(const QByteArray& genesis = {}) const = 0; + +}; + +} +#endif // CRYPTO_H diff --git a/Heart/AbstractSpace/keystorage.cpp b/Heart/AbstractSpace/keystorage.cpp new file mode 100644 index 0000000..3ad654b --- /dev/null +++ b/Heart/AbstractSpace/keystorage.cpp @@ -0,0 +1,383 @@ +#include "cryptopairkeys.h" +#include "icrypto.h" +#include "keystorage.h" +#include <quasarapp.h> + +#include <QCoreApplication> +#include <QDataStream> +#include <QDateTime> +#include <QDir> +#include <QFile> +#include <QMutex> +#include <QStandardPaths> +#include "config.h" + +namespace NP { + +#define THE_CLASS(x) QString::fromLatin1(typeid(*x).name()) +#define VERSION_FILE "version" + +KeyStorage::KeyStorage(ICrypto * cryptoMethod) { + _keyPoolSizeMutex = new QMutex(); + _keysMutex = new QMutex(); + _taskMutex = new QMutex(); + + _cryptoMethod = cryptoMethod; + + assert(_cryptoMethod); +} + +KeyStorage::~KeyStorage() { + + stop(); + waitForThreadFinished(WAIT_TIME); + + if (!saveStorage()) { + QuasarAppUtils::Params::log("save keys to storae is failed!", + QuasarAppUtils::Error); + } + + delete _keyPoolSizeMutex; + delete _keysMutex; + delete _taskMutex; + delete _cryptoMethod; +} + +CryptoPairKeys KeyStorage::getNextPair(const QString &accsessKey, + const QByteArray& genesis, + int timeout) { + + if (!isInited() && genesis == RAND_KEY) { + QuasarAppUtils::Params::log("You want get the random crypto keys pair in a not initialized crypto object.", + QuasarAppUtils::Error); + return CryptoPairKeys{}; + } + + if (_keyPoolSize <= 0) { + return CryptoPairKeys{}; + } + + if (!genKey(accsessKey, genesis)) { + return {}; + } + + start(); + + if (!waitForGeneratekey(accsessKey, timeout)) { + return CryptoPairKeys{}; + } + + QMutexLocker locker(_keysMutex); + + return _keys.value(accsessKey, {}); +} + +int KeyStorage::getKeyPoolSize() const { + return _keyPoolSize; +} + +void KeyStorage::setKeyPoolSize(int keyPoolSize) { + _keyPoolSizeMutex->lock(); + _keyPoolSize = keyPoolSize; + _keyPoolSizeMutex->unlock(); + + start(); +} + +bool KeyStorage::isValid() const { + return isInited(); +} + +bool KeyStorage::isInited() const { + return _inited; +} + +bool KeyStorage::crypt(QByteArray *data, const QByteArray &publicKey) { + return _cryptoMethod->crypt(data, publicKey); +} + +bool KeyStorage::decrypt(QByteArray *cryptedData, const QByteArray &privateKey) { + return _cryptoMethod->decrypt(cryptedData, privateKey); +} + +bool KeyStorage::sign(QByteArray *data, const QByteArray &privateKey) { + return _cryptoMethod->sign(data, privateKey); +} + +QByteArray KeyStorage::extractSign(const QByteArray &data) { + return _cryptoMethod->extractSign(data); +} + +QByteArray KeyStorage::concatSign(const QByteArray &data, const QByteArray &sign) { + return _cryptoMethod->concatSign(data, sign); +} + +bool KeyStorage::check(const QByteArray &signedData, const QByteArray &publicKey) { + return _cryptoMethod->check(signedData, publicKey); +} + +void KeyStorage::setGenesisList(const QList<QByteArray>& list) { + _keysMutex->lock(); + for (const auto& i : list) { + _keys.insert(i, {}); + } + _keysMutex->unlock(); + + start(); +} + +bool KeyStorage::toStorage(const QString &key) const { + + if (!isValid()) + return false; + + _keysMutex->lock(); + CryptoPairKeys value = _keys.value(key); + _keysMutex->unlock(); + + auto filePath = storageLocation() + "/" + key; + + QFile file(filePath); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + return false; + } + + file.setPermissions(QFile::Permission::ReadOwner | QFile::Permission::WriteOwner); + + QDataStream stream(&file); + + stream << value; + + file.close(); + + return true; +} + +bool KeyStorage::fromStorage(const QByteArray &key) { + auto filePath = storageLocation() + "/" + key; + + QFile file(filePath); + + if (!file.open(QIODevice::ReadOnly)) { + return false; + } + + QDataStream stream(&file); + + CryptoPairKeys value; + stream >> value; + + file.close(); + + _keys.insert(key, value); + + return value.isValid(); +} + +void KeyStorage::generateKeysByTasks() { + _taskMutex->lock(); + auto tasks = _generateTasks; + _taskMutex->unlock(); + + for (auto it = tasks.begin(); it != tasks.end(); ++it) { + + if (_stopGenerator) { + return; + } + + const auto& value = _keys.value(it.key()); + if (!value.isValid()) { + + _keysMutex->lock(); + + if (it.value() == RAND_KEY && _randomKeysPool.size()) { + _keys[it.key()] = *_randomKeysPool.begin(); + _randomKeysPool.erase(_randomKeysPool.begin()); + } else { + _keys[it.key()] = _cryptoMethod->generate(it.value()); + } + + _keysMutex->unlock(); + + } + + _taskMutex->lock(); + _generateTasks.remove(it.key()); + _taskMutex->unlock(); + + } +} + +void KeyStorage::generateRandomKeys() { + _keyPoolSizeMutex->lock(); + int size = _keyPoolSize; + _keyPoolSizeMutex->unlock(); + + while (size > _randomKeysPool.size()) { + + if ((_stopGenerator)) + return; + + auto &&keys = _cryptoMethod->generate(); + + _keysMutex->lock(); + _randomKeysPool.insert(keys); + _keysMutex->unlock(); + } +} + +void KeyStorage::run() { + + if (_stopGenerator) { + return; + } + + _keyPoolSizeMutex->lock(); + int keyPoolSize = _keyPoolSize; + _keyPoolSizeMutex->unlock(); + + while ((_generateTasks.size() || keyPoolSize > _randomKeysPool.size()) + && !_stopGenerator) { + + generateKeysByTasks(); + generateRandomKeys(); + + _keyPoolSizeMutex->lock(); + keyPoolSize = _keyPoolSize; + _keyPoolSizeMutex->unlock(); + } +} + +void KeyStorage::stop() { + _stopGenerator = true; +} + +bool KeyStorage::waitForGeneratekey(const QString& key, int timeout) const { + return waitFor([this, &key](){return _keys.contains(key);}, timeout); +} + +bool KeyStorage::waitForThreadFinished(int timeout) const { + return waitFor([this](){return !isRunning();}, timeout); +} + +bool KeyStorage::waitFor(const std::function<bool()> &checkFunc, int timeout) const { + auto waitFor = timeout + QDateTime::currentMSecsSinceEpoch(); + while (!checkFunc() && waitFor > QDateTime::currentMSecsSinceEpoch()) { + QCoreApplication::processEvents(); + } + + return checkFunc(); +} + +void KeyStorage::loadAllKeysFromStorage() { + auto list = QDir(storageLocation()).entryInfoList(QDir::Files | QDir::NoDotAndDotDot); + + for (const auto& file: list ) { + if (file.fileName() != VERSION_FILE) { + fromStorage(file.fileName().toLatin1()); + } + } +} + +bool KeyStorage::saveStorage() const { + + bool result = true; + for (auto it = _keys.begin(); it != _keys.end(); ++it) { + result = result && toStorage(it.key()); + } + + return result; +} + +bool KeyStorage::genKey(const QString &accessKey, const QByteArray &genesis) { + + if (accessKey.isEmpty()) + return false; + + QMutexLocker locker(_taskMutex); + _generateTasks.insert(accessKey, genesis); + return true; +} + +QString KeyStorage::storageLocation() const { + return _storageLocation; +} + +bool KeyStorage::initStorageLocation(const QString &value) { + QFile version(value + "/" + VERSION_FILE); + + if (!QFile::exists(value)) { + + if (!QDir().mkpath(value)) { + QuasarAppUtils::Params::log(" fail to create a key storagge. Into " + + value, QuasarAppUtils::Error); + return false; + } + + QFile::setPermissions(value, + QFile::Permission::ExeOwner | + QFile::Permission::ReadOwner | + QFile::Permission::WriteOwner); + + QFile version(value + "/" + VERSION_FILE); + + if (!version.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + return false; + } + + QDataStream stream(&version); + stream << THE_CLASS(_cryptoMethod); + version.close(); + + } else { + + if (!version.open(QIODevice::ReadOnly)) { + return false; + } + + QDataStream stream(&version); + QString versionName; + stream >> versionName; + version.close(); + + if (THE_CLASS(_cryptoMethod) != versionName) { + return false; + } + + } + + _storageLocation = value; + + return _storageLocation.size(); + +} + +bool KeyStorage::initDefaultStorageLocation(const QString &dirName) { + auto storageLoation = + QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + + "/" + dirName; + + if (dirName.isEmpty()) { + storageLoation += THE_CLASS(_cryptoMethod); + } + + storageLoation += "/crypto/"; + + if (!initStorageLocation(storageLoation)) { + QuasarAppUtils::Params::log("CryptoStorage not inited", + QuasarAppUtils::Error); + + return false; + } + + loadAllKeysFromStorage(); + + return _inited = true; +} + +void KeyStorage::clearStorage() const { + QDir::root().remove(storageLocation()); +} + +} diff --git a/Heart/AbstractSpace/keystorage.h b/Heart/AbstractSpace/keystorage.h new file mode 100644 index 0000000..807a663 --- /dev/null +++ b/Heart/AbstractSpace/keystorage.h @@ -0,0 +1,246 @@ +#ifndef KEYSTORAGE_H +#define KEYSTORAGE_H + +#include <QList> +#include <QThread> +#include "heart_global.h" +#include <QByteArray> +#include <QHash> +#include <QSet> +#include "config.h" + +#define RAND_KEY "" + +class QMutex; + + +namespace NP { + +class CryptoPairKeys; +class ICrypto; +/** + * @brief The KeyStorage class - this class provie the functionality of controll crypto keys (generate, save, write); + */ +class KeyStorage: public QThread +{ + Q_OBJECT +public: + /** + * @brief KeyStorage + * @param cryptoMethod - any class inherited from ICrypto + */ + KeyStorage(ICrypto* cryptoMethod); + ~KeyStorage(); + + /** + * @brief getNextPair - take a one pair key from keys pool. + * @warning If key pool is empty then this method frease a current thread for awiting f neg generated pair key. + * @note if the key is not generated within the specified period of time, an invalid copy of the key pair will be returned. + * @param accsessKey - the byte array for get a acceses to key from storage. + * @param genesis - set this params to empty for get random key pair or set the byte array for get a key pair for genesis array. + * @param timeout_msec - timeout in milisecunds. default is WAIT_TIME (30000) + * @return pair of keys. + */ + CryptoPairKeys getNextPair(const QString &accsessKey, + const QByteArray &genesis = RAND_KEY, + int timeout_msec = WAIT_TIME); + + /** + * @brief getKeyPoolSize + * @return + */ + int getKeyPoolSize() const; + + /** + * @brief setKeyPoolSize + * @param keyPoolSize + */ + void setKeyPoolSize(int keyPoolSize); + + /** + * @brief isValid + * @return true if the crypto object is valid. + */ + virtual bool isValid() const; + + /** + * @brief isInited + * @return true if the crypto object has been initialized. + */ + virtual bool isInited() const; + + /** + * @brief crypt + * @param data - pointer to data array for crypting. + * @note data as ben changed after call this method. + * @param publicKey - key for crypting data + * @return true if function finished seccussful + */ + bool crypt(QByteArray *data, const QByteArray& publicKey); + + /** + * @brief decrypt + * @param cryptedData - pointer to data array for decrypting. + * @note cryptedData as ben changed after call this method. + * @param privateKey + * @return true if function finished seccussful + */ + bool decrypt(QByteArray *cryptedData, const QByteArray& privateKey); + + /** + * @brief sign + * @param data - pointer to data array for signed. + * @note data as ben changed after call this method. + * @param privateKey + * @return true if function finished seccussful + */ + bool sign(QByteArray* data, const QByteArray& privateKey); + + /** + * @brief extractSign - extract sign from signed byteArray + * @param data - signed message. + * @return return array of sign. + */ + QByteArray extractSign(const QByteArray& data); + + /** + * @brief concatSign + * @param data - message data + * @return signed message + */ + QByteArray concatSign(const QByteArray& data, const QByteArray& sign); + + /** + * @brief check + * @param publicKey + * @return true if function finished seccussful and signedData is valid. + */ + bool check(const QByteArray& signedData, const QByteArray& publicKey); + + /** + * @brief setGenesisList - set genesis list for generation key pairs + */ + void setGenesisList(const QList<QByteArray> &list); + + /** + * @brief storageLocation + * @default QStandardPaths::DataLocation/KeysStorage + * @return parth to storage location of crypto keys + */ + QString storageLocation() const; + + /** + * @brief initStorageLocation set a new path for storage location of keys. + * @param value - new path + */ + bool initStorageLocation(const QString &value); + + /** + * @brief initDefaultStorageLocation - the some as initStorageLocation, but set default + * path. + * @param dirName - it is name of storage location. If This parametr weel be empty then + * storage location set default dir name. By default is name of crypto class. + * @default default path of storage is '/QStandardPaths::AppDataLocation/crypto/dirName' + * @return true if the storage inited successful + */ + bool initDefaultStorageLocation(const QString& dirName = ""); + + /** + * @brief clearStorage + */ + void clearStorage() const; + +protected: + + /** + * @brief toStorage - save key from genesis into local storage. + * @param genesis - genesis of key pair + * @note override this method if you want to change storage location or method of save of keys. + * @return true if key saved successful + */ + virtual bool toStorage(const QString &genesis) const; + + /** + * @brief fromStorage - load keys from local storage + * @param genesis - genesis of key pair + * @return true if key pair saved seccussful. + */ + virtual bool fromStorage(const QByteArray& key); + + /** + * @brief run - start the key generator. + */ + void run() override; + + /** + * @brief stop - stop generate keys. + */ + void stop(); +private: + + /** + * @brief waitForGeneratekey + * @param timeout - maximum time for generation new key. by default = WAIT_TIME (30000) + * @return true if key generated successful + */ + bool waitForGeneratekey(const QString &key, int timeout = WAIT_TIME) const; + + /** + * @brief waitForThreadFinished + * @param timeout + * @return + */ + bool waitForThreadFinished(int timeout = WAIT_TIME) const; + + /** + * @brief waitFor - base waint function + * @param checkFunc - this is lyambda of check event + * @param timeout - maximu time line of waiting of event + * @return true if event is checkFunc return true + */ + bool waitFor(const std::function<bool()>& checkFunc, int timeout) const; + + /** + * @brief loadAllKeysFromStorage + */ + void loadAllKeysFromStorage(); + + /** + * @brief saveStorage + * @return true if all keys has been saved in a storage. + */ + bool saveStorage() const; + + /** + * @brief genKey - this method add a new task for generate keys pair + * @param accessKey - the byte array for get access of the keys pair. + * @param genesis - the byte array for generate new key + * @note If access key well be empty then this method return false. + * @note for generate random key use a RAND_KEY genesis or empty value. + * @return true if task of generation a new pair keys added seccussful else false. + */ + bool genKey(const QString &accessKey, const QByteArray& genesis = RAND_KEY); + + QHash<QString, CryptoPairKeys> _keys; + QSet<CryptoPairKeys> _randomKeysPool; + + QHash<QString, QByteArray> _generateTasks; + + int _keyPoolSize = 1; + + QMutex *_keyPoolSizeMutex = nullptr; + QMutex *_keysMutex = nullptr; + QMutex *_taskMutex = nullptr; + + QString _storageLocation; + + bool _inited = false; + bool _stopGenerator = false; + + ICrypto *_cryptoMethod = nullptr; + + void generateKeysByTasks(); + void generateRandomKeys(); +}; +} +#endif // KEYSTORAGE_H diff --git a/Heart/AbstractSpace/package.cpp b/Heart/AbstractSpace/package.cpp new file mode 100644 index 0000000..9f730eb --- /dev/null +++ b/Heart/AbstractSpace/package.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018-2020 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 "abstractdata.h" +#include "package.h" + +#include <QDataStream> + +namespace NP { + +Package::Package() { + reset(); +} + +bool Package::isValid() const { + if (!hdr.isValid()) { + return false; + } + + auto rawint = data.mid(0, sizeof (decltype (hdr.command))); + decltype (hdr.command) cmd; + memcpy(&cmd, rawint.data(), sizeof (cmd)); + + if (data.size() && hdr.command != cmd) { + std::reverse(rawint.begin(), rawint.end()); + memcpy(&cmd, rawint.data(), sizeof (cmd)); + + if (hdr.command != cmd) + return false; + } + + if (hdr.size != data.size()) { + return false; + } + + return qHash(data) == hdr.hash; +} + +void Package::reset() { + hdr.reset(); + data.clear(); +} + +QString Package::toString() const { + return QString("Pakcage description: %0." + " Data description: Data size - %1, Data: %2"). + arg(hdr.toString()).arg(data.size()).arg(QString(data.toHex().toUpper())); +} + +QDataStream &Package::fromStream(QDataStream &stream) { + reset(); + stream.readRawData(reinterpret_cast<char*>(&hdr), sizeof(Header)); + + char * buf = static_cast<char*>(malloc(hdr.size)); + stream.readRawData(buf, hdr.size); + data.clear(); + data.insert(0, buf, hdr.size); + + free(buf); + + return stream; +} + +QDataStream &Package::toStream(QDataStream &stream) const { + stream.writeRawData(reinterpret_cast<const char*>(&hdr), + sizeof (hdr)); + + stream.writeRawData(data.data(), + data.size()); + + return stream; +} + +} diff --git a/NetworkProtocol/package.h b/Heart/AbstractSpace/package.h similarity index 50% rename from NetworkProtocol/package.h rename to Heart/AbstractSpace/package.h index 8cd5d3d..972f9e7 100644 --- a/NetworkProtocol/package.h +++ b/Heart/AbstractSpace/package.h @@ -1,9 +1,17 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTPACKAGE_H #define ABSTRACTPACKAGE_H #include "header.h" -#include "networkprotocol_global.h" +#include "heart_global.h" #include <QByteArray> +#include <baseid.h> namespace NP { @@ -11,7 +19,9 @@ class Abstract; /** * @brief The Package struct */ -struct NETWORKPROTOCOLSHARED_EXPORT Package { +class NETWORKPROTOCOLSHARED_EXPORT Package: public StreamBase { + +public: /** * @brief hdr - header of package */ @@ -22,6 +32,7 @@ struct NETWORKPROTOCOLSHARED_EXPORT Package { QByteArray data; Package(); + virtual ~Package() = default; /** * @brief isValid @@ -29,24 +40,21 @@ struct NETWORKPROTOCOLSHARED_EXPORT Package { */ virtual bool isValid() const; - /** - * @brief toBytes - * @return bytes array of packag - */ - virtual QByteArray toBytes() const; - - /** - * @brief fromBytes - * @return bytes array to packag - */ - virtual void fromBytes(const QByteArray &array); /** * @brief reset - reset all data and set for package invalid status */ virtual void reset(); - virtual ~Package() = default; + /** + * @brief toString - convert pakcage information to string label + * @return string + */ + QString toString() const; + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; }; } diff --git a/Heart/AbstractSpace/packagemanager.cpp b/Heart/AbstractSpace/packagemanager.cpp new file mode 100644 index 0000000..9526d66 --- /dev/null +++ b/Heart/AbstractSpace/packagemanager.cpp @@ -0,0 +1,59 @@ +#include "packagemanager.h" + +#include <package.h> +#include <ctime> +#include <config.h> + +namespace NP { + +PackageManager::PackageManager() +{ + +} + +PackageManager::~PackageManager() { + for (const auto& data : _parseResults) { + delete data; + } + + _parseResults.clear(); +} + +const Package *PackageManager::getPkgFromArhive(const unsigned int &id) const { + if (!contains(id)) + return nullptr; + + QMutexLocker lock(&_processMutex); + return _parseResults.value(id)->_data; +} + +bool PackageManager::contains(const unsigned int &id) const { + QMutexLocker lock(&_processMutex); + return _parseResults.contains(id); +} + +void PackageManager::processed(const Package &pkg, char processResult) { + + if (!pkg.hdr.hash || !PACKAGE_CACHE_SIZE) { + return; + } + + QMutexLocker lock(&_processMutex); + + if (_parseResults.size() > PACKAGE_CACHE_SIZE) { + _processTime.erase(_processTime.begin()); + } + + _parseResults.insert(pkg.hdr.hash, new PackaData { + processResult, + new Package(pkg) + }); + + _processTime.insert(static_cast<int>(time(0)), pkg.hdr.hash); +} + +PackageManager::PackaData::~PackaData() { + delete _data; +} + +} diff --git a/Heart/AbstractSpace/packagemanager.h b/Heart/AbstractSpace/packagemanager.h new file mode 100644 index 0000000..fa037a4 --- /dev/null +++ b/Heart/AbstractSpace/packagemanager.h @@ -0,0 +1,58 @@ +#ifndef PAKCAGEMANAGER_H +#define PAKCAGEMANAGER_H + +#include <QMutex> +#include <QSharedDataPointer> +#include <baseid.h> + + +namespace NP { + +/** + * @brief The PakcageManager class - contains all processed packages + */ +class PackageManager +{ +public: + PackageManager(); + ~PackageManager(); + + /** + * @brief getPkgFromArhive - return pointer tot package from arhive. + * @param id - id of the requariment package. + * @result pointer of the processed package, if package not return nullpt + */ + const Package * getPkgFromArhive(const unsigned int &id) const; + + /** + * @brief contains - check packge by id + * @param id + * @return true if pakcge has been parsed + */ + bool contains(const unsigned int& id) const; + + /** + * @brief processed - add package to arhice + * @param pkg - object of package + * @param processResult - result of method parsePackage. + */ + void processed(const Package& pkg, char processResult); +private: + /** + * @brief The PackaData struct - private data of packages + */ + struct PackaData { + char _parseResult; + Package *_data = nullptr; + + ~PackaData(); + }; + + QMultiMap<int, unsigned int> _processTime; + QHash<unsigned int, const PackaData*> _parseResults; + + mutable QMutex _processMutex; +}; + +} +#endif // PAKCAGEMANAGER_H diff --git a/Heart/AbstractSpace/packages/abstractdata.cpp b/Heart/AbstractSpace/packages/abstractdata.cpp new file mode 100644 index 0000000..432c6d0 --- /dev/null +++ b/Heart/AbstractSpace/packages/abstractdata.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2018-2020 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 "abstractdata.h" +#include <QDataStream> +#include <QMap> +#include <typeinfo> +#include "heart.h" +#include <limits> +#include <quasarapp.h> +#include <QCryptographicHash> + +namespace NP { + +unsigned short AbstractData::cmd() const { + return _cmd; +} + +void AbstractData::setCmd(unsigned short cmd) { + _cmd = cmd; +} + +bool AbstractData::init() { + if (typeid (*this).hash_code() == typeid(AbstractData).hash_code()) + return false; + + generateCmd(); + + return true; +} + +void AbstractData::generateCmd() { + setCmd(H_16(*this)); +} + +AbstractData::AbstractData() { + _cmd = 0; +} + +bool AbstractData::fromBytes(const QByteArray &data) { + return StreamBase::fromBytes(data); +} + +QByteArray AbstractData::toBytes() const { + return StreamBase::toBytes(); +} + +bool AbstractData::toPackage(Package &package, + unsigned int triggerHash) const { + + if (!isValid()) { + return false; + } + + package.data = toBytes(); + + package.hdr.command = _cmd; + package.hdr.triggerHash = triggerHash; + package.hdr.size = static_cast<unsigned short>(package.data.size()); + package.hdr.hash = qHash(package.data); + + return package.isValid(); +} + +QDataStream &AbstractData::fromStream(QDataStream &stream) { + stream >> _cmd; + return stream; +} + +QDataStream &AbstractData::toStream(QDataStream &stream) const { + stream << _cmd; + return stream; +} + +bool AbstractData::isValid() const { + return _cmd; +} + +bool AbstractData::copyFrom(const AbstractData *other) { + + return other; +} + +QString AbstractData::toString() const { + return QString("Object: type:%0, command:%1"). + arg(typeid(*this).name()). + arg(_cmd); +} + +bool AbstractData::prepareToSend() { + if (isValid()) { + return true; + } + + return init(); +} + +AbstractData::~AbstractData() { + +} + + +} diff --git a/Heart/AbstractSpace/packages/abstractdata.h b/Heart/AbstractSpace/packages/abstractdata.h new file mode 100644 index 0000000..e12dbad --- /dev/null +++ b/Heart/AbstractSpace/packages/abstractdata.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTDATA_H +#define ABSTRACTDATA_H +#include "package.h" +#include <streambase.h> +#include <global.h> + +namespace NP { + +/** + * @brief The AbstractData class + * all data packages inherited this class. + */ +class NETWORKPROTOCOLSHARED_EXPORT AbstractData : public StreamBase +{ +public: + + virtual ~AbstractData() override; + + /** + * @brief cmd + * @return command of package + */ + unsigned short cmd() const; + + /** + * @brief toBytes + * @return byte array for package + */ + QByteArray toBytes() const; + + + /** + * @brief toPackage + * @param package - return value + * @param trigeredCommand - old cmd + * @return retorn package object created from this object. + */ + bool toPackage(Package &package, unsigned int triggerHash = 0) const; + + /** + * @brief isValid + * @return true if class isValid + */ + virtual bool isValid() const; + + /** + * @brief copyFrom this function try cast other object to this class type + * and invoke copy operation. cmd option is ignored; + * @param other + * @return true if all good + */ + virtual bool copyFrom(const AbstractData*); + + /** + * @brief toString - return a string implementation fo this object + * @return string of object + */ + virtual QString toString() const; + + /** + * @brief prepareToSend - this method check object to valid and if an object is invalid invoke method init. + * @return return true if the object prepared for sending. + */ + bool prepareToSend(); + + /** + * @brief create - this is factory method for create a new object with some type that parent object. + * @param args - list of arguments for create object + * @return pointer toObject + */ + template<class C, class... Args> + C* create(Args&&... args) const { + C* object = new C(std::forward<Args>(args)...); + object->generateCmd(); + return object; + } + +protected: + /** + * @brief AbstractData + */ + explicit AbstractData(); + + /** + * @brief fromBytes - private initialisation of object from byte array + * @return true if all good + */ + bool fromBytes(const QByteArray&); + + /** + * @brief setCmd + * @param cmd + */ + void setCmd(unsigned short cmd); + + /** + * @brief init - this method need to invoke after create object for initialize all componet of ojects. + * @note do not invode this method on constructor of object, becose object wel be initialized not correctly. + * @default defaul implementation of object init _com of object. + * @return true if object initialized correctly. + */ + virtual bool init(); + + + /** + * @brief fromStream + * @param stream + * @return stream + */ + QDataStream& fromStream(QDataStream& stream) override; + + /** + * @brief toStream + * @param stream + * @return stream + */ + QDataStream& toStream(QDataStream& stream) const override; + +private: + /** + * @brief generateCmd set cmd from class name. + * @note call this method only after create objects. do not call in constructor of class. + */ + void generateCmd(); + /** + * @brief _cmd - unique id of class using in Header of package for identification. + */ + unsigned short _cmd = 0; +}; + + +} + +#endif // ABSTRACTDATA_H diff --git a/NetworkProtocol/DataPacakages/badrequest.cpp b/Heart/AbstractSpace/packages/badrequest.cpp similarity index 72% rename from NetworkProtocol/DataPacakages/badrequest.cpp rename to Heart/AbstractSpace/packages/badrequest.cpp index 910724a..279b1fb 100644 --- a/NetworkProtocol/DataPacakages/badrequest.cpp +++ b/Heart/AbstractSpace/packages/badrequest.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 "badrequest.h" #include <QDataStream> @@ -6,7 +13,7 @@ namespace NP{ BadRequest::BadRequest(const QString &err):AbstractData() { - INIT_COMMAND + setErr(err); diff --git a/NetworkProtocol/DataPacakages/badrequest.h b/Heart/AbstractSpace/packages/badrequest.h similarity index 68% rename from NetworkProtocol/DataPacakages/badrequest.h rename to Heart/AbstractSpace/packages/badrequest.h index db90d4b..d6deca5 100644 --- a/NetworkProtocol/DataPacakages/badrequest.h +++ b/Heart/AbstractSpace/packages/badrequest.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 BADREQUEST_H #define BADREQUEST_H diff --git a/Heart/AbstractSpace/packages/closeconnection.cpp b/Heart/AbstractSpace/packages/closeconnection.cpp new file mode 100644 index 0000000..e2e93f0 --- /dev/null +++ b/Heart/AbstractSpace/packages/closeconnection.cpp @@ -0,0 +1,8 @@ +#include "closeconnection.h" + +namespace NP { +CloseConnection::CloseConnection() +{ + +} +} diff --git a/Heart/AbstractSpace/packages/closeconnection.h b/Heart/AbstractSpace/packages/closeconnection.h new file mode 100644 index 0000000..7a54061 --- /dev/null +++ b/Heart/AbstractSpace/packages/closeconnection.h @@ -0,0 +1,22 @@ +#ifndef CLOSECONNECTION_H +#define CLOSECONNECTION_H + +#include "abstractdata.h" + + +namespace NP{ + +/** + * @brief The CloseConnection class - This commnad is request for close connection on parent node of connection + * This neede becouse QAbstractSocket emit error when connection closed from remote node. + * + * From QtDocumentation : + * ``` If the remote host closes the connection, QAbstractSocket will emit errorOccurred(QAbstractSocket::RemoteHostClosedError), during which the socket state will still be ConnectedState, and then the disconnected() signal will be emitted.``` + */ +class NETWORKPROTOCOLSHARED_EXPORT CloseConnection: public AbstractData +{ +public: + CloseConnection(); +}; +} +#endif // CLOSECONNECTION_H diff --git a/Heart/AbstractSpace/packages/ping.cpp b/Heart/AbstractSpace/packages/ping.cpp new file mode 100644 index 0000000..ba2ffb3 --- /dev/null +++ b/Heart/AbstractSpace/packages/ping.cpp @@ -0,0 +1,50 @@ +#include "ping.h" + +#include <QDataStream> +namespace NP { + +Ping::Ping() { + +} + +Ping::Ping(const Package &from): Ping() { + fromBytes(from.data); +} + +bool Ping::isValid() const { + return AbstractData::isValid(); +} + +bool Ping::copyFrom(const AbstractData * other) { + if (!AbstractData::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const Ping*>(other); + if (!otherObject) + return false; + + this->_ansver = otherObject->_ansver; + return true; +} + +bool Ping::ansver() const { + return _ansver; +} + +void Ping::setAnsver(bool ansver) { + _ansver = ansver; +} + +QDataStream &Ping::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + stream >> _ansver; + return stream; + +} + +QDataStream &Ping::toStream(QDataStream &stream) const { + AbstractData::toStream(stream); + stream << _ansver; + return stream; +} +} diff --git a/Heart/AbstractSpace/packages/ping.h b/Heart/AbstractSpace/packages/ping.h new file mode 100644 index 0000000..31aff84 --- /dev/null +++ b/Heart/AbstractSpace/packages/ping.h @@ -0,0 +1,34 @@ +#ifndef PING_H +#define PING_H + +#include "abstractdata.h" + + +namespace NP { + +/** + * @brief The Ping class - test class for translate data on network + */ +class NETWORKPROTOCOLSHARED_EXPORT Ping: public AbstractData +{ +public: + Ping(); + Ping(const Package& from); + + // AbstractData interface + bool isValid() const; + bool copyFrom(const AbstractData *); + + bool ansver() const; + void setAnsver(bool ansver); + +protected: + // StreamBase interface + QDataStream &fromStream(QDataStream &stream); + QDataStream &toStream(QDataStream &stream) const; + +private: + bool _ansver = false; +}; +} +#endif // PING_H diff --git a/Heart/AbstractSpace/qsecretrsa2048.cpp b/Heart/AbstractSpace/qsecretrsa2048.cpp new file mode 100644 index 0000000..25153c0 --- /dev/null +++ b/Heart/AbstractSpace/qsecretrsa2048.cpp @@ -0,0 +1,73 @@ +#include "cryptopairkeys.h" +#include "qsecretrsa2048.h" +#include <QDir> +#include <qrsaencryption.h> + +namespace NP { + +QSecretRSA2048::QSecretRSA2048() { + qtSecret = new QRSAEncryption(QRSAEncryption::RSA_2048); +} + +CryptoPairKeys QSecretRSA2048::generate(const QByteArray &genesis) const { + QByteArray pubKey; + QByteArray privKey; + + qtSecret->generatePairKey(pubKey, privKey, genesis); + + return {pubKey, privKey}; +} + +bool QSecretRSA2048::crypt(QByteArray *data, + const QByteArray &publicKey) { + *data = qtSecret->encode(*data, publicKey); + + return data->size(); +} + +bool QSecretRSA2048::decrypt(QByteArray *cryptedData, + const QByteArray &privateKey) { + *cryptedData = qtSecret->decode(*cryptedData, privateKey); + + return cryptedData->size(); +} + +bool QSecretRSA2048::sign(QByteArray *data, + const QByteArray &privateKey) { + + *data = qtSecret->signMessage(*data, privateKey); + return data->size(); + +} + +bool QSecretRSA2048::check(const QByteArray &signedData, + const QByteArray &publicKey) { + + return qtSecret->checkSignMessage(signedData, publicKey); +} + +QByteArray QSecretRSA2048::extractSign(const QByteArray &data) { + + int end = data.lastIndexOf("-SIGN-"); + int begin = data.lastIndexOf("-SIGN-", end); + + if (end < 0 || begin < 0) { + return {}; + } + + return QByteArray::fromHex(data.mid(begin, begin - end)); +} + +QByteArray QSecretRSA2048::concatSign(const QByteArray &data, const QByteArray &sign) { + return data + "-SIGN-" + sign.toHex() + "-SIGN-"; +} + +bool QSecretRSA2048::isValid() const { + return qtSecret; +} + +QSecretRSA2048::~QSecretRSA2048() { + delete qtSecret; +} + +} diff --git a/Heart/AbstractSpace/qsecretrsa2048.h b/Heart/AbstractSpace/qsecretrsa2048.h new file mode 100644 index 0000000..39a0b25 --- /dev/null +++ b/Heart/AbstractSpace/qsecretrsa2048.h @@ -0,0 +1,44 @@ +#ifndef QSECRETRSA2048_H +#define QSECRETRSA2048_H + +#include "icrypto.h" + +#include <QHash> + +class QRSAEncryption; + +namespace NP { + +/** + * @brief The QSecretRSA2048 class Use + */ +class NETWORKPROTOCOLSHARED_EXPORT QSecretRSA2048: public ICrypto +{ + // ICrypto interface +public: + QSecretRSA2048(); + ~QSecretRSA2048() override; + bool crypt(QByteArray *data, const QByteArray &publicKey) override; + bool decrypt(QByteArray *cryptedData, const QByteArray &privateKey) override; + bool sign(QByteArray *data, const QByteArray &privateKey) override; + bool check(const QByteArray &signedData, const QByteArray &publicKey) override; + QByteArray extractSign(const QByteArray &data) override; + QByteArray concatSign(const QByteArray &data, const QByteArray &sign) override; + + /** + * @brief isValid + * @return true if object is valid. + */ + bool isValid() const override; + +protected: + CryptoPairKeys generate(const QByteArray& genesis = {}) const override; + + +private: + QRSAEncryption *qtSecret = nullptr; + + +}; +} +#endif // QSECRETRSA2048_H diff --git a/Heart/AbstractSpace/receivedata.cpp b/Heart/AbstractSpace/receivedata.cpp new file mode 100644 index 0000000..10f23a6 --- /dev/null +++ b/Heart/AbstractSpace/receivedata.cpp @@ -0,0 +1,9 @@ +#include "receivedata.h" + +namespace NP { + +ReceiveData::ReceiveData() +{ + +} +} diff --git a/Heart/AbstractSpace/receivedata.h b/Heart/AbstractSpace/receivedata.h new file mode 100644 index 0000000..5074b8a --- /dev/null +++ b/Heart/AbstractSpace/receivedata.h @@ -0,0 +1,21 @@ +#ifndef RECEIVEDATA_H +#define RECEIVEDATA_H + +#include "package.h" + +namespace NP { + +/** + * @brief The ReceiveData struct - this structure contains informaton for parse packages + */ +struct ReceiveData +{ +public: + ReceiveData(); + + Package _pkg; + QByteArray _hdrArray; + +}; +} +#endif // RECEIVEDATA_H diff --git a/Heart/AbstractSpace/request.cpp b/Heart/AbstractSpace/request.cpp new file mode 100644 index 0000000..c3eabfd --- /dev/null +++ b/Heart/AbstractSpace/request.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018-2020 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 "request.h" +namespace NP { + +Request::Request() { + +} + +unsigned char Request::getRequestCmd() const { + return requestCmd; +} + +void Request::setRequestCmd(unsigned char value) { + requestCmd = value; +} + +} diff --git a/Heart/AbstractSpace/request.h b/Heart/AbstractSpace/request.h new file mode 100644 index 0000000..6713127 --- /dev/null +++ b/Heart/AbstractSpace/request.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018-2020 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 IREQUEST_H +#define IREQUEST_H + +#include "heart_global.h" + +namespace NP { + +/** + * @brief The Request class - base request methods for data packages + */ +class NETWORKPROTOCOLSHARED_EXPORT Request +{ +public: + Request(); + unsigned char getRequestCmd() const; + void setRequestCmd(unsigned char value); + +protected: + unsigned char requestCmd = 0; + +}; +} +#endif // IREQUEST_H diff --git a/NetworkProtocol/streambase.cpp b/Heart/AbstractSpace/streambase.cpp similarity index 74% rename from NetworkProtocol/streambase.cpp rename to Heart/AbstractSpace/streambase.cpp index 86f3036..4434dad 100644 --- a/NetworkProtocol/streambase.cpp +++ b/Heart/AbstractSpace/streambase.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 "package.h" #include "streambase.h" diff --git a/NetworkProtocol/streambase.h b/Heart/AbstractSpace/streambase.h similarity index 76% rename from NetworkProtocol/streambase.h rename to Heart/AbstractSpace/streambase.h index 0063dbd..a03262d 100644 --- a/NetworkProtocol/streambase.h +++ b/Heart/AbstractSpace/streambase.h @@ -1,15 +1,25 @@ +/* + * Copyright (C) 2018-2020 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 STREAMBASE_H #define STREAMBASE_H #include <QByteArray> #include <QVariantMap> -#include "networkprotocol_global.h" +#include "heart_global.h" class QDataStream; namespace NP { class Package; +/** + * @brief The StreamBase class - this class add support for streaming data for all cheldren classes. + */ class NETWORKPROTOCOLSHARED_EXPORT StreamBase { public: @@ -28,20 +38,6 @@ public: */ QByteArray toBytes() const; - /** - * @brief fromStream - * @param stream - * @return stream - */ - virtual QDataStream& fromStream(QDataStream& stream) = 0; - - /** - * @brief toStream - * @param stream - * @return stream - */ - virtual QDataStream& toStream(QDataStream& stream) const = 0; - /** * @brief operator << it is wraper over toStream @@ -60,7 +56,20 @@ public: friend QDataStream& operator>> (QDataStream& stream, StreamBase& obj); +protected: + /** + * @brief fromStream + * @param stream + * @return stream + */ + virtual QDataStream& fromStream(QDataStream& stream) = 0; + /** + * @brief toStream + * @param stream + * @return stream + */ + virtual QDataStream& toStream(QDataStream& stream) const = 0; }; } diff --git a/NetworkProtocol/workstate.cpp b/Heart/AbstractSpace/workstate.cpp similarity index 76% rename from NetworkProtocol/workstate.cpp rename to Heart/AbstractSpace/workstate.cpp index 8938ce8..dd7aee7 100644 --- a/NetworkProtocol/workstate.cpp +++ b/Heart/AbstractSpace/workstate.cpp @@ -1,6 +1,13 @@ +/* + * Copyright (C) 2018-2020 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 "workstate.h" -#include <QHostAddress> +#include <hostaddress.h> namespace NP{ @@ -61,11 +68,11 @@ void WorkState::setMaxConnectionCount(int value) { maxConnectionCount = value; } -QList<QHostAddress> WorkState::getBanedList() const { +QList<HostAddress> WorkState::getBanedList() const { return _banedList; } -void WorkState::setBanedList(const QList<QHostAddress> &banedList) { +void WorkState::setBanedList(const QList<HostAddress> &banedList) { _banedList = banedList; } } diff --git a/NetworkProtocol/workstate.h b/Heart/AbstractSpace/workstate.h similarity index 77% rename from NetworkProtocol/workstate.h rename to Heart/AbstractSpace/workstate.h index 36eb918..ea06131 100644 --- a/NetworkProtocol/workstate.h +++ b/Heart/AbstractSpace/workstate.h @@ -1,7 +1,14 @@ +/* + * Copyright (C) 2018-2020 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 WORKSTATE_H #define WORKSTATE_H -#include <QHostAddress> +#include <hostaddress.h> #include <QList> namespace NP { @@ -16,7 +23,7 @@ private: int maxConnectionCount = 0; bool isRun = false; - QList<QHostAddress> _banedList; + QList<HostAddress> _banedList; QString getWorkStateString() const; public: @@ -60,13 +67,13 @@ public: * @brief getBanedList * @return list of id's of baned nodes */ - QList<QHostAddress> getBanedList() const; + QList<HostAddress> getBanedList() const; /** * @brief setBanedList * @param banedList set new baned list */ - void setBanedList(const QList<QHostAddress> &banedList); + void setBanedList(const QList<HostAddress> &banedList); /** * @brief getIsRun diff --git a/Heart/CMakeLists.txt b/Heart/CMakeLists.txt new file mode 100644 index 0000000..1e0fad4 --- /dev/null +++ b/Heart/CMakeLists.txt @@ -0,0 +1,87 @@ +# +# Copyright (C) 2018-2020 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. +# + +cmake_minimum_required(VERSION 3.10) + +include(../QuasarAppLib/CMake/ProjectOut.cmake) +include(../QuasarAppLib/CMake/Version.cmake) + +add_subdirectory(Qt-Secret) + + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + + + +add_definitions(-DNETWORKPROTOCOL_LIBRARY) + + +find_package(Qt5 COMPONENTS Core Network Sql Concurrent REQUIRED) + +if (${BUILD_LVL} GREATER_EQUAL 0) + message("BUILD LVL >= 0") + file(GLOB SOURCE_CPP_LVL_0 + "*.cpp" "*.qrc" + "AbstractSpace/*.cpp" "AbstractSpace/*.qrc" + "AbstractSpace/packages/*.cpp" "AbstractSpace/packages/*.qrc" + "AbstractSpace/Private/*.cpp" "AbstractSpace/Private/*.qrc" + + ) + + set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace") + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace/packages") + set(PRIVATE_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace/Private") + +endif() + +if (${BUILD_LVL} GREATER_EQUAL 1) + message("BUILD LVL >= 1") + file(GLOB SOURCE_CPP_LVL_1 + "DataBaseSpace/*.cpp" "DataBaseSpace/*.qrc" + "DataBaseSpace/packages/*.cpp" "DataBaseSpace/packages/*.qrc" + "DataBaseSpace/Private/*.cpp" "DataBaseSpace/Private/*.qrc" + ) + + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace") + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace/packages") + + set(PRIVATE_INCUDE_DIR ${PRIVATE_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace/Private") + +endif() + +if (${BUILD_LVL} GREATER_EQUAL 2) + message("BUILD LVL >= 2") + file(GLOB SOURCE_CPP_LVL_2 + "NetworkSpace/*.cpp" "NetworkSpace/*.qrc" + "NetworkSpace/packages/*.cpp" "NetworkSpace/packages/*.qrc" + "NetworkSpace/Private/*.cpp" "NetworkSpace/Private/*.qrc" + ) + + + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace") + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace/packages") + + set(PRIVATE_INCUDE_DIR ${PRIVATE_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace/Private") + +endif() + +set(SOURCE_CPP ${SOURCE_CPP_LVL_0} ${SOURCE_CPP_LVL_1} ${SOURCE_CPP_LVL_2}) + + +add_library(${PROJECT_NAME} SHARED ${SOURCE_CPP}) +target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core Qt5::Network Qt5::Sql Qt5::Concurrent QuasarApp crypto ssl Qt-Secret) + +target_include_directories(${PROJECT_NAME} PUBLIC ${PUBLIC_INCUDE_DIR}) +target_include_directories(${PROJECT_NAME} PRIVATE ${PRIVATE_INCUDE_DIR}) + + +setVersion(1 1 0) diff --git a/Heart/DataBaseSpace/Res/BaseDB.sql b/Heart/DataBaseSpace/Res/BaseDB.sql new file mode 100644 index 0000000..5a0dff1 --- /dev/null +++ b/Heart/DataBaseSpace/Res/BaseDB.sql @@ -0,0 +1,19 @@ + +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); diff --git a/NetworkProtocol/Res/DefaultDbConfig.json b/Heart/DataBaseSpace/Res/DbConfig.json similarity index 100% rename from NetworkProtocol/Res/DefaultDbConfig.json rename to Heart/DataBaseSpace/Res/DbConfig.json diff --git a/Heart/DataBaseSpace/abstractkey.cpp b/Heart/DataBaseSpace/abstractkey.cpp new file mode 100644 index 0000000..aba26a4 --- /dev/null +++ b/Heart/DataBaseSpace/abstractkey.cpp @@ -0,0 +1 @@ +#include "abstractkey.h" diff --git a/Heart/DataBaseSpace/abstractkey.h b/Heart/DataBaseSpace/abstractkey.h new file mode 100644 index 0000000..d723cb0 --- /dev/null +++ b/Heart/DataBaseSpace/abstractkey.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018-2020 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 ABSTRACTKEY_H +#define ABSTRACTKEY_H +#include "heart_global.h" + +#include <baseid.h> + +namespace NP { + +/** + * @brief The Abstractkey class - this class provid one hash function for all keys of database objcets + */ +class NETWORKPROTOCOLSHARED_EXPORT AbstractKey +{ +public: + AbstractKey() = default; + + virtual ~AbstractKey() = default; + virtual unsigned int hash() const = 0; + virtual bool equal(const AbstractKey* other) const = 0; + + /** + * @brief id - this method return id of object + * @return BaseId of object. + */ + virtual const BaseId& id() const = 0; + + /** + * @brief table - this method return table name of object + * @return table name + */ + virtual const QString& table() const = 0; + + /** + * @brief isValid + * @return true if key is valid + */ + virtual bool isValid() const = 0; +}; + + +} +#endif // ABSTRACTKEY_H diff --git a/NetworkProtocol/accesstoken.cpp b/Heart/DataBaseSpace/accesstoken.cpp similarity index 88% rename from NetworkProtocol/accesstoken.cpp rename to Heart/DataBaseSpace/accesstoken.cpp index b94265d..f118036 100644 --- a/NetworkProtocol/accesstoken.cpp +++ b/Heart/DataBaseSpace/accesstoken.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 <QCryptographicHash> #include <QDataStream> diff --git a/NetworkProtocol/accesstoken.h b/Heart/DataBaseSpace/accesstoken.h similarity index 87% rename from NetworkProtocol/accesstoken.h rename to Heart/DataBaseSpace/accesstoken.h index 249f8e1..bb960c3 100644 --- a/NetworkProtocol/accesstoken.h +++ b/Heart/DataBaseSpace/accesstoken.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 ACCSESTOKEN_H #define ACCSESTOKEN_H @@ -5,7 +12,7 @@ #include <QByteArray> #include <QDateTime> -#include <networkprotocol_global.h> +#include <heart_global.h> namespace NP { diff --git a/Heart/DataBaseSpace/asyncsqldbwriter.cpp b/Heart/DataBaseSpace/asyncsqldbwriter.cpp new file mode 100644 index 0000000..26e834c --- /dev/null +++ b/Heart/DataBaseSpace/asyncsqldbwriter.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2018-2020 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 "asyncsqldbwriter.h" + +#include <QDateTime> +#include <QMetaMethod> +#include <QThread> +#include <dbobject.h> +#include <quasarapp.h> + +namespace NP { + + +AsyncSqlDbWriter::AsyncSqlDbWriter(QObject *ptr): + QObject(ptr) { + _own = new QThread(this); + moveToThread(_own); + _own->start(); + +} + +AsyncSqlDbWriter::~AsyncSqlDbWriter() { + _own->quit(); + _own->wait(); +} + +bool AsyncSqlDbWriter::saveObject(const DBObject *saveObject) { + if (QThread::currentThread() == thread()) { + return SqlDBWriter::saveObject(saveObject); + } + + return QMetaObject::invokeMethod(this, + "handleSaveObject", + Qt::QueuedConnection, + Q_ARG(const NP::DBObject *, saveObject), + Q_ARG(bool *, nullptr), + Q_ARG(bool *, nullptr)); + +} + +bool AsyncSqlDbWriter::deleteObject(const DBObject *deleteObject) { + if (QThread::currentThread() == thread()) { + return SqlDBWriter::deleteObject(deleteObject); + } + + return QMetaObject::invokeMethod(this, + "handleDeleteObject", + Qt::QueuedConnection, + Q_ARG(const NP::DBObject *, deleteObject), + Q_ARG(bool *, nullptr), + Q_ARG(bool *, nullptr)); +} + +bool AsyncSqlDbWriter::saveObjectWithWait(const DBObject *saveObject) { + if (QThread::currentThread() == thread()) { + return SqlDBWriter::saveObject(saveObject); + } + + bool workOfEnd = false, workResult = false; + + + bool invoke = QMetaObject::invokeMethod(this, + "handleSaveObject", + Qt::QueuedConnection, + Q_ARG(const NP::DBObject *, saveObject), + Q_ARG(bool *, &workResult), + Q_ARG(bool *, &workOfEnd)); + + if (!invoke) { + QuasarAppUtils::Params::log("handleDeleteObject not invokecd", QuasarAppUtils::Debug); + return false; + } + + + if (!waitFor(&workOfEnd)) { + return false; + } + + return workResult; +} + +bool AsyncSqlDbWriter::deleteObjectWithWait(const DBObject *deleteObject) { + if (QThread::currentThread() == thread()) { + return SqlDBWriter::deleteObject(deleteObject); + } + + bool workOfEnd = false, workResult = false; + + + bool invoke = QMetaObject::invokeMethod(this, + "handleDeleteObject", + Qt::QueuedConnection, + Q_ARG(const NP::DBObject *, deleteObject), + Q_ARG(bool *, &workResult), + Q_ARG(bool *, &workOfEnd)); + + if (!invoke) { + QuasarAppUtils::Params::log("handleDeleteObject not invokecd", QuasarAppUtils::Debug); + return false; + } + + + if (!waitFor(&workOfEnd)) { + return false; + } + + return workResult; +} + +bool AsyncSqlDbWriter::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) { + + if (QThread::currentThread() == thread()) { + return SqlDBWriter::getAllObjects(templateObject, result); + } + + bool workOfEnd = false, workResult = false; + + + bool invockeResult = QMetaObject::invokeMethod(this, + "handleGetAllObject", + Qt::QueuedConnection, + Q_ARG(const NP::DBObject *, &templateObject), + Q_ARG(QList<const NP::DBObject *> *, &result), + Q_ARG(bool *, &workResult), + Q_ARG(bool *, &workOfEnd)); + + if (!invockeResult) + return false; + + + if (!waitFor(&workOfEnd)) { + return false; + } + + return workResult; +} + +bool AsyncSqlDbWriter::initDb(const QVariantMap ¶ms) { + if (QThread::currentThread() == thread()) { + return SqlDBWriter::initDb(params); + } + + bool workOfEnd = false, workResult = false; + + + bool invockeResult = QMetaObject::invokeMethod(this, + "handleInitDb", + Qt::QueuedConnection, + Q_ARG(const QVariantMap &, params), + Q_ARG(bool *, &workResult), + Q_ARG(bool *, &workOfEnd)); + + if (!invockeResult) + return false; + + + if (!waitFor(&workOfEnd)) { + return false; + } + + return workResult; +} + +void AsyncSqlDbWriter::handleSaveObject(const DBObject* saveObject, + bool *resultOfWork, + bool *endOfWork) { + if (resultOfWork) { + *resultOfWork = SqlDBWriter::saveObject(saveObject); + + if (endOfWork) { + *endOfWork = true; + } + + } else { + if (!SqlDBWriter::saveObject(saveObject)) { + QuasarAppUtils::Params::log("AsyncSqlDbWriter: save object fail!", + QuasarAppUtils::Error); + } + } +} + +void AsyncSqlDbWriter::handleDeleteObject(const DBObject *deleteObject, bool *resultOfWork, bool *endOfWork) { + if (resultOfWork) { + *resultOfWork = SqlDBWriter::deleteObject(deleteObject); + + if (endOfWork) { + *endOfWork = true; + } + + } else { + if (!SqlDBWriter::deleteObject(deleteObject)) { + QuasarAppUtils::Params::log("AsyncSqlDbWriter: delete object fail!", + QuasarAppUtils::Error); + } + } +} + +void AsyncSqlDbWriter::handleGetAllObject(const DBObject *templateObject, + QList<const DBObject *> *result, + bool *resultOfWork, bool *endOfWork) { + + + *resultOfWork = SqlDBWriter::getAllObjects(*templateObject, *result); + + if (endOfWork) { + *endOfWork = true; + } + +} + +void AsyncSqlDbWriter::handleInitDb(const QVariantMap ¶ms, + bool *resultOfWork, bool *endOfWork) { + + *resultOfWork = SqlDBWriter::initDb(params); + + if (endOfWork) { + *endOfWork = true; + } +} + +bool AsyncSqlDbWriter::waitFor(bool *condition, int timeout) const { + auto curmsec = QDateTime::currentMSecsSinceEpoch() + timeout; + while (curmsec > QDateTime::currentMSecsSinceEpoch() && !*condition) { + QCoreApplication::processEvents(); + } + QCoreApplication::processEvents(); + return *condition; +} + +} diff --git a/Heart/DataBaseSpace/asyncsqldbwriter.h b/Heart/DataBaseSpace/asyncsqldbwriter.h new file mode 100644 index 0000000..8dbb1bb --- /dev/null +++ b/Heart/DataBaseSpace/asyncsqldbwriter.h @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018-2020 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 ASYNCSQLDBWRITER_H +#define ASYNCSQLDBWRITER_H + +#include "sqldbwriter.h" +#include "atomicmetatypes.h" + +namespace NP { + + +/** + * @brief The AsyncSqlDbWriter class some as SqlDBWriter bud run all commnad in main thread + * is thread save db writer. + */ +class AsyncSqlDbWriter :public QObject, public SqlDBWriter +{ + Q_OBJECT +public: + AsyncSqlDbWriter(QObject* ptr = nullptr); + ~AsyncSqlDbWriter(); + // iObjectProvider interface + /** + * @brief saveObject - save object in to database. This implementation work on own thread + * @param saveObject - ptr to object + * @return true if function finished successful + */ + bool saveObject(const DBObject* saveObject) override; + + /** + * @brief saveObject - delete object in to database. This implementation work on own thread + * @param deleteObject - ptr to object + * @return true if function finished successful + */ + bool deleteObject(const DBObject* deleteObject) override; + + /** + * @brief saveObjectWithWait - this is owerload of saveObject with wait results of a database thread. + * @param saveObject - ptr to object + * @return true if function finished successful + */ + bool saveObjectWithWait(const DBObject* saveObject); + + /** + * @brief deleteObjectWithWait - this is owerload of deleteObject with wait results of a database thread. + * @param deleteObject - ptr to object + * @return true if function finished successful + */ + bool deleteObjectWithWait(const DBObject* deleteObject); + + /** + * @brief getAllObjects - this implementation work on own thread and wait results in current thread. + * @param templateObject - template object with request + * @param result - list of objects + * @return true if function finished successful + */ + bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override; + + /** + * @brief initDb - this implementation initialise database in own thread and wait result of initialization on current thread + * @param initDbParams - initialise parameters + * @return true if database initialise successful + */ + bool initDb(const QVariantMap ¶ms) override; + +protected slots: + /** + * @brief handleSaveObject - this method call SaveObject on own thread. + * @param saveObject - object for save + */ + void handleSaveObject(const NP::DBObject* saveObject, + bool *resultOfWork, bool *endOfWork); + + /** + * @brief handleDeleteObject - this method call DeleteObject on own thread. + * @param deleteObject object for delete + */ + void handleDeleteObject(const NP::DBObject* deleteObject, + bool *resultOfWork, bool *endOfWork); + + /** + * @brief the handleGetAllObject - this method call getAllObjects on own thread. + * @param templateObject - the some as in getAllObjects + * @param result - the some as in getAllObjects + * @param resultOfWork - this ptr contains result of invoked of getAllObjects method on own thread + * @param endOfWork - this ptr set true when invocked method is finished + * @param cb - this call back method invoke after getAllObjects method + */ + virtual void handleGetAllObject(const NP::DBObject *templateObject, + QList<const NP::DBObject *> *result, + bool *resultOfWork, bool *endOfWork = nullptr); + + /** + * @brief handleInitDb - this method invoke initDb on own thread + * @param params - input parameters data + * @param resultOfWork - this ptr contains result of invoked of initDb method on own thread + * @param endOfWork - this ptr set true when invocked method is finished + */ + void handleInitDb(const QVariantMap ¶ms, + bool *resultOfWork, bool *endOfWork = nullptr); + +private: + /** + * @brief waitFor - The base wait function. + * @param condition - condition for wait + * @param timeout - maximu time for wait. By default this value equals WAIT_TIME it is 30000 msec. + * @return true if condition is true. + */ + bool waitFor(bool* condition, int timeout = WAIT_TIME) const; + + QThread *_own = nullptr; + +}; + +} +#endif // ASYNCSQLDBWRITER_H diff --git a/Heart/DataBaseSpace/basedefines.h b/Heart/DataBaseSpace/basedefines.h new file mode 100644 index 0000000..251f2f0 --- /dev/null +++ b/Heart/DataBaseSpace/basedefines.h @@ -0,0 +1,19 @@ +#ifndef BASEDEFINES_H +#define BASEDEFINES_H + +namespace NP { + +/** + * @brief The DBOperationResult enum + */ +enum class DBOperationResult { + /// Node do not know about this operaio + Unknown, + /// Node allow this operation and exec it + Allowed, + /// Node forbid this operation. + Forbidden, +}; + +} +#endif // BASEDEFINES_H diff --git a/Heart/DataBaseSpace/baseid.cpp b/Heart/DataBaseSpace/baseid.cpp new file mode 100644 index 0000000..983de18 --- /dev/null +++ b/Heart/DataBaseSpace/baseid.cpp @@ -0,0 +1,75 @@ +#include "baseid.h" +namespace NP { + +BaseId::BaseId() = default; + +BaseId::BaseId(unsigned int val) { + fromRaw(reinterpret_cast<char*>(&val), sizeof (val)); +} + +BaseId::BaseId(const QByteArray &raw) { + fromRaw(raw); +} + +BaseId::BaseId(const QString &base64) { + fromBase64(base64.toLatin1()); +} + +bool BaseId::fromBase64(const QByteArray &base64) { + return fromRaw(QByteArray::fromBase64(base64, QByteArray::Base64UrlEncoding)); +} + +bool BaseId::fromRaw(const QByteArray &raw) { + _data = raw; + return isValid(); +} + +bool BaseId::fromRaw(const char *data, int len) { + _data.clear(); + _data.insert(0, data, len); + return isValid(); +} + +QByteArray BaseId::toBase64() const { + return _data.toBase64(QByteArray::Base64UrlEncoding); +} + +const QByteArray& BaseId::toRaw() const { + return _data; +} + +bool BaseId::isValid() const { + return _data.size(); +} + +void BaseId::clear() { + _data.clear(); +} + +unsigned char BaseId::prefix() const { + if (_data.size()) + return _data[0]; + + return 0; +} + +QDataStream &BaseId::fromStream(QDataStream &stream) { + stream >> _data; + return stream; +} + +QDataStream &BaseId::toStream(QDataStream &stream) const { + stream << _data; + return stream; +} + +bool operator==(const BaseId &left, const BaseId &other) { + return left._data == other._data; +} + + +uint qHash(const NP::BaseId &object) { + return qHash(object.toRaw()); +} +} + diff --git a/Heart/DataBaseSpace/baseid.h b/Heart/DataBaseSpace/baseid.h new file mode 100644 index 0000000..54a9d17 --- /dev/null +++ b/Heart/DataBaseSpace/baseid.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018-2020 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 BaseId_H +#define BaseId_H + +#include <QByteArray> +#include <streambase.h> + +namespace NP { + +/** + * @brief The BaseId class. General class for work with database id. + * Database id is '1byte of prefix + hash (sha256)' from object value. + */ +class NETWORKPROTOCOLSHARED_EXPORT BaseId: public StreamBase +{ +public: + BaseId(); + BaseId(unsigned int val); + + BaseId(const QByteArray& raw); + BaseId(const QString& base64); + + /** + * @brief fromBase64 + * @param base64 + * @return + */ + bool fromBase64(const QByteArray& base64); + + /** + * @brief fromRaw + * @param raw + * @return + */ + bool fromRaw(const QByteArray& raw); + + /** + * @brief fromRaw + * @param raw + * @return + */ + bool fromRaw(const char* data, int len); + + /** + * @brief toBase64 + * @return + */ + QByteArray toBase64() const; + + /** + * @brief toRaw + * @return + */ + const QByteArray& toRaw() const; + + /** + * @brief isValid + * @return true if object is valid + */ + virtual bool isValid() const; + + /** + * @brief clear + * @return + */ + void clear(); + + /** + * @brief prefix - return prefix of id. if id is not valid return 0. + * @return prefix of id + */ + unsigned char prefix() const; + + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + + friend bool operator== (const BaseId& left, const BaseId& other); + +private: + QByteArray _data; +}; + + +uint qHash(const NP::BaseId& object); + +} + + +#endif // BaseId_H diff --git a/Heart/DataBaseSpace/basenodeinfo.cpp b/Heart/DataBaseSpace/basenodeinfo.cpp new file mode 100644 index 0000000..f6c44e6 --- /dev/null +++ b/Heart/DataBaseSpace/basenodeinfo.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018-2020 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 "basenodeinfo.h" +#include "dbaddress.h" +#include <QTcpSocket> +#include <hostaddress.h> + +namespace NP { + + +BaseNodeInfo::BaseNodeInfo(QAbstractSocket *tcp, const HostAddress* address): + AbstractNodeInfo(tcp, address){} + +BaseNodeInfo::~BaseNodeInfo() = default; + +bool BaseNodeInfo::isValid() const { + return AbstractNodeInfo::isValid(); +} + +BaseId BaseNodeInfo::selfId() const { + return _selfId; +} + +void BaseNodeInfo::setSelfId(const BaseId &selfId) { + _selfId = selfId; +} + +bool BaseNodeInfo::confirmData() const { + return AbstractNodeInfo::confirmData(); +} + +} diff --git a/Heart/DataBaseSpace/basenodeinfo.h b/Heart/DataBaseSpace/basenodeinfo.h new file mode 100644 index 0000000..b7ff5c6 --- /dev/null +++ b/Heart/DataBaseSpace/basenodeinfo.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018-2020 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 CONNECTIONINFO_H +#define CONNECTIONINFO_H + +#include "abstractnodeinfo.h" +#include "accesstoken.h" +#include "baseid.h" +#include "heart_global.h" +#include <QByteArray> + +class QAbstractSocket; +namespace NP { + +class DbAddress; + +/** + * @brief The BaseNodeInfo class contaisn list of nodes id of know this node. + */ +class NETWORKPROTOCOLSHARED_EXPORT BaseNodeInfo: public AbstractNodeInfo { + +public: + + /** + * @brief BaseNodeInfo - create node info from the tcp descriptor + * @param tcp - tcp socket dsscriptor + */ + explicit BaseNodeInfo(QAbstractSocket * tcp = nullptr, + const HostAddress* clientAddress = nullptr); + ~BaseNodeInfo() override; + + /** + * @brief isValid + * @return true if node is valid. + */ + bool isValid() const override; + + /** + * @brief selfId - it is id of peer node + * @return + */ + BaseId selfId() const; + + /** + * @brief setSelfId + * @param selfId + */ + void setSelfId(const BaseId &selfId); + + /** + * @brief confirmData - this implementaton check self id of node. + * @return true if node contains valid self id. + */ + bool confirmData() const override; + +protected: + BaseId _selfId; +}; + +} + +#endif // CONNECTIONINFO_H diff --git a/Heart/DataBaseSpace/databasenode.cpp b/Heart/DataBaseSpace/databasenode.cpp new file mode 100644 index 0000000..28c7b9b --- /dev/null +++ b/Heart/DataBaseSpace/databasenode.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (C) 2018-2020 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 "databasenode.h" +#include "abstractnodeinfo.h" +#include "sqldbcache.h" +#include "sqldbwriter.h" +#include "websocketcontroller.h" +#include "asyncsqldbwriter.h" + +#include <badrequest.h> +#include <quasarapp.h> +#include <websocket.h> +#include <websocketsubscriptions.h> +#include <websocketcontroller.h> +#include <QCoreApplication> +#include <qsecretrsa2048.h> +#include <ping.h> +#include <keystorage.h> +#include <basenodeinfo.h> +#include <networkmember.h> +#include <memberpermisionobject.h> + +#define THIS_NODE "this_node_key" +namespace NP { + +DataBaseNode::DataBaseNode(NP::SslMode mode, QObject *ptr): + AbstractNode(mode, ptr) { + + _webSocketWorker = new WebSocketController(this); + +} + +bool DataBaseNode::initSqlDb(QString DBparamsFile, + SqlDBCache *cache, + SqlDBWriter *writer) { + + initDefaultDbObjects(cache, writer); + + QVariantMap params; + + if (DBparamsFile.isEmpty()) { + params = defaultDbParams(); + return _db->init(params); + } + + if (!_db->init(DBparamsFile)) { + return false; + } + + return true; +} + +bool DataBaseNode::isSqlInited() const { + return _db; +} + +bool DataBaseNode::run(const QString &addres, unsigned short port) { + if (!isSqlInited() && !initSqlDb()) { + return false; + } + + return AbstractNode::run(addres, port); +} + +bool DataBaseNode::run(const QString &addres, + unsigned short port, + const QString &localNodeName) { + + if (localNodeName.isEmpty()) + return false; + + _localNodeName = localNodeName; + + if (!isSqlInited() && !initSqlDb()) { + return false; + } + + return AbstractNode::run(addres, port); +} + +void DataBaseNode::stop() { + + AbstractNode::stop(); + + if (db()) { + auto writer = _db->writer(); + delete _db; + _db = nullptr; + delete writer; + + } + +} + +DataBaseNode::~DataBaseNode() { +} + +void DataBaseNode::initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer) { + if (!writer) { + writer = new AsyncSqlDbWriter(); + } + + if (!cache) { + cache = new SqlDBCache(); + } + + cache->setWriter(writer); + _db = cache; + + connect(_db, &SqlDBCache::sigItemChanged, + _webSocketWorker, &WebSocketController::handleItemChanged); +} + + +bool DataBaseNode::welcomeAddress(const HostAddress&) { + return true; +} + +bool DataBaseNode::isBanned(const BaseId &node) const { + NetworkMember member(node); + auto objectFromDataBase = db()->getObject(member); + + return objectFromDataBase->trust() <= 0; +} + +void DataBaseNode::nodeConnected(const HostAddress &node) { + AbstractNode::nodeConnected(node); + welcomeAddress(node); +} + +QString DataBaseNode::dbLocation() const { + if (db() && db()->writer()) { + return db()->writer()->databaseLocation(); + } + + return ""; +} + + +bool DataBaseNode::sendData(AbstractData *resp, + const HostAddress &addere, + const Header *req) { + return AbstractNode::sendData(resp, addere, req); +} + +bool DataBaseNode::sendData(const AbstractData *resp, + const HostAddress &addere, + const Header *req) { + + return AbstractNode::sendData(resp, addere, req); +} + + + +bool DataBaseNode::sendData(AbstractData *resp, + const BaseId &nodeId, + const Header *req) { + + + if (!resp || !resp->prepareToSend()) { + return false; + } + + return sendData(const_cast<const AbstractData*>(resp), nodeId, req); +} + +bool DataBaseNode::sendData(const AbstractData *resp, const BaseId &nodeId, const Header *req) { + auto nodes = connections(); + + for (auto it = nodes.begin(); it != nodes.end(); ++it) { + auto info = dynamic_cast<BaseNodeInfo*>(it.value()); + if (info && info->selfId() == nodeId) { + return sendData(resp, it.key(), req); + } + } + + return false; +} + +void DataBaseNode::badRequest(const HostAddress &address, const Header &req, const QString msg) { + AbstractNode::badRequest(address, req, msg); +} + +void DataBaseNode::badRequest(const BaseId &address, const Header &req, const QString msg) { + + if (!changeTrust(address, REQUEST_ERROR)) { + + QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" + " because trust not changed", + QuasarAppUtils::Error); + + return; + } + + auto bad = BadRequest(msg); + if (!sendData(&bad, address, &req)) { + return; + } + + QuasarAppUtils::Params::log("Bad request sendet to adderess: " + + address.toBase64(), + QuasarAppUtils::Info); +} + +bool DataBaseNode::changeTrust(const HostAddress &id, int diff) { + return AbstractNode::changeTrust(id, diff); +} + +bool DataBaseNode::changeTrust(const BaseId &id, int diff) { + if (!_db) + return false; + + auto client = _db->getObject(NetworkMember{id}); + + if (!client) { + + QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" + " because client == null", + QuasarAppUtils::Error); + return false; + } + + auto clone = client->clone().staticCast<NetworkMember>(); + clone->changeTrust(diff); + + if (!_db->saveObject(clone.data())) { + return false; + } + + return true; +} + +ParserResult DataBaseNode::parsePackage(const Package &pkg, + const AbstractNodeInfo *sender) { + auto parentResult = AbstractNode::parsePackage(pkg, sender); + if (parentResult != ParserResult::NotProcessed) { + return parentResult; + } + + if (H_16<WebSocket>() == pkg.hdr.command) { + WebSocket obj(pkg); + + BaseId requesterId = getSender(sender, &obj); + + if (!obj.isValid()) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + if (!workWithSubscribe(obj, requesterId, *sender)) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + return ParserResult::Processed; + + } else if (H_16<WebSocketSubscriptions>() == pkg.hdr.command) { + WebSocketSubscriptions obj(pkg); + if (!obj.isValid()) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + incomingData(&obj, sender->networkAddress()); + return ParserResult::Processed; + } + + return ParserResult::NotProcessed; +} + +QString DataBaseNode::hashgenerator(const QByteArray &pass) { + return QCryptographicHash::hash( + QCryptographicHash::hash(pass, QCryptographicHash::Sha256) + "QuassarAppSoult", + QCryptographicHash::Sha256); +} + +SqlDBCache *DataBaseNode::db() const { + return _db; +} + +bool DataBaseNode::workWithSubscribe(const WebSocket &rec, + const BaseId &clientOrNodeid, + const AbstractNodeInfo & sender) { + + auto _db = db(); + if (_db) + return false; + + switch (static_cast<WebSocketRequest>(rec.getRequestCmd())) { + + case WebSocketRequest::Subscribe: { + return _webSocketWorker->subscribe(clientOrNodeid, rec.address()); + } + + case WebSocketRequest::Unsubscribe: { + _webSocketWorker->unsubscribe(clientOrNodeid, rec.address()); + return true; + } + + case WebSocketRequest::SubscribeList: { + + WebSocketSubscriptions resp; + resp.setAddresses(_webSocketWorker->list(clientOrNodeid)); + + return sendData(&resp, sender.networkAddress()); + } + + default: break; + } + + return false; +} + +QVariantMap DataBaseNode::defaultDbParams() const { + + return { + {"DBDriver", "QSQLITE"}, + {"DBFilePath", DEFAULT_DB_PATH + "/" + _localNodeName + "/" + _localNodeName + "_" + DEFAULT_DB_NAME}, + {"DBInitFile", DEFAULT_DB_INIT_FILE_PATH} + }; +} + +DBOperationResult NP::DataBaseNode::getObject(const NP::BaseId &requester, + const NP::DBObject &templateObj, + const DBObject** 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 DataBaseNode::getObjects(const BaseId &requester, + const DBObject &templateObj, + QList<const DBObject *> *result) const { + if (!_db && !result) { + return DBOperationResult::Unknown; + } + + if (!_db->getAllObjects(templateObj, *result)) { + return DBOperationResult::Unknown; + } + + for (const auto& obj: *result) { + if (!obj) + return DBOperationResult::Unknown; + + auto permisionResult = checkPermission(requester, obj->dbAddress(), + Permission::Read); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + } + + return DBOperationResult::Allowed; +} + +DBOperationResult DataBaseNode::setObject(const BaseId &requester, + const DBObject *saveObject) { + + if (!_db) { + return DBOperationResult::Unknown; + } + + auto permisionResult = checkPermission(requester, + saveObject->dbAddress(), + Permission::Write); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + + if (!_db->saveObject(saveObject)) { + return DBOperationResult::Unknown; + } + + return DBOperationResult::Allowed; +} + +BaseId DataBaseNode::getSender(const AbstractNodeInfo *connectInfo, const AbstractData *) const { + + auto info = dynamic_cast<const BaseNodeInfo*>(connectInfo); + + if (!info) + return {}; + + return info->selfId(); +} + +DBOperationResult DataBaseNode::checkPermission(const BaseId &requester, + const DbAddress &objectAddress, + const Permission& requarimentPermision) const { + const NetworkMember *member = _db->getObject(NetworkMember{requester}); + if (!member) { + return DBOperationResult::Unknown; + } + + const MemberPermisionObject *permision = + _db->getObject(MemberPermisionObject({requester, objectAddress})); + + if (!permision) { + return DBOperationResult::Unknown; + } + + if (permision->permisions() < requarimentPermision) { + return DBOperationResult::Forbidden; + } + + return DBOperationResult::Allowed; +} + +DBOperationResult DataBaseNode::deleteObject(const BaseId &requester, + const DBObject *dbObject) { + + if (!_db) { + return DBOperationResult::Unknown; + } + + auto permisionResult = checkPermission(requester, + dbObject->dbAddress(), + Permission::Write); + if (permisionResult != DBOperationResult::Allowed) { + return permisionResult; + } + + if (!_db->deleteObject(dbObject)) { + return DBOperationResult::Unknown; + } + + return DBOperationResult::Allowed; +} + +} + diff --git a/Heart/DataBaseSpace/databasenode.h b/Heart/DataBaseSpace/databasenode.h new file mode 100644 index 0000000..a3740f9 --- /dev/null +++ b/Heart/DataBaseSpace/databasenode.h @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2018-2020 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 DATABASENODE_H +#define DATABASENODE_H + +#include "abstractnode.h" +#include <dbobject.h> +#include <hostaddress.h> +#include <permission.h> + + +namespace NP { + +class SqlDBCache; +class SqlDBWriter; +class WebSocket; +class WebSocketController; +class DbAddress; +class BaseId; + + +/** + * @brief The BaseNode class - base inplementation of nodes. This implementation contains methods for work with database and work with data transopt on network. + * BaseNode - is thread save class + */ +class NETWORKPROTOCOLSHARED_EXPORT DataBaseNode : public AbstractNode +{ + Q_OBJECT +public: + + /** + * @brief BaseNode + * @param mode + * @param ptr + */ + DataBaseNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr); + ~DataBaseNode() override; + + /** + * @brief intSqlDb - this function init database of node + * @param DBparamsFile - path to json file with all patarams + * @param cache - new SqlDBCache object + * @param writer - new SqlDBWriter + * @return true if all good + */ + virtual bool initSqlDb( QString DBparamsFile = "", + SqlDBCache * cache = nullptr, + SqlDBWriter* writer = nullptr); + + /** + * @brief isSqlInited + * @return return true if intSqlDb invocked correctly; + */ + bool isSqlInited() const; + + + /** + * @brief run server on address an port + * @param addres - If address is empty then serve weel be listen all addreses of all interfaces + * @param port + * @return recomendet befor invoke this method call the intSqlDb. + * If you skeap a call of intSqlDb method then data base inited with default parameters. + */ + bool run(const QString &addres, unsigned short port) override; + + /** + * @brief run server on address an port with local name of storage of keys + * @param addres - network address of node + * @param port - port of node + * @return true if node is deployed successful + */ + virtual bool run(const QString &addres, unsigned short port, + const QString &localNodeName); + + /** + * @brief stop - this implementation stop work database and push to database all cache data. + */ + void stop() override; + + + + /** + * @brief defaultDbParams + * @return + */ + virtual QVariantMap defaultDbParams() const; + +protected: + + /** + * @brief initDefaultDbObjects create default cache and db writer if pointer is null + * @param cache + * @param writer + */ + void initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer); + + /** + * @brief parsePackage + * @param pkg + * @param sender + * @return + */ + ParserResult parsePackage(const Package &pkg, + const AbstractNodeInfo* sender) override; + + + /** + * @brief sendData - send data to an ip address + * @param resp + * @param addere + * @param req + * @return true if a function finished seccussful + */ + bool sendData(AbstractData *resp, + const HostAddress &addere, + const Header *req = nullptr) override; + + /** + * @brief sendData - send data to an ip address + * @param resp + * @param addere + * @param req + * @return true if a function finished seccussful + */ + bool sendData(const AbstractData *resp, + const HostAddress &addere, + const Header *req = nullptr) override; + + /** + * @brief sendDataToId - send data to node or clientby them id. This implementation prepare object to sending. + * @param resp - responce package + * @param nodeId - id of target node + * @param req - header of request + * @return true if data sendet seccussful + */ + virtual bool sendData(AbstractData *resp, const BaseId &nodeId, + const Header *req = nullptr); + + /** + * @brief sendDataToId - send data to node or clientby them id. + * @param resp - responce package + * @param nodeId - id of target node + * @param req - header of request + * @return true if data sendet seccussful + */ + virtual bool sendData(const AbstractData *resp, const BaseId &nodeId, + const Header *req = nullptr); + /** + * @brief badRequest -send bad request and change trus for ip address + * @param address + * @param req + * @param msg + */ + void badRequest(const HostAddress &address, const Header &req, + const QString msg = "") override; + + /** + * @brief badRequest - send bad request to node with id + * @param address - id of target node or client + * @param req - header of an accepted request. + * @param msg + */ + virtual void badRequest(const BaseId &address, const Header &req, + const QString msg = ""); + + /** + * @brief changeTrust - change trust of ip address + * @param id - ip address of node + * @param diff + */ + bool changeTrust(const HostAddress &id, int diff) override; + + /** + * @brief changeTrust change trus of node with id. + * @param id + * @param diff + * @return true if functin finished seccussful + */ + virtual bool changeTrust(const BaseId &id, int diff); + + /** + * @brief hashgenerator + * @param pass + */ + virtual QString hashgenerator(const QByteArray &pass); + + + /** + * @brief nodeConnected - this implementation call a welcomeAddress method. + * @param node + */ + void nodeConnected(const HostAddress &node) override; + + /** + * @brief db + * @return pinter to data base + */ + SqlDBCache* db() const; + + /** + * @brief workWithSubscribe - this metod work work with subscribe commnads + * @param rec request data + * @param address sendet address + * @return true if data parsed seccusseful + */ + bool workWithSubscribe(const WebSocket &rec, + const BaseId &clientOrNodeid, const AbstractNodeInfo &sender); + + /** + * @brief deleteObject - delete object by address dbObject + * @param requester - reqester. + * @param dbObject + * @return result of operation (allow, forbiden unknown) + */ + DBOperationResult deleteObject(const BaseId &requester, + const DBObject *dbObject); + + /** + * @brief getObject - general method for geting object wth check permisions + * this function check permishen to requested object and set new object to res if access granted. + * @param requester - requser node or client + * @param templateObj - object with request + * @param result - pointer to pointer of result object + * @return operation status + */ + DBOperationResult getObject(const BaseId &requester, + const DBObject &templateObj, + const DBObject **result) const; + + + /** + * @brief getObjects - general object for get object + * this function check permishen to requested object and set new object to res if access granted. + * @param requester - requser node or client + * @param templateObj - object with request + * @param result - pointer to list of pointers with result objects + * @return operation status + */ + DBOperationResult getObjects(const BaseId &requester, + const DBObject &templateObj, + QList<const DBObject *> *result) const; + + /** + * @brief setObject + * @param saveObject + * @param requiredNodeAddere + * @param dbObject + * @return operation status + */ + DBOperationResult setObject(const BaseId &requester, + const DBObject *saveObject); + + /** + * @brief getSender - this method return id of requester. + * @default Base implementation get id from BaseNdoeInfo. + * @param connectInfo - info about connect + * @param requestData - data of request + * @return id of requester member + */ + virtual BaseId getSender(const AbstractNodeInfo *connectInfo, const AbstractData *requestData) const; + + /** + * @brief checkPermision - check permision of requester to objectAddress + * Override this method for your backend + * @param requester - user on node or another object of network + * @param objectAddress - addres to database object + * @param requarimentPermision - needed permision for requester + * @return DBOperationResult::Alowed if permission granted + */ + virtual DBOperationResult checkPermission(const BaseId& requester, + const DbAddress& objectAddress, + const Permission& requarimentPermision) const; + + /** + * @brief dbLocation - return location of database of node. + * @return path to the location of database + */ + QString dbLocation() const; + + /** + * @brief welcomeAddress - this method send to the ip information about yaster self. + * @param ip - host address of the peer node obeject + * @return true if all iformation sendet succesful + */ + virtual bool welcomeAddress(const HostAddress &ip); + + /** + * @brief isBanned - check trust of node, if node trus is lover of 0 return true. + * @param member + * @return true if node is banned + */ + bool isBanned(const BaseId& member) const; +private: + + SqlDBCache *_db = nullptr; + QString _localNodeName; + WebSocketController *_webSocketWorker = nullptr; + + + friend class WebSocketController; +}; + + +} +#endif // DATABASENODE_H diff --git a/Heart/DataBaseSpace/dbaddress.cpp b/Heart/DataBaseSpace/dbaddress.cpp new file mode 100644 index 0000000..bf1e1e6 --- /dev/null +++ b/Heart/DataBaseSpace/dbaddress.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018-2020 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 "dbaddress.h" +#include <QDataStream> +#include <QHash> + + +namespace NP { + +qint64 qHash(const DbAddress &address) { + return qHash(address.id().toRaw() + address.table()); +} + +DbAddress::DbAddress(const QString &table, const BaseId &id) { + this->_table = table; + this->_id = id; +} + +bool operator==(const DbAddress & left, const DbAddress &other) { + return left._table == other._table && left._id == other._id; +} + +QDataStream &DbAddress::fromStream(QDataStream &stream) { + stream >> _id; + stream >> _table; + return stream; +} + +QDataStream &DbAddress::toStream(QDataStream &stream) const { + stream << _id; + stream << _table; + return stream; +} + +QString DbAddress::toString() const { + return QString("DbAddress: id:%0, table:%1"). + arg(QString(_id.toBase64())). + arg(_table); +} + +bool operator!=(const DbAddress &left, const DbAddress &other) { + return !operator==(left, other); +} + +bool DbAddress::isValid() const { + return _id.isValid() && _table.size(); +} + +const QString& DbAddress::table() const { + return _table; +} + +void DbAddress::setTable(const QString &table) { + _table = table; +} + +const BaseId& DbAddress::id() const { + return _id; +} + +void DbAddress::setId(const BaseId &id) { + _id = id; +} + +} diff --git a/Heart/DataBaseSpace/dbaddress.h b/Heart/DataBaseSpace/dbaddress.h new file mode 100644 index 0000000..b5fc917 --- /dev/null +++ b/Heart/DataBaseSpace/dbaddress.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018-2020 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 DBADDRESS_H +#define DBADDRESS_H + +#include "streambase.h" +#include "basedefines.h" +#include "baseid.h" + +namespace NP { + +/** + * @brief The DbAddress class - this is address of data base object + */ +class NETWORKPROTOCOLSHARED_EXPORT DbAddress : public StreamBase { + +public: + + DbAddress() = default; + DbAddress(const QString& table, const BaseId& id); + + QDataStream &fromStream(QDataStream &stream); + QDataStream &toStream(QDataStream &stream) const; + + /** + * @brief toString - return a string implementation fo this object + * @return string of object + */ + QString toString() const; + + friend bool operator== (const DbAddress& left, const DbAddress& other); + friend bool operator!= (const DbAddress& left, const DbAddress& other); + + bool isValid() const; + + const QString& table() const; + void setTable(const QString &table); + + const BaseId &id() const; + void setId(const BaseId &id); + +private: + + QString _table; + BaseId _id; +}; + +qint64 qHash(const DbAddress& address); + +} + + +#endif // DBADDRESS_H diff --git a/Heart/DataBaseSpace/dbaddresskey.cpp b/Heart/DataBaseSpace/dbaddresskey.cpp new file mode 100644 index 0000000..373f563 --- /dev/null +++ b/Heart/DataBaseSpace/dbaddresskey.cpp @@ -0,0 +1,42 @@ +#include "dbaddresskey.h" +namespace NP { + +DbAddressKey::DbAddressKey() { + +} + +DbAddressKey::DbAddressKey(const DbAddress &address): + DbAddress(address) { + +} + +DbAddressKey::DbAddressKey(const QString &address, const BaseId &id): + DbAddress(address, id) { + +} + +unsigned int DbAddressKey::hash() const { + return qHash(*static_cast<const DbAddress*>(this)); +} + +const BaseId &DbAddressKey::id() const { + return DbAddress::id(); +} + +const QString &DbAddressKey::table() const { + return DbAddress::table(); +} + +bool DbAddressKey::equal(const AbstractKey *other) const { + auto otherObject = dynamic_cast<const DbAddressKey*>(other); + + if (!otherObject) + return false; + + return operator==(*static_cast<const DbAddress*>(this), *otherObject); +} + +bool DbAddressKey::isValid() const { + return DbAddress::isValid(); +} +} diff --git a/Heart/DataBaseSpace/dbaddresskey.h b/Heart/DataBaseSpace/dbaddresskey.h new file mode 100644 index 0000000..9d0e0b4 --- /dev/null +++ b/Heart/DataBaseSpace/dbaddresskey.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018-2020 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 DBADDRESSKEY_H +#define DBADDRESSKEY_H +#include "abstractkey.h" +#include "dbaddress.h" + +namespace NP { + +/** + * @brief The DbAddressKey class - key provider for DbAddress + */ +class NETWORKPROTOCOLSHARED_EXPORT DbAddressKey: public DbAddress, public AbstractKey +{ +public: + DbAddressKey(); + DbAddressKey(const DbAddress& address); + DbAddressKey(const QString& address, const BaseId& id); + + unsigned int hash() const override; + + const BaseId &id() const override; + const QString &table() const override; + bool equal(const AbstractKey *other) const override; + + bool isValid() const override; + +}; +} +#endif // DBADDRESSKEY_H diff --git a/Heart/DataBaseSpace/dbcachekey.cpp b/Heart/DataBaseSpace/dbcachekey.cpp new file mode 100644 index 0000000..f1deeee --- /dev/null +++ b/Heart/DataBaseSpace/dbcachekey.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018-2020 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 "dbcachekey.h" + +#include <abstractkey.cpp> +namespace NP { + +DBCacheKey *DBCacheKey::instance() { + static auto ptr = new DBCacheKey(); + return ptr; +} + +QString DBCacheKey::description(uint hash) const { + auto val = value(hash); + + if (!val) + return ""; + + return QString("table:%0 id:%1").arg(val->id().toBase64(), val->table()); +} + +DBCacheKey::DBCacheKey() {} +} + diff --git a/Heart/DataBaseSpace/dbcachekey.h b/Heart/DataBaseSpace/dbcachekey.h new file mode 100644 index 0000000..916197f --- /dev/null +++ b/Heart/DataBaseSpace/dbcachekey.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018-2020 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 DBCACHEKEY_H +#define DBCACHEKEY_H + +#include "baseid.h" + +#include <abstractkey.h> +#include <QHash> +#include <heart_global.h> + +namespace NP { + +/** + * @brief The DBCacheKey class - is database main key value + */ +class NETWORKPROTOCOLSHARED_EXPORT DBCacheKey +{ +public: + + /** + * @brief instance + * @return singleton of object + */ + static DBCacheKey* instance(); + + template <class TYPE = AbstractKey> + /** + * @brief value - return vale from key + * @param key - hash of ke value + * @return value of key + */ + const TYPE* value(uint key) const { + return dynamic_cast<const TYPE*>(_data.value(key, nullptr)); + } + + template <class TYPE> + /** + * @brief key - return hash key and save object into objects table + * @param value - the value of a key objekt + * @return hash of input value + */ + uint key(const TYPE& value) { + auto object = dynamic_cast<const AbstractKey*>(&value); + + if (!object) { + return 0; + } + + uint hash = object->hash(); + if (_data.contains(hash)) { + _data[hash] = new TYPE(value); + } + return hash; + } + + /** + * @brief description - return string description of id + * @param hash + * @return + */ + QString description(uint hash) const; + + +private: + QHash<uint, AbstractKey*> _data; + DBCacheKey(); + +}; + +#define HASH_KEY(X) DBCacheKey::instance()->key(X) +#define VALUE_KEY(X) DBCacheKey::instance()->value(X) +#define DESCRIPTION_KEY(X) DBCacheKey::instance()->description(X) + +} + +#endif // DBCACHEKEY_H diff --git a/Heart/DataBaseSpace/iobjectprovider.cpp b/Heart/DataBaseSpace/iobjectprovider.cpp new file mode 100644 index 0000000..2de298e --- /dev/null +++ b/Heart/DataBaseSpace/iobjectprovider.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018-2020 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 "iobjectprovider.h" + +namespace NP { +iObjectProvider::iObjectProvider() = default; + +iObjectProvider::~iObjectProvider() = default; + +const DBObject *iObjectProvider::getObjectRaw(const DBObject &templateVal) { + + if (!dynamic_cast<const DBObject*>(&templateVal)) { + return nullptr; + } + + QList<const DBObject *> list; + if (!getAllObjects(templateVal, list)) { + return nullptr; + } + + if (list.size() > 1) { + QuasarAppUtils::Params::log("getObject method returned more than one object," + " the first object was selected as the result, all the rest were lost.", + QuasarAppUtils::Warning); + } + + return list.first(); +} + +} diff --git a/Heart/DataBaseSpace/iobjectprovider.h b/Heart/DataBaseSpace/iobjectprovider.h new file mode 100644 index 0000000..43bdd3f --- /dev/null +++ b/Heart/DataBaseSpace/iobjectprovider.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018-2020 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 IOBJECTPROVIDER_H +#define IOBJECTPROVIDER_H +#include "heart_global.h" + +#include <QSharedPointer> +#include <dbobject.h> +#include <quasarapp.h> + +namespace NP { + +class AbstractData; + +class NETWORKPROTOCOLSHARED_EXPORT iObjectProvider +{ +public: + iObjectProvider(); + virtual ~iObjectProvider(); + + /** + * @brief getObject - this method return pointer to DBObject created by select method of template object. + * @param obj - template object with a select db request. + * @return return pointer to DBObject ot nullptr id object not exits. + */ + template<class TYPE> + const TYPE *getObject(const TYPE &templateVal) { + + auto val = getObjectRaw(templateVal); + const TYPE* result = dynamic_cast<const TYPE*>(val); + if (!result && val) { + QuasarAppUtils::Params::log("getObject method returned object with deffirent type of TYPE," + " check getAllObjects merhod", + QuasarAppUtils::Error); + + } + + return result; + } + + /** + * @brief getObjectRaw - return object without test object type + * @note if you want get object with check object type use getObject method. + * @param templateVal - template object with request to database + * @return - return database object pointer (not casted) + */ + const DBObject *getObjectRaw(const DBObject &templateVal); + + /** + * @brief getAllObjects - executable select method of objects and return list of all selected objects + * @param obj - template object with select request. + * @param result - return value, list of selected objects. + * @return true if objects have in db else false. + */ + virtual bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) = 0; + + /** + * @brief saveObject + * @return + */ + virtual bool saveObject(const DBObject* saveObject) = 0; + + /** + * @brief deleteObject + * @return + */ + virtual bool deleteObject(const DBObject* obj) = 0; + +}; + +} +#endif // IOBJECTPROVIDER_H diff --git a/Heart/DataBaseSpace/packages/dbobject.cpp b/Heart/DataBaseSpace/packages/dbobject.cpp new file mode 100644 index 0000000..17dc206 --- /dev/null +++ b/Heart/DataBaseSpace/packages/dbobject.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2018-2020 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 "dbaddresskey.h" +#include "dbcachekey.h" +#include "dbobject.h" +#include <QDataStream> +#include <QDateTime> +#include <QSqlQuery> +#include <QHash> +#include <QSqlRecord> +#include <QVariantMap> +#include <QSharedPointer> + +namespace NP { + +DBObject::DBObject(const QString &tableName) { + clear(); + _dbId.setTable(tableName); +} + +DBObject::~DBObject() { + +} + +QString DBObject::tableName() const { + return _dbId.table(); +} + +PrepareResult DBObject::prepareSelectQuery(QSqlQuery &q) const { + + QString queryString = "SELECT * FROM %0 " + getWhereBlock(); + + queryString = queryString.arg(tableName()); + + if (!q.prepare(queryString)) { + return PrepareResult::Fail; + } + + return PrepareResult::Success; +} + +bool DBObject::fromSqlRecord(const QSqlRecord &q) { + + if (q.contains("id")) { + setId(q.value("id").toString()); + return true; + } + + return false; +} + +bool DBObject::isCached() const { + return true; +} + +bool DBObject::isBundle() const { + return false; +} + +uint DBObject::dbKey() const { + return HASH_KEY(DbAddressKey(_dbId)); +} + +QPair<QString, QString> DBObject::altarnativeKey() const { + return {}; +} + +DbAddress DBObject::dbAddress() const { + return _dbId; +} + +QSharedPointer<DBObject> DBObject::clone() const { + return QSharedPointer<DBObject>(cloneRaw()); +} + +DBObject *DBObject::cloneRaw() const { + auto cloneObject = factory(); + if (!cloneObject->copyFrom(this)) { + return nullptr; + } + + cloneObject->init(); + + return cloneObject; +} + +QString DBObject::toString() const { + return AbstractData::toString() + + QString(" %0").arg(_dbId.toString()); +} + +QString DBObject::getWhereBlock() const { + QString whereBlock = "WHERE "; + + if (getId().isValid()) { + whereBlock += "id='" + getId().toBase64() + "'"; + } else { + auto altKeys = altarnativeKey(); + if (altKeys.first.isEmpty()) { + return {}; + } + whereBlock += altKeys.first + "='" + altKeys.second + "'"; + + } + + return whereBlock; +} + +PrepareResult DBObject::prepareRemoveQuery(QSqlQuery &q) const { + + QString queryString = "DELETE FROM %0 " + getWhereBlock(); + + queryString = queryString.arg(tableName()); + + if (!q.prepare(queryString)) { + return PrepareResult::Fail; + } + + return PrepareResult::Success; +} + +QDataStream &DBObject::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + + stream >> _dbId; + + return stream; +} + +QDataStream &DBObject::toStream(QDataStream &stream) const { + AbstractData::toStream(stream); + + stream << _dbId; + + return stream; +} + +bool DBObject::init() { + if (!AbstractData::init()) + return false; + + if (isBundle()) { + return true; + } + + _dbId.setId(generateId()); + return _dbId.isValid(); +} + +bool DBObject::isValid() const { + return AbstractData::isValid() && _dbId.isValid(); +} + +bool DBObject::copyFrom(const AbstractData * other) { + if (!AbstractData::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const DBObject*>(other); + if (!otherObject) + return false; + + this->_dbId = otherObject->_dbId; + + return true; +} + +BaseId DBObject::getId() const { + return dbAddress().id(); +} + +void DBObject::setId(const BaseId& id) { + _dbId.setId(id); +} + +void DBObject::clear() { + setId({}); +} + +} diff --git a/Heart/DataBaseSpace/packages/dbobject.h b/Heart/DataBaseSpace/packages/dbobject.h new file mode 100644 index 0000000..78c759d --- /dev/null +++ b/Heart/DataBaseSpace/packages/dbobject.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2018-2020 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 DBOBJECT_H +#define DBOBJECT_H +#include <QSqlRecord> +#include <QVariantMap> +#include "abstractdata.h" +#include "heart_global.h" +#include "dbaddress.h" +#include "basedefines.h" +#include "dbcachekey.h" + +class QSqlQuery; + +namespace NP { + +/** + * @brief The PrepareResult enum - result of work prepare sql query + */ +enum class PrepareResult { + /// prepare finished fail. + Fail, + /// prepare finished succussful + Success, + /// prepare disabled for method. Use this case for disable prepare method for object without errors. + Disabled, +}; + +/** + * @brief The DBObject class- main class for work with data base. + */ +class NETWORKPROTOCOLSHARED_EXPORT DBObject : public AbstractData +{ +public: + /** + * @brief DBObject + */ + DBObject(const QString& tableName); + + ~DBObject() override; + + //// AbstractData interface + bool isValid() const override; + + /** + * @brief copyFrom get all data from other + * @arg other - other data package + * @return return true if method finished seccussful + */ + bool copyFrom(const AbstractData * other) override; + + /** + * @brief getId + * @return id of objcet + */ + BaseId getId() const; + + /** + * @brief setId - set new id for db object + * @param id + */ + void setId(const BaseId& id); + + /** + * @brief clear + */ + virtual void clear(); + + /** + * @brief tableName + * @return + */ + QString tableName() const; + + /** + * @brief factory + * @return clone of self object pointer + */ + virtual DBObject* factory() const = 0; + + /** + * @brief prepareSelectQuery - override this metod for get item from database + * this method need to prepare a query for selected data. + * the default implementation generate default select: "select * from [table] where id=[id]". + * If id is empty this implementation use data from altarnativeKey method. + * @param q - query object + * @return true if query is prepared seccussful + */ + virtual PrepareResult prepareSelectQuery(QSqlQuery& q) const; + + /** + * @brief fromSqlRecord- this method need to init this object from executed sqlRecord. + * default implementation get general dbObject information ( id and table name ) + * @note this method weel be invoke for one object. but if isBundle return 'true' then a function fromSqlRecord moust be invoked foreach all elements of list. + * @param q - sql record + * @return true if method finished succesful + */ + virtual bool fromSqlRecord(const QSqlRecord& q); + + /** + * @brief prepareSaveQuery - override this method for save item into database + * this method need to prepare a query for selected data. + * @param q - query of requst + * @return PrepareResult value + */ + virtual PrepareResult prepareSaveQuery(QSqlQuery& q) const = 0 ; + + /** + * @brief prepareRemoveQuery - override this method for remove this item from database. + * this method need to prepare a query for remove this object. + * the default implementatin remove item from id or primaryKey. + * If id is empty this implementation use data from altarnativeKey method. + * @param q - query of requst + * @return PrepareResult value + */ + virtual PrepareResult prepareRemoveQuery(QSqlQuery& q) const; + + /** + * @brief isCached + * @return return true if item in cache. default implementation retun true only + */ + virtual bool isCached() const; + + /** + * @brief isBundle + * If this function return true then SqlDBWriter create only one object after invoked selectquery. + * And if the selectquery function return a list of more 1 elements then a method fromSqlRecord moust be invoked foreach all elements of list. + * @return true if the object is a selection from a set of database object. + */ + virtual bool isBundle() const; + + /** + * @brief dbAddress - unique address of item in database {id:table} + * default implementation + * @return unique key of this object + */ + virtual uint dbKey() const; + + /** + * @brief altarnativeKey - this method need to return a altarnative key:value pair for a select object when a object do not have a database id. + * @default default implementation return empty pair. + * @return pair of altarnative keys. Key : Value. + */ + virtual QPair<QString, QString> altarnativeKey() const; + + /** + * @brief dbAddress + * @return + */ + DbAddress dbAddress() const; + + /** + * @brief clone - this nethod create a new object. The new Object is cone of current object. + * @note If you want to get raw pointer to cone object use a "cloneRaw" method. + * @return return shared pointer to clone of current object + */ + QSharedPointer<DBObject> clone() const; + + /** + * @brief cloneRaw - this method return a raw pointer to clone of this object. + * @warning - clone object don not removed automatically and may result in a memory leak. + * @note for get a shared pointer of clone object use the "clone" method. + * @return retuen raw pointer to cloe of this object. + */ + DBObject* cloneRaw() const; + + /** + * @brief toString - return a string implementation fo this object + * @return string of object + */ + QString toString() const override; + + +protected: + + //// StreamBase interface + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + + /** + * @brief generateId - override this method for all db Objects. + * if create id is impasoble ther retrun not valid id. + * @return retuern Id of database object + */ + virtual BaseId generateId() const = 0; + + /** + * @brief init - init this object, prepare work with database. + * @default - this implementation is create id for object of database. + * If method generateId return not valid id this method return false. + * @return true if object initialized fuccessful else return false. + */ + bool init() override; + +private: + QString getWhereBlock() const; + + DbAddress _dbId; +}; +} + +Q_DECLARE_METATYPE(const NP::DBObject*) +Q_DECLARE_METATYPE(NP::DBObject*) +Q_DECLARE_METATYPE(QList<NP::DBObject *>*); +Q_DECLARE_METATYPE(QList<const NP::DBObject *>*); + +#endif // DBOBJECT_H diff --git a/Heart/DataBaseSpace/packages/memberpermisionobject.cpp b/Heart/DataBaseSpace/packages/memberpermisionobject.cpp new file mode 100644 index 0000000..9a51877 --- /dev/null +++ b/Heart/DataBaseSpace/packages/memberpermisionobject.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018-2020 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 "memberpermisionobject.h" + +#include <QDataStream> +#include <QSqlQuery> +#include <dbcachekey.h> + +namespace NP { + +MemberPermisionObject::MemberPermisionObject(): + DBObject("MemberPermisions") { + +} + +MemberPermisionObject::MemberPermisionObject(const Package &pkg): + MemberPermisionObject() { + fromBytes(pkg.data); + +} + +MemberPermisionObject::MemberPermisionObject(const PermisionData &id): + MemberPermisionObject() { + setKey(id); +} + +bool MemberPermisionObject::isValid() const { + return _key.isValid(); +} + +bool MemberPermisionObject::copyFrom(const AbstractData *other) { + if (!DBObject::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const MemberPermisionObject*>(other); + if (!otherObject) + return false; + + this->_key = otherObject->_key; + this->_permisions = otherObject->_permisions; + + return true; +} + +PrepareResult MemberPermisionObject::prepareSaveQuery(QSqlQuery &q) const { + + if (!isValid()) { + return PrepareResult::Fail; + } + + QString queryString = "INSERT INTO %0(%1) VALUES (%3) " + "ON CONFLICT(MemberPermisionsIndex) DO UPDATE SET %2"; + + queryString = queryString.arg(tableName()); + + queryString = queryString.arg( + "memberId, objectTable", "objectId", "lvl"); + + queryString = queryString.arg("memberId='" + _key.id().toBase64() + "', " + + "objectTable='" + _key.address().table()+ "', " + + "objectId='" + _key.address().id().toBase64() + "', " + + "lvl='" + QString::number(static_cast<int>(_permisions)) + "'"); + QString values; + + values += "'" + _key.id().toBase64() + "', "; + values += "'" + _key.address().table() + "', "; + values += "'" + _key.address().id().toBase64() + "', "; + values += QString::number(static_cast<int>(_permisions)); + + + + queryString = queryString.arg(values); + + if (q.prepare(queryString)) + return PrepareResult::Success; + return PrepareResult::Fail; +} + +PrepareResult MemberPermisionObject::prepareRemoveQuery(QSqlQuery &q) const { + if (!isValid()) { + return PrepareResult::Fail; + } + + QString queryString = "DELETE FROM %0 where memberId='%1' and objectTable='%2' and objectId='%3'"; + queryString = queryString.arg(tableName(), + _key.id().toBase64(), + _key.address().table(), + _key.address().id().toBase64()); + + if (q.prepare(queryString)) + return PrepareResult::Success; + return PrepareResult::Fail; +} + +PrepareResult MemberPermisionObject::prepareSelectQuery(QSqlQuery &q) const { + if (_key.isValid()) { + return PrepareResult::Fail; + } + + QString queryString = "SELECT * FROM %0 WHERE"; + bool fOptionAdded = false; + + if (_key.id().isValid()) { + queryString += "memberId='" + _key.id().toBase64() + "'"; + fOptionAdded = true; + } + + if (_key.address().table().size()) { + if (fOptionAdded) + queryString += " and "; + queryString += "objectTable='" + _key.address().table() + "'"; + fOptionAdded = true; + } + + if (_key.address().id().isValid()) { + if (fOptionAdded) + queryString += " and "; + queryString += "objectId='" + _key.address().id().toBase64() + "'"; + fOptionAdded = true; + } + + queryString = queryString.arg(tableName()); + + if (q.prepare(queryString)) + return PrepareResult::Success; + return PrepareResult::Fail; +} + +DBObject *MemberPermisionObject::factory() const { + return create<MemberPermisionObject>(); +} + +uint MemberPermisionObject::dbKey() const { + return HASH_KEY(_key); +} + +QDataStream &MemberPermisionObject::fromStream(QDataStream &stream) { + + stream >> _key; + stream >> _permisions; + + return stream; +} + +QDataStream &MemberPermisionObject::toStream(QDataStream &stream) const { + stream << _key; + stream << _permisions; + + return stream; +} + +BaseId MemberPermisionObject::generateId() const { + if (!_key.isValid()) + return {}; + + return _key.hash(); +} + +PermisionData MemberPermisionObject::key() const { + return _key; +} + +void MemberPermisionObject::setKey(const PermisionData &key) { + _key = key; +} + +Permission MemberPermisionObject::permisions() const { + return _permisions; +} + +void MemberPermisionObject::setPermisions(const Permission &permisions) { + _permisions = permisions; +} +} diff --git a/Heart/DataBaseSpace/packages/memberpermisionobject.h b/Heart/DataBaseSpace/packages/memberpermisionobject.h new file mode 100644 index 0000000..a8e0ebd --- /dev/null +++ b/Heart/DataBaseSpace/packages/memberpermisionobject.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018-2020 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 NODESPERMISIONOBJECT_H +#define NODESPERMISIONOBJECT_H + +#include "dbcachekey.h" +#include "dbobject.h" +#include "permisiondata.h" +#include "permission.h" + +namespace NP { + +/** + * @brief The NodesPermisionObject class - database object of permisions of node + */ +class NETWORKPROTOCOLSHARED_EXPORT MemberPermisionObject: public DBObject +{ +public: + MemberPermisionObject(); + MemberPermisionObject(const Package& pkg); + MemberPermisionObject(const PermisionData& id); + + // AbstractData interface + bool isValid() const override; + bool copyFrom(const AbstractData *other) override; + + // DBObject interface + PrepareResult prepareSaveQuery(QSqlQuery &q) const override; + PrepareResult prepareRemoveQuery(QSqlQuery &q) const override; + PrepareResult prepareSelectQuery(QSqlQuery &q) const override; + DBObject *factory() const override; + uint dbKey() const override; + + Permission permisions() const; + void setPermisions(const Permission &permisions); + + PermisionData key() const; + void setKey(const PermisionData &key); + +protected: + // StreamBase interface + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + BaseId generateId() const override; + +private: + Permission _permisions; + PermisionData _key; + + +}; +} +#endif // NODESPERMISIONOBJECT_H diff --git a/Heart/DataBaseSpace/packages/networkmember.cpp b/Heart/DataBaseSpace/packages/networkmember.cpp new file mode 100644 index 0000000..74985bb --- /dev/null +++ b/Heart/DataBaseSpace/packages/networkmember.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018-2020 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 "networkmember.h" +#include <quasarapp.h> +#include <QSqlQuery> +#include <QSqlError> +#include <QDataStream> +#include <QCryptographicHash> + + +namespace NP { + +NetworkMember::NetworkMember():DBObject("NetworkMembers") { + +} + +NetworkMember::NetworkMember(const Package &pkg): + NetworkMember() { + fromBytes(pkg.data); +} + +NetworkMember::NetworkMember(const BaseId &id): + NetworkMember() { + setId(id); +} + +DBObject *NetworkMember::factory() const { + return create<NetworkMember>(); +} + +PrepareResult NetworkMember::prepareSaveQuery(QSqlQuery &q) const { + QString queryString = "INSERT INTO %0(%1) VALUES (%3) " + "ON CONFLICT(id) DO UPDATE SET %2"; + queryString = queryString.arg(tableName()); + queryString = queryString.arg("id, authenticationData, trust"); + queryString = queryString.arg("authenticationData=:AuthenticationData, " + "trust=" + QString::number(_trust)); + + QString values; + + values += "'" + getId().toBase64() + "', "; + values += ":AuthenticationData, "; + values += QString::number(_trust); + + queryString = queryString.arg(values); + + if (q.prepare(queryString)) { + q.bindValue(":AuthenticationData", authenticationData()); + return PrepareResult::Success; + } + + + QuasarAppUtils::Params::log("Query:" + queryString, + QuasarAppUtils::Error); + + return PrepareResult::Fail; +} + +bool NetworkMember::fromSqlRecord(const QSqlRecord &q) { + if (!DBObject::fromSqlRecord(q)) { + return false; + } + + setAuthenticationData(q.value("authenticationData").toByteArray()); + setTrust(q.value("trust").toInt()); + + return isValid(); +} + +QByteArray NetworkMember::authenticationData() const { + return _authenticationData; +} + +void NetworkMember::setAuthenticationData(const QByteArray &publickKey) { + _authenticationData = publickKey; +} + +QDataStream &NetworkMember::fromStream(QDataStream &stream) { + DBObject::fromStream(stream); + + stream >> _authenticationData; + stream >> _trust; + + return stream; +} + +QDataStream &NetworkMember::toStream(QDataStream &stream) const { + DBObject::toStream(stream); + + stream << _authenticationData; + stream << _trust; + return stream; +} + +BaseId NetworkMember::generateId() const { + if (authenticationData().isEmpty()) { + return {}; + } + + return QCryptographicHash::hash(authenticationData(), QCryptographicHash::Sha256); +} + +int NetworkMember::trust() const { + return _trust; +} + +void NetworkMember::changeTrust(int diff) { + _trust += diff; +} + +void NetworkMember::setTrust(int trust) { + _trust = trust; +} + +bool NetworkMember::isValid() const { + return DBObject::isValid() && _authenticationData.size(); +} + +bool NetworkMember::copyFrom(const AbstractData * other) { + if (!DBObject::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const NetworkMember*>(other); + if (!otherObject) + return false; + + this->_authenticationData = otherObject->_authenticationData; + this->_trust = otherObject->_trust; + + return true; +} + +QPair<QString, QString> NetworkMember::altarnativeKey() const { + return {"authenticationData", _authenticationData.toBase64(QByteArray::Base64UrlEncoding)}; +} + +} diff --git a/Heart/DataBaseSpace/packages/networkmember.h b/Heart/DataBaseSpace/packages/networkmember.h new file mode 100644 index 0000000..c79181f --- /dev/null +++ b/Heart/DataBaseSpace/packages/networkmember.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018-2020 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 NETWORKMEMBER_H +#define NETWORKMEMBER_H + +#include "dbobject.h" + + +namespace NP { + +/** + * @brief The NodeObject class - database structure of node + */ +class NETWORKPROTOCOLSHARED_EXPORT NetworkMember: public DBObject +{ +public: + NetworkMember(); + NetworkMember(const Package& pkg); + NetworkMember(const BaseId& id); + + // DBObject interface + DBObject *factory() const override; + PrepareResult prepareSaveQuery(QSqlQuery &q) const override; + bool fromSqlRecord(const QSqlRecord &q) override; + + QByteArray authenticationData() const; + void setAuthenticationData(const QByteArray &publickKey); + + // AbstractData interface + bool isValid() const override; + bool copyFrom(const AbstractData *) override; + + QPair<QString, QString> altarnativeKey() const override; + + int trust() const; + void changeTrust(int diff); + void setTrust(int trust); + + +protected: + + // StreamBase interface + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + BaseId generateId() const override; + +private: + QByteArray _authenticationData; + int _trust; +}; +} +#endif // NETWORKMEMBER_H diff --git a/Heart/DataBaseSpace/packages/websocket.cpp b/Heart/DataBaseSpace/packages/websocket.cpp new file mode 100644 index 0000000..44b8ad5 --- /dev/null +++ b/Heart/DataBaseSpace/packages/websocket.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018-2020 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 "websocket.h" + +#include <QDataStream> +#include <QSharedPointer> +namespace NP { + +WebSocket::WebSocket(): AbstractData(){ + +} + +WebSocket::WebSocket(const Package &package): + WebSocket() { + fromBytes(package.data); + +} + +QDataStream &WebSocket::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + stream >> requestCmd; + stream >> _address; + + return stream; +} + +QDataStream &WebSocket::toStream(QDataStream &stream) const { + AbstractData::toStream(stream); + stream << requestCmd; + stream << _address; + + return stream; +} + +DbAddress WebSocket::address() const { + return _address; +} + +void WebSocket::setAddress(const DbAddress &address) { + _address = address; +} + +bool WebSocket::isValid() const { + return requestCmd > static_cast<int>(WebSocketRequest::Invalied) + && AbstractData::isValid(); +} + +} diff --git a/Heart/DataBaseSpace/packages/websocket.h b/Heart/DataBaseSpace/packages/websocket.h new file mode 100644 index 0000000..976e39d --- /dev/null +++ b/Heart/DataBaseSpace/packages/websocket.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2018-2020 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 WEBSOCKET_H +#define WEBSOCKET_H + +#include "dbobject.h" +#include "request.h" + + +namespace NP { + +/** + * @brief The WebSocketRequest enum + */ +enum class WebSocketRequest { + /// Invalied data + Invalied = 0, + /// subscribe to data + Subscribe = 1, + + /// unsubscribe + Unsubscribe = 2, + + /// get list of curennt subscribes + SubscribeList = 3 +}; + +/** + * @brief The WebSocket class - this class contains methods for work with stream data + */ +class NETWORKPROTOCOLSHARED_EXPORT WebSocket: + public AbstractData, public Request +{ +public: + WebSocket(); + WebSocket(const Package& package); + + bool isValid() const override; + + // DBObject interface + DbAddress address() const; + void setAddress(const DbAddress &address); + +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + +private: + DbAddress _address; +}; + +} +#endif // WEBSOCKET_H diff --git a/NetworkProtocol/DataPacakages/websocketsubscriptions.cpp b/Heart/DataBaseSpace/packages/websocketsubscriptions.cpp similarity index 68% rename from NetworkProtocol/DataPacakages/websocketsubscriptions.cpp rename to Heart/DataBaseSpace/packages/websocketsubscriptions.cpp index f77d1a8..84ac995 100644 --- a/NetworkProtocol/DataPacakages/websocketsubscriptions.cpp +++ b/Heart/DataBaseSpace/packages/websocketsubscriptions.cpp @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 "websocketsubscriptions.h" #include <QDataStream> @@ -5,7 +12,7 @@ namespace NP { WebSocketSubscriptions::WebSocketSubscriptions() { - INIT_COMMAND + } @@ -18,21 +25,21 @@ WebSocketSubscriptions::WebSocketSubscriptions(const NP::Package &package): QDataStream &WebSocketSubscriptions::fromStream(QDataStream &stream) { AbstractData::fromStream(stream); + return stream >> _addresses; } QDataStream &WebSocketSubscriptions::toStream(QDataStream &stream) const { AbstractData::toStream(stream); + return stream << _addresses; } -QSet<DbAddress> WebSocketSubscriptions::addresses() const -{ +QSet<DbAddress> WebSocketSubscriptions::addresses() const { return _addresses; } -void WebSocketSubscriptions::setAddresses(const QSet<DbAddress> &addresses) -{ +void WebSocketSubscriptions::setAddresses(const QSet<DbAddress> &addresses) { _addresses = addresses; } diff --git a/NetworkProtocol/DataPacakages/websocketsubscriptions.h b/Heart/DataBaseSpace/packages/websocketsubscriptions.h similarity index 68% rename from NetworkProtocol/DataPacakages/websocketsubscriptions.h rename to Heart/DataBaseSpace/packages/websocketsubscriptions.h index 2079374..9a43281 100644 --- a/NetworkProtocol/DataPacakages/websocketsubscriptions.h +++ b/Heart/DataBaseSpace/packages/websocketsubscriptions.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 WEBSOCKETSUBSCRIPTIONS_H #define WEBSOCKETSUBSCRIPTIONS_H @@ -9,6 +16,9 @@ namespace NP { +/** + * @brief The WebSocketSubscriptions class + */ class NETWORKPROTOCOLSHARED_EXPORT WebSocketSubscriptions: public AbstractData { public: diff --git a/Heart/DataBaseSpace/permisiondata.cpp b/Heart/DataBaseSpace/permisiondata.cpp new file mode 100644 index 0000000..dff732c --- /dev/null +++ b/Heart/DataBaseSpace/permisiondata.cpp @@ -0,0 +1,72 @@ +#include "dbaddress.h" +#include "permisiondata.h" +#include <quasarapp.h> +#include <QDataStream> + +namespace NP { + +bool operator ==(const PermisionData &left, const PermisionData &right) { + return left._id == right._id && left._address == right._address; +} + +PermisionData::PermisionData(const BaseId &subject, const DbAddress &objcet) { + setId(subject); + setAddress(objcet); +} + +unsigned int PermisionData::hash() const { + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + + stream << _id; + stream << _address; + return qHash(data); +} + +const BaseId &PermisionData::id() const { + return _id; +} + +const QString &PermisionData::table() const { + return _address.table(); +} + +bool PermisionData::isValid() const { + return address().isValid() && _id.isValid(); +} + +bool PermisionData::equal(const AbstractKey *other) const { + auto otherObject = dynamic_cast<const PermisionData*>(other); + if (!otherObject) + return false; + + return _address == otherObject->_address && _id == otherObject->_id; +} + +DbAddress PermisionData::address() const { + return _address; +} + +void PermisionData::setAddress(const DbAddress &address) { + _address = address; +} + +QDataStream &PermisionData::fromStream(QDataStream &stream) { + stream >> _id; + stream >> _address; + + return stream; +} + +QDataStream &PermisionData::toStream(QDataStream &stream) const { + stream << _id; + stream << _address; + + return stream; +} + +void PermisionData::setId(const BaseId &Id) { + _id = Id; +} + +} diff --git a/Heart/DataBaseSpace/permisiondata.h b/Heart/DataBaseSpace/permisiondata.h new file mode 100644 index 0000000..9570a0c --- /dev/null +++ b/Heart/DataBaseSpace/permisiondata.h @@ -0,0 +1,57 @@ +#ifndef PERMISIONDATA_H +#define PERMISIONDATA_H + +#include <QString> +#include <abstractkey.h> +#include "dbaddress.h" + +namespace NP { + +/** + * @brief The PermisionData class- this class provide unique key for permison of subject (id) to object (address). + */ +class NETWORKPROTOCOLSHARED_EXPORT PermisionData: public AbstractKey, public StreamBase { + +public: + + PermisionData() = default; + PermisionData(const BaseId& subject, const DbAddress& objcet); + + friend bool operator == (const PermisionData& left, const PermisionData& right); + + /** + * @brief qHash - calc unique key of PermisionData + * @param userPermision + * @return unique key + */ + unsigned int hash() const override; + + + const BaseId & id() const override; + const QString &table() const override; + bool isValid() const override; + bool equal(const AbstractKey *other) const override; + + void setId(const BaseId &Id); + + DbAddress address() const; + void setAddress(const DbAddress &address); + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + +private: + + /// id of user of node + BaseId _id; + + /// table of target object (second part of key) + DbAddress _address; + + +}; + +} +#endif // PERMISIONDATA_H diff --git a/Heart/DataBaseSpace/permission.h b/Heart/DataBaseSpace/permission.h new file mode 100644 index 0000000..1720296 --- /dev/null +++ b/Heart/DataBaseSpace/permission.h @@ -0,0 +1,17 @@ +#ifndef PERMISIONS_H +#define PERMISIONS_H +namespace NP { + +/** + * @brief The Permission enum + * permision to data in database + */ +enum class Permission: unsigned char { + NoPermission = 0x00, + Read = 0x01, + Update = 0x02, + Write = 0x03, +}; + +} +#endif // PERMISIONS_H diff --git a/Heart/DataBaseSpace/sqldbcache.cpp b/Heart/DataBaseSpace/sqldbcache.cpp new file mode 100644 index 0000000..2bf7570 --- /dev/null +++ b/Heart/DataBaseSpace/sqldbcache.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2018-2020 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 "sqldbcache.h" +#include "quasarapp.h" +#include "sqldbwriter.h" +#include "dbaddresskey.h" +#include "permisiondata.h" + +#include <dbobject.h> +#include <asyncsqldbwriter.h> + +#include <QDateTime> +#include <QtConcurrent/QtConcurrent> + + +namespace NP { + +void SqlDBCache::globalUpdateDataBasePrivate(qint64 currentTime) { + + QMutexLocker lock(&_saveLaterMutex); + + for (uint it : _needToSaveCache) { + + auto async = dynamic_cast<AsyncSqlDbWriter*>(_writer); + + if (_writer && _writer->isValid()) { + + auto obj = getFromCache(it); + + if (!obj || !obj->isValid()) { + deleteFromCache(obj); + + QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" + " db object is not valid! key=" + DESCRIPTION_KEY(it) + + " " + obj->toString(), + QuasarAppUtils::VerboseLvl::Error); + continue; + } + + bool saveResult = false; + if (async) + saveResult = async->saveObjectWithWait(obj); + else + saveResult = _writer->saveObject(obj); + + + + if (!saveResult ) { + QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" + " work globalUpdateDataRelease!!! key=" + DESCRIPTION_KEY(it) + + " " + obj->toString(), + QuasarAppUtils::VerboseLvl::Error); + } + } else { + + QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" + " db writer is npt inited! ", + QuasarAppUtils::VerboseLvl::Error); + return; + } + } + + _needToSaveCache.clear(); + + lastUpdateTime = currentTime; +} + +void SqlDBCache::globalUpdateDataBase(SqlDBCasheWriteMode mode) { + qint64 currentTime = QDateTime::currentMSecsSinceEpoch(); + + if (currentTime - lastUpdateTime > updateInterval || + static_cast<bool>(mode & SqlDBCasheWriteMode::Force)) { + + if (static_cast<bool>(mode & SqlDBCasheWriteMode::On_New_Thread)) { + + QtConcurrent::run([currentTime, this](){ + globalUpdateDataBasePrivate(currentTime); + }); + + } else { + globalUpdateDataBasePrivate(currentTime); + } + } +} + +SqlDBCache::SqlDBCache(qint64 updateInterval) { + lastUpdateTime = QDateTime::currentMSecsSinceEpoch(); + this->updateInterval = updateInterval; +} + +SqlDBCache::~SqlDBCache() { + globalUpdateDataBase(SqlDBCasheWriteMode::Force); +} + +SqlDBWriter *SqlDBCache::writer() const { + return _writer; +} + +void SqlDBCache::setWriter(SqlDBWriter *writer) { + _writer = writer; +} + +bool SqlDBCache::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) { + + DBObject* obj = getFromCache(templateObject.dbKey()); + if(obj) { + result.push_back(obj); + return true; + } + + if (_writer && _writer->isValid()) { + if (!_writer->getAllObjects(templateObject, result)) { + return false; + } + + for (auto object: result) { + if (object->isCached() && !saveToCache(object)) { + QuasarAppUtils::Params::log("Selected object from database can not be saved into database cache. " + + object->toString(), + QuasarAppUtils::Warning); + } + } + + return true; + } + + return false; +} + +bool SqlDBCache::saveObject(const DBObject *saveObject) { + + if (!saveObject || !saveObject->isValid()) { + return false; + } + + saveToCache(saveObject); + + if (getMode() == SqlDBCasheWriteMode::Force) { + if (_writer && _writer->isValid()) { + if (!_writer->saveObject(saveObject)) { + return false; + } + + return true; + } + } else { + _needToSaveCache.insert(saveObject->dbKey()); + globalUpdateDataBase(_mode); + } + + return true; + +} + +bool SqlDBCache::deleteObject(const DBObject *delObj) { + + if (!delObj) + return false; + + deleteFromCache(delObj); + + if (_writer && _writer->isValid()) { + return _writer->deleteObject(delObj); + } + + return false; + +} + +bool SqlDBCache::init(const QString &initDbParams) { + + if (!_writer) { + return false; + } + + return _writer->initDb(initDbParams); +} + +bool SqlDBCache::init(const QVariantMap ¶ms) { + + if (!_writer) { + return false; + } + + return _writer->initDb(params); +} + +void SqlDBCache::deleteFromCache(const DBObject *delObj) { + if (!delObj) + return; + + _cacheMutex.lock(); + _cache.remove(delObj->dbKey()); + _cacheMutex.unlock(); +} + +bool SqlDBCache::saveToCache(const DBObject *obj) { + if (!obj) + return false; + + QMutexLocker lock(&_cacheMutex); + + auto existsObject = _cache.value(obj->dbKey(), nullptr); + if (!existsObject) { + + _cache[obj->dbKey()] = obj->cloneRaw(); + + } else if (existsObject->cmd() != obj->cmd()) { + + delete existsObject; + _cache[obj->dbKey()] = obj->cloneRaw(); + + } else { + + if (!existsObject->copyFrom(obj)) { + return false; + } + + } + + emit sigItemChanged(obj); + + return true; + +} + +DBObject* SqlDBCache::getFromCache(uint objKey) { + + QMutexLocker locker(&_cacheMutex); + + return _cache.value(objKey, nullptr); +} + +SqlDBCasheWriteMode SqlDBCache::getMode() const { + return _mode; +} + +void SqlDBCache::setMode(const SqlDBCasheWriteMode &mode) { + _mode = mode; +} + +qint64 SqlDBCache::getUpdateInterval() const { + return updateInterval; +} + +void SqlDBCache::setUpdateInterval(const qint64 &value) { + updateInterval = value; +} + +} diff --git a/NetworkProtocol/sqldbcache.h b/Heart/DataBaseSpace/sqldbcache.h similarity index 62% rename from NetworkProtocol/sqldbcache.h rename to Heart/DataBaseSpace/sqldbcache.h index 41a3fc6..073c520 100644 --- a/NetworkProtocol/sqldbcache.h +++ b/Heart/DataBaseSpace/sqldbcache.h @@ -1,19 +1,29 @@ +/* + * Copyright (C) 2018-2020 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 SQLDBCASHE_H #define SQLDBCASHE_H +#include "dbcachekey.h" #include "iobjectprovider.h" #include <QMap> #include <QHash> #include <QSet> #include <QVariantMap> -#include <networkprotocol.h> #include <QMutex> +#include "config.h" +#include "basedefines.h" namespace NP { class SqlDBWriter; class DBObject; +class DbAddress; enum class SqlDBCasheWriteMode: int { Default = 0x0, @@ -37,19 +47,18 @@ public: * @brief writer * @return weak pointer to writer */ - WP<SqlDBWriter> writer() const; + SqlDBWriter* writer() const; /** * @brief setWriter * @param writer */ - void setWriter(const WP<SqlDBWriter> &writer); + void setWriter(SqlDBWriter* writer); - bool getObject(SP<DBObject> &obj) override; - SP<DBObject> &getObjectFromCache(const QString& table, int id); + bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override; - bool saveObject(const WP<AbstractData> &saveObject) override; - bool deleteObject(const WP<AbstractData>& delObj) override; + bool saveObject(const DBObject* saveObject) override; + bool deleteObject(const DBObject* delObj) override; /** * @brief getUpdateInterval of SqlDBCasheWriteMode::Default mode @@ -83,14 +92,20 @@ protected: * @param id in table of object * @return true if all good */ - virtual void deleteFromCache(const QString &table, int id); + virtual void deleteFromCache(const DBObject *delObj); /** * @brief saveToCache * @param obj */ - virtual void saveToCache(const WP<AbstractData> &obj); + virtual bool saveToCache(const DBObject *obj); + /** + * @brief getFromCache - get database objcet from cache. + * @param objKey + * @return object from cache. if object with objKey not exits return nullptr + */ + virtual DBObject* getFromCache(uint objKey); /** * @brief getMode @@ -104,24 +119,35 @@ protected: */ void setMode(const SqlDBCasheWriteMode &mode); - QMutex _saveLaterMutex; + /** + * @brief globalUpdateDataBasePrivate + * @param currentTime + */ + virtual void globalUpdateDataBasePrivate(qint64 currentTime); + + /** + * @brief globalUpdateDataBase + * @param mode + */ + virtual void globalUpdateDataBase(SqlDBCasheWriteMode mode = SqlDBCasheWriteMode::Default); + + SqlDBWriter* _writer = nullptr; private: qint64 lastUpdateTime = 0; qint64 updateInterval = DEFAULT_UPDATE_INTERVAL; + QMutex _saveLaterMutex; + QMutex _cacheMutex; SqlDBCasheWriteMode _mode; - SP<SqlDBWriter> _writer = nullptr; + QHash<uint, DBObject*> _cache; + QSet<uint> _needToSaveCache; - QHash<QString, QHash <int, SP<DBObject>>> _cache; - QHash<QString, QList<int>> _needToSaveCache; - virtual void globalUpdateDataBasePrivate(qint64 currentTime); - virtual void globalUpdateDataBase(SqlDBCasheWriteMode mode = SqlDBCasheWriteMode::Default); signals: - void sigItemChanged(const WP<AbstractData> &obj); + void sigItemChanged(const DBObject *obj); }; diff --git a/NetworkProtocol/sqldbwriter.cpp b/Heart/DataBaseSpace/sqldbwriter.cpp similarity index 56% rename from NetworkProtocol/sqldbwriter.cpp rename to Heart/DataBaseSpace/sqldbwriter.cpp index 04bf989..7255196 100644 --- a/NetworkProtocol/sqldbwriter.cpp +++ b/Heart/DataBaseSpace/sqldbwriter.cpp @@ -1,5 +1,10 @@ -#include "dbobjectsfactory.h" -#include "dbtablebase.h" +/* + * Copyright (C) 2018-2020 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 "sqldbwriter.h" #include <QRegularExpression> @@ -8,12 +13,13 @@ #include <QDebug> #include <QSqlError> #include <quasarapp.h> -#include <networkprotocol.h> #include <QJsonDocument> #include <QJsonObject> #include <QHash> #include <dbobject.h> #include <QSqlRecord> +#include <QStandardPaths> +#include <QCoreApplication> namespace NP { @@ -115,7 +121,6 @@ QVariantMap SqlDBWriter::defaultInitPararm() const { QVariantMap params; params["DBDriver"] = "QSQLITE"; params["DBFile"] = DEFAULT_DB_PATH; - return params; } @@ -191,45 +196,139 @@ bool SqlDBWriter::isValid() const { return db.isValid() && db.isOpen() && initSuccessful; } -bool SqlDBWriter::getObject(SP<DBObject>& obj) { - return selectQuery(obj); +bool SqlDBWriter::getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) { + return selectQuery(templateObject, result); } -bool SqlDBWriter::saveObject(const WP<AbstractData> &saveObject) { - return saveQuery(saveObject); +bool SqlDBWriter::saveObject(const DBObject* ptr) { + return saveQuery(ptr); } -bool SqlDBWriter::deleteObject(const WP<AbstractData> &deleteObject) { - return deleteQuery(deleteObject); +bool SqlDBWriter::deleteObject(const DBObject* ptr) { + return deleteQuery(ptr); +} + +QString SqlDBWriter::databaseLocation() const { + return db.databaseName(); } SqlDBWriter::~SqlDBWriter() { + db.close(); } -bool SqlDBWriter::saveQuery(const WP<AbstractData>& ptr) const { +bool SqlDBWriter::saveQuery(const DBObject* ptr) const { + if (!ptr) + return false; QSqlQuery q(db); - auto obj = ptr.toStrongRef().dynamicCast<DBObject>(); - if (obj.isNull()) + auto prepare = [ptr](QSqlQuery&q) { + return ptr->prepareSaveQuery(q); + }; + + auto cb = [](){return true;}; + + return workWithQuery(q, prepare, cb); +} + +bool SqlDBWriter::selectQuery(const DBObject& requestObject, QList<const DBObject *> &result) { + + QSqlQuery q(db); + auto prepare = [&requestObject](QSqlQuery&q) { + return requestObject.prepareSelectQuery(q); + }; + + auto cb = [&q, &requestObject, &result]() -> bool { + + if (requestObject.isBundle()) { + auto newObject = requestObject.factory(); + + if (!newObject) + return false; + + while (q.next()) { + if (!newObject->fromSqlRecord(q.record())) { + QuasarAppUtils::Params::log("Init sql object error.", + QuasarAppUtils::Error); + return false; + } + } + + result.push_back(newObject); + + } else { + while (q.next()) { + auto newObject = requestObject.factory(); + + if (!newObject) + return false; + + if (!newObject->fromSqlRecord(q.record())) { + QuasarAppUtils::Params::log("Init sql object error.", + QuasarAppUtils::Error); + return false; + } + result.push_back(newObject); + } + } + + return result.size(); + }; + + return workWithQuery(q, prepare, cb); +} + +bool SqlDBWriter::deleteQuery(const DBObject *deleteObject) const { + if (!deleteObject) return false; - return obj->save(q); + QSqlQuery q(db); + + auto prepare = [deleteObject](QSqlQuery&q) { + return deleteObject->prepareRemoveQuery(q); + }; + + auto cb = []() -> bool { + return true; + }; + + return workWithQuery(q, prepare, cb); } -bool SqlDBWriter::selectQuery(const SP<DBObject>& obj) { - if (obj.isNull()) +bool SqlDBWriter::workWithQuery(QSqlQuery &q, + const std::function< PrepareResult (QSqlQuery &)> &prepareFunc, + const std::function<bool ()> &cb) const { + + switch (prepareFunc(q)) { + case PrepareResult::Success: { + + if (!q.exec()) { + + QuasarAppUtils::Params::log("exec sql error: " + q.lastError().text(), + QuasarAppUtils::Error); + + return false; + } + + return cb(); + } + case PrepareResult::Disabled: { + QuasarAppUtils::Params::log("call disabled operator! ", + QuasarAppUtils::Warning); + return true; + } + + case PrepareResult::Fail: { + QuasarAppUtils::Params::log("prepare sql error: " + q.lastError().text(), + QuasarAppUtils::Error); + return false; + } - QSqlQuery query(db); - return obj->select(query); -} + } -bool SqlDBWriter::deleteQuery(const WP<AbstractData> &deleteObject) const { - QSqlQuery query(db); - auto ref = deleteObject.toStrongRef().dynamicCast<DBObject>(); + return false; - return ref->remove(query); } } diff --git a/NetworkProtocol/sqldbwriter.h b/Heart/DataBaseSpace/sqldbwriter.h similarity index 54% rename from NetworkProtocol/sqldbwriter.h rename to Heart/DataBaseSpace/sqldbwriter.h index d31c126..e164b09 100644 --- a/NetworkProtocol/sqldbwriter.h +++ b/Heart/DataBaseSpace/sqldbwriter.h @@ -1,3 +1,10 @@ +/* + * Copyright (C) 2018-2020 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 SQLDBWRITER_H #define SQLDBWRITER_H @@ -5,32 +12,74 @@ #include <QSqlDatabase> #include <QDir> #include <QSqlQuery> -#include "networkprotocol_global.h" +#include "heart_global.h" #include "config.h" -#include "dbtablebase.h" #include "iobjectprovider.h" #include <QVariant> +#include <QCoreApplication> +#include <dbobject.h> -class QSqlQuery; class QSqlDatabase; -class QSqlQuery; class PlayerDBData; namespace NP { -class DBObject; -class AbstractData; /** * @brief The SqlDBWriter class */ class NETWORKPROTOCOLSHARED_EXPORT SqlDBWriter : public iObjectProvider { -private: +public: + SqlDBWriter(); - bool exec(QSqlQuery *sq, const QString &sqlFile); + /** + * @brief initDb + * @param path + * @return + */ + virtual bool initDb(const QString &initDbParams = DEFAULT_DB_PATH); - bool initSuccessful = false; - QVariantMap _config; + /** + * @brief initDb + * @param path + * @return + */ + virtual bool initDb(const QVariantMap ¶ms); + + /** + * @brief isValid + * @return + */ + virtual bool isValid() const; + + /** + * @brief getAllObjects - executable select method of objects and return list of all selected objects + * @param obj - template object with select request. + * @param result - return value, list of selected objects. + * @return true if objects have in db else false. + */ + bool getAllObjects(const DBObject &templateObject, QList<const DBObject *> &result) override; + + /** + * @brief saveObject + * @return + */ + bool saveObject(const NP::DBObject *ptr) override; + + /** + * @brief deleteObject + * @return + */ + bool deleteObject(const NP::DBObject *ptr) override; + + /** + * @brief databaseLocation - return location of database. + * if it is sqllite then return path to db file else return database name. + * @return path or name of database. + */ + QString databaseLocation() const; + + virtual ~SqlDBWriter() override; protected: @@ -73,12 +122,13 @@ protected: virtual QVariantMap defaultInitPararm() const; QSqlDatabase db; - QHash<QString, DbTableBase> _dbStruct; - // 0 - table name - // 1 - headers of update values - // 2 - update values - virtual bool saveQuery(const WP<AbstractData> &ptr) const; + /** + * @brief saveQuery - exec save query of object + * @param ptr + * @return true if function finished seccussful + */ + virtual bool saveQuery(const NP::DBObject *ptr) const; /** * @brief selectQuery generate select query to database from parameters @@ -88,56 +138,30 @@ protected: * @param val - compare value * @return true if all goodelse false */ - virtual bool selectQuery(const SP<DBObject> &obj); + virtual bool selectQuery(const DBObject &requestObject, QList<const DBObject *> &result); - virtual bool deleteQuery(const WP<AbstractData> &deleteObject) const; + virtual bool deleteQuery(const NP::DBObject *deleteObject) const; -public: - SqlDBWriter(); + +private: /** - * @brief initDb - * @param path - * @return + * @brief workWithQuery - this base function for all prepareQuery functions. + * steps work : call prepareFunc, call exec , call cb. + * @param q - query object with a request + * @param prepareFunc - function with pripare data for query + * @param cb - call after success exec and prepare steps + * @return true if all steps finished successful */ - virtual bool initDb(const QString &initDbParams = DEFAULT_DB_PATH); + bool workWithQuery(QSqlQuery &q, + const std::function< PrepareResult (QSqlQuery &)> &prepareFunc, + const std::function<bool()>& cb) const; - /** - * @brief initDb - * @param path - * @return - */ - virtual bool initDb(const QVariantMap ¶ms); + bool exec(QSqlQuery *sq, const QString &sqlFile); - /** - * @brief isValid - * @return - */ - virtual bool isValid() const; + bool initSuccessful = false; + QVariantMap _config; - /** - * @brief getObject - * @return - */ - bool getObject(SP<DBObject> &obj) override; - - /** - * @brief saveObject - * @return - */ - bool saveObject(const WP<AbstractData> &saveObject) override; - - /** - * @brief deleteObject - * @return - */ - bool deleteObject(const WP<AbstractData> &deleteObject) override; - - virtual ~SqlDBWriter() override; - - - QHash<QString, SP<DbTableBase> > getDbStruct() const; - void setDbStruct(const QHash<QString, SP<DbTableBase> > &dbStruct); }; } diff --git a/Heart/DataBaseSpace/websocketcontroller.cpp b/Heart/DataBaseSpace/websocketcontroller.cpp new file mode 100644 index 0000000..dc4f1bd --- /dev/null +++ b/Heart/DataBaseSpace/websocketcontroller.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018-2020 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 "databasenode.h" +#include "abstractnodeinfo.h" +#include "websocketcontroller.h" +#include <quasarapp.h> +#include <permission.h> + +namespace NP { + + +WebSocketController::WebSocketController(DataBaseNode *node) { + _node = node; + assert(_node); +} + +bool WebSocketController::subscribe(const BaseId& subscriber, + const DbAddress &item) { + + _subscribsMutex.lock(); + _subscribs[item].insert(subscriber); + _subscribsMutex.unlock(); + + _itemsMutex.lock(); + _items[subscriber].insert(item); + _itemsMutex.unlock(); + + return true; +} + +void WebSocketController::unsubscribe(const BaseId &subscriber, + const DbAddress& item) { + _subscribsMutex.lock(); + _subscribs[item].remove(subscriber); + _subscribsMutex.unlock(); + + _itemsMutex.lock(); + _items[subscriber].remove(item); + _itemsMutex.unlock(); + +} + +const QSet<DbAddress> &WebSocketController::list(const BaseId &subscriber) { + QMutexLocker locker(&_itemsMutex); + return _items[subscriber]; +} + +void WebSocketController::handleItemChanged(const DBObject *item) { + auto obj = dynamic_cast<const DBObject*>(item); + if (obj) + return; + + QMutexLocker locker(&_subscribsMutex); + + foreachSubscribers(item, _subscribs.value(obj->dbAddress())); +} + +void WebSocketController::foreachSubscribers(const DBObject *item, + const QSet<BaseId> &subscribersList) { + + for (const auto &subscriber : subscribersList) { + bool fAllowed = _node->checkPermission(subscriber, item->dbAddress(), Permission::Read) == + DBOperationResult::Allowed; + + if (fAllowed && !_node->sendData(item, subscriber)) { + QuasarAppUtils::Params::log("Send update failed for " + subscriber.toBase64(), + QuasarAppUtils::Warning); + } + + if (!fAllowed) { + QuasarAppUtils::Params::log(QString("Internal Error. Member:%0 not have permission to object %1"). + arg(QString(subscriber.toBase64())).arg(item->toString()), + QuasarAppUtils::Error); + } + } +} +} diff --git a/Heart/DataBaseSpace/websocketcontroller.h b/Heart/DataBaseSpace/websocketcontroller.h new file mode 100644 index 0000000..9040350 --- /dev/null +++ b/Heart/DataBaseSpace/websocketcontroller.h @@ -0,0 +1,59 @@ + +/* + * Copyright (C) 2018-2020 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 WEBSOCKETCONTROLLER_H +#define WEBSOCKETCONTROLLER_H + +#include <QHash> +#include <QSharedPointer> +#include <dbobject.h> +#include <baseid.h> +#include <QMutex> + +namespace NP { + +class AbstractNodeInfo; +class DataBaseNode; + +/** + * @brief The WebSocketController class - manage subscribe + */ +class NETWORKPROTOCOLSHARED_EXPORT WebSocketController : public QObject +{ + Q_OBJECT + +public: + WebSocketController(DataBaseNode *node); + bool subscribe(const BaseId &subscriber, + const DbAddress &item); + + void unsubscribe(const BaseId &subscriber, + const DbAddress &item); + + const QSet<DbAddress> &list(const BaseId& subscriber); + +public slots: + void handleItemChanged(const DBObject *item); + +private: + void foreachSubscribers(const DBObject *item, + const QSet<BaseId> &subscribersList); + + /// subscribers it is nodes or clients + QHash<DbAddress, QSet<BaseId>> _subscribs; + QHash<BaseId, QSet<DbAddress>> _items; + + QMutex _subscribsMutex; + QMutex _itemsMutex; + + DataBaseNode *_node = nullptr; + +}; + +} +#endif // WEBSOCKETCONTROLLER_H diff --git a/Heart/NetworkSpace/consensus.cpp b/Heart/NetworkSpace/consensus.cpp new file mode 100644 index 0000000..29b0d41 --- /dev/null +++ b/Heart/NetworkSpace/consensus.cpp @@ -0,0 +1,11 @@ +#include "consensus.h" + +namespace NP { + +const QStringList Consensus::Nodes = { + "QuasarApp.ddns.net" +}; + +const short Consensus::networkPort = 8211; + +} diff --git a/Heart/NetworkSpace/consensus.h b/Heart/NetworkSpace/consensus.h new file mode 100644 index 0000000..baef1e9 --- /dev/null +++ b/Heart/NetworkSpace/consensus.h @@ -0,0 +1,26 @@ +#ifndef CONSENSUS_H +#define CONSENSUS_H + +#include "heart_global.h" +#include <QStringList> + +namespace NP { + +/** + * @brief The Consensus namespace - a bundle of general rules constants for behavior of nodes network. + */ +namespace Consensus { + /** + * @brief Nodes - list of main nodes of network + */ + extern const QStringList Nodes; + + /** + * @brief networkPort - sync network port + */ + extern const short networkPort; + +}; + +} +#endif // CONSENSUS_Hs diff --git a/Heart/NetworkSpace/networknode.cpp b/Heart/NetworkSpace/networknode.cpp new file mode 100644 index 0000000..648408f --- /dev/null +++ b/Heart/NetworkSpace/networknode.cpp @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2018-2020 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 "networknode.h" +#include "basenodeinfo.h" +#include "sqldbcache.h" +#include "sqldbwriter.h" +#include "websocketcontroller.h" +#include "badnoderequest.h" +#include "sign.h" +#include "asyncsqldbwriter.h" +#include "router.h" + +#include <badrequest.h> +#include <quasarapp.h> +#include <transportdata.h> +#include <websocket.h> +#include <websocketsubscriptions.h> +#include <websocketcontroller.h> +#include <QCoreApplication> +#include <qsecretrsa2048.h> +#include <ping.h> +#include <keystorage.h> +#include <knowaddresses.h> +#include <longping.h> +#include <networkrequest.h> +#include <networkmember.h> +#include <networknodeinfo.h> +#include <nodeobject.h> + + +#define THIS_NODE "this_node_key" +namespace NP { + +NetworkNode::NetworkNode(NP::SslMode mode, QObject *ptr): + DataBaseNode(mode, ptr) { + + _nodeKeys = new KeyStorage(new QSecretRSA2048()); + _router = new Router(); + +} + +bool NetworkNode::run(const QString &addres, unsigned short port) { + if (!DataBaseNode::run(addres, port)) { + return false; + } + + _nodeKeys->initDefaultStorageLocation(); + _nodeKeys->start(); + + return true; +} + +bool NetworkNode::run(const QString &addres, + unsigned short port, + const QString &localNodeName) { + + if (!DataBaseNode::run(addres, port, localNodeName)) { + return false; + } + + _nodeKeys->initDefaultStorageLocation(localNodeName); + _nodeKeys->start(); + + return true; +} + +void NetworkNode::stop() { + DataBaseNode::stop(); + +} + +NetworkNode::~NetworkNode() { + delete _nodeKeys; + delete _router; +} + +BaseId NetworkNode::nodeId() const { + + auto keys = _nodeKeys->getNextPair(THIS_NODE); + return QCryptographicHash::hash(keys.publicKey(), QCryptographicHash::Sha256); +} + +bool NetworkNode::checkSignOfRequest(const AbstractData *request) { + auto object = dynamic_cast<const Sign*>(request); + auto dbObject = dynamic_cast<const SenderData*>(request); + + if (!(object && dbObject)) { + return false; + } + + auto node = db()->getObject(NetworkMember{dbObject->senderID()}); + return _nodeKeys->check(_nodeKeys->concatSign(object->dataForSigned(), + object->sign()), node->authenticationData()); +} + +NodeObject NetworkNode::thisNode() const { + NodeObject res; + auto keys = _nodeKeys->getNextPair(THIS_NODE); + + res.setAuthenticationData(keys.publicKey()); + res.setTrust(0); + + res.prepareToSend(); + + return res; +} + +QSet<BaseId> NetworkNode::myKnowAddresses() const { + QSet<BaseId> res; + + for (const AbstractNodeInfo *i : connections()) { + auto info = dynamic_cast<const BaseNodeInfo*>(i); + if (info && info->selfId().isValid()) { + res += info->selfId(); + } + } + + return res; +} + +bool NetworkNode::welcomeAddress(const HostAddress& ip) { + NodeObject self = thisNode(); + + if (!sendData(&self, ip)) { + return false; + } + + if (connections().size()) { + + auto knowAddresses = myKnowAddresses(); + if (knowAddresses.size()) { + KnowAddresses addressesData; + addressesData.setKnowAddresses(knowAddresses); + + if (!sendData(&addressesData, ip)) { + return false; + } + } + } + + return true; + +} + +void NetworkNode::nodeConnected(const HostAddress &node) { + DataBaseNode::nodeConnected(node); + + welcomeAddress(node); + +} + +void NetworkNode::nodeConfirmend(const HostAddress &node) { + DataBaseNode::nodeConfirmend(node); + + auto nodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(node)); + if (!nodeInfo) { + return; + } + + _connectionsMutex.lock(); + NetworkNodeInfo* oldNodeInfo = _connections.value(nodeInfo->selfId(), nullptr); + _connectionsMutex.unlock(); + + if (oldNodeInfo) { + removeNode(node); + return; + } + + _connectionsMutex.lock(); + _connections.insert(nodeInfo->selfId(), nodeInfo); + + _connectionsMutex.unlock(); + +} + +void NetworkNode::nodeDisconnected(const HostAddress &node) { + AbstractNode::nodeDisconnected(node); + + auto nodeInfo = dynamic_cast<BaseNodeInfo*>(getInfoPtr(node)); + if (!nodeInfo) { + return; + } + + _connectionsMutex.lock(); + _connections.remove(nodeInfo->selfId()); + _connectionsMutex.unlock(); +} + +void NetworkNode::incomingData(AbstractData *, const BaseId &) {} + +QString NetworkNode::keyStorageLocation() const { + return _nodeKeys->storageLocation(); +} + +ParserResult NetworkNode::parsePackage(const Package &pkg, + const AbstractNodeInfo *sender) { + auto parentResult = AbstractNode::parsePackage(pkg, sender); + if (parentResult != ParserResult::NotProcessed) { + return parentResult; + } + + auto baseSender = dynamic_cast<const BaseNodeInfo*>(sender); + if (!baseSender) { + QuasarAppUtils::Params::log("Sender is not basenode info!", + QuasarAppUtils::Error); + return ParserResult::Error; + } + + if (H_16<BadNodeRequest>() == pkg.hdr.command) { + BadNodeRequest cmd(pkg); + + incomingData(&cmd, baseSender->selfId()); + emit requestError(cmd.err()); + + return ParserResult::Processed; + + } else if (H_16<TransportData>() == pkg.hdr.command) { + TransportData cmd(pkg); + return workWithTransportData(&cmd, sender, pkg); + + + } else if (H_16<NodeObject>() == pkg.hdr.command) { + NodeObject obj(pkg); + if (!obj.isValid()) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + if (!workWithNodeObjectData(obj, sender)) { + badRequest(obj.senderID(), pkg.hdr); + return ParserResult::Error; + } + + return ParserResult::Processed; + } else if (H_16<KnowAddresses>() == pkg.hdr.command) { + KnowAddresses obj(pkg); + if (!obj.isValid()) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + if (!workWithKnowAddresses(obj, sender)) { + badRequest(sender->networkAddress(), pkg.hdr); + return ParserResult::Error; + } + + return ParserResult::Processed; + } else if (H_16<LongPing>() == pkg.hdr.command) { + LongPing cmd(pkg); + + if (!cmd.ansver()) { + cmd.setAnsver(true); + sendData(&cmd, cmd.senderID(), &pkg.hdr); + } + + incomingData(&cmd, baseSender->selfId()); + return ParserResult::Processed; + } else if (H_16<NetworkRequest>() == pkg.hdr.command) { + NetworkRequest cmd(pkg); + + if (!cmd.isValid()) { + badRequest(baseSender->selfId(), pkg.hdr); + return ParserResult::Error; + } + + workWithNetworkRequest(&cmd, baseSender); + return ParserResult::Processed; + } + + return ParserResult::NotProcessed; +} + +bool NetworkNode::workWithNodeObjectData(NodeObject &node, + const AbstractNodeInfo* nodeInfo) { + + if (!db()) { + return false; + } + + auto localObjec = db()->getObject(node); + + if (localObjec) { + node.setTrust(std::min(node.trust(), localObjec->trust())); + } else { + node.setTrust(0); + } + + if (!db()->saveObject(&node)) { + return false; + }; + + auto peerNodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(nodeInfo->networkAddress())); + if (!peerNodeInfo) + return false; + + peerNodeInfo->setSelfId(node.getId()); + + return true; +} + +bool NetworkNode::workWithKnowAddresses(const KnowAddresses &obj, + const AbstractNodeInfo *nodeInfo) { + + auto peerNodeInfo = dynamic_cast<NetworkNodeInfo*>(getInfoPtr(nodeInfo->networkAddress())); + if (!peerNodeInfo) + return false; + + peerNodeInfo->addKnowAddresses(obj.knowAddresses()); + + return true; +} + +ParserResult NetworkNode::workWithTransportData(AbstractData *transportData, + const AbstractNodeInfo* sender, + const Package& pkg) { + + // convert transoprt pakcage + auto cmd = dynamic_cast<TransportData*>(transportData); + + if (!cmd) + return ParserResult::Error; + + // ignore processed packages + if (_router->isProcessed(cmd->packageId())) + return ParserResult::Processed; + + // check distanation + if (cmd->targetAddress() == nodeId()) { + + // inversion route and update route to sender + _router->updateRoute(cmd->senderID(), + {cmd->route().rbegin(), cmd->route().rend()}); + + return parsePackage(cmd->data(), sender); + } + + bool fRouteIsValid = false; + + // find route if transport command do not have own route. + if (!cmd->isHaveRoute() && _router->contains(cmd->targetAddress())) { + auto route = _router->getRoute(cmd->targetAddress()); + + auto cmdRute = cmd->route(); + + cmdRute.push_back(address()); + cmdRute.append(route); + + cmd->setRoute(cmdRute); + } + + // check exists route + if (cmd->isHaveRoute()) { + + // if package have a route then remove all nodes from sender to this node from route and update route + if (!sender) + return ParserResult::Error; + + cmd->strip(sender->networkAddress(), address()); + + // send this package to first available node of knownnodes route nodes + auto it = cmd->route().rbegin(); + while (it != cmd->route().rend() && !sendData(cmd, *it, &pkg.hdr)) { + it++; + } + + fRouteIsValid = it != cmd->route().rend(); + + } else { + // if command not have a route or route is not completed then add this node to end route + cmd->addNodeToRoute(address()); + } + + // save route for sender node from this node + auto routeFromSenderToHere = cmd->route(); + int index = routeFromSenderToHere.indexOf(address()); + + if (index < 0) { + QuasarAppUtils::Params::log("own node no findet on route.", + QuasarAppUtils::Error); + } + + routeFromSenderToHere.erase(routeFromSenderToHere.begin(), routeFromSenderToHere.begin() + index); + // inversion route and update route to sender + _router->updateRoute(cmd->senderID(), + {routeFromSenderToHere.rbegin(), routeFromSenderToHere.rend()}); + + // remove invalid route nodes and fix exists route. + if (!fRouteIsValid) { + cmd->setRoute(routeFromSenderToHere); + cmd->completeRoute(false); + + // send bodcast if route is invalid + if (!sendData(cmd, cmd->targetAddress(), &pkg.hdr)) { + return ParserResult::Error; + } + } + + _router->addProcesedPackage(cmd->packageId()); + return ParserResult::Processed; + +} + +ParserResult NetworkNode::workWithNetworkRequest(AbstractData *networkRequest, + const AbstractNodeInfo *sender) { + // convert transoprt pakcage + auto cmd = dynamic_cast<NetworkRequest*>(networkRequest); + + if (!cmd) + return ParserResult::Error; + + if (cmd->isComplete()) { + if (cmd->askedNodes().contains(nodeId())) { + return parsePackage(cmd->dataResponce(), sender); + } + + return ParserResult::Processed; + } + + return parsePackage(cmd->dataRequest(), sender); +} + +void NetworkNode::incomingData(AbstractData *pkg, const HostAddress &sender) { + AbstractNode::incomingData(pkg, sender); +} + +AbstractNodeInfo *NetworkNode::createNodeInfo(QAbstractSocket *socket, + const HostAddress* clientAddress) const { + return new NetworkNodeInfo(socket, clientAddress); +} + +bool NetworkNode::sendData(const AbstractData *resp, const BaseId &nodeId, const Header *req) { + auto nodes = connections(); + + for (auto it = nodes.begin(); it != nodes.end(); ++it) { + auto info = dynamic_cast<NetworkNodeInfo*>(it.value()); + if (info && info->isKnowAddress(nodeId)) { + return sendData(resp, it.key(), req); + } + } + + auto brodcast = [this, &nodes, req](const AbstractData *data){ + bool result = false; + for (auto it = nodes.begin(); it != nodes.end(); ++it) { + result = result || sendData(data, it.key(), req); + } + + return result; + }; + + + if (resp->cmd() != H_16<TransportData>()) { + TransportData data(address()); + data.setTargetAddress(nodeId); + if (!data.setData(*resp)) { + return false; + } + + data.setRoute(_router->getRoute(nodeId)); + data.setSenderID(this->nodeId()); + data.prepareToSend(); + + return brodcast(&data); + } + + return brodcast(resp); +} + +bool NetworkNode::sendData(AbstractData *resp, const BaseId &nodeId, const Header *req) { + return DataBaseNode::sendData(resp, nodeId, req); +} + +bool NetworkNode::sendData(const AbstractData *resp, const HostAddress &nodeId, const Header *req) { + return DataBaseNode::sendData(resp, nodeId, req); +} + +bool NetworkNode::sendData(AbstractData *resp, const HostAddress &nodeId, const Header *req) { + return DataBaseNode::sendData(resp, nodeId, req); +} + +bool NetworkNode::ping(const BaseId &id) { + LongPing cmd(nodeId()); + return sendData(&cmd, id); +} + +} + diff --git a/Heart/NetworkSpace/networknode.h b/Heart/NetworkSpace/networknode.h new file mode 100644 index 0000000..dd5edd3 --- /dev/null +++ b/Heart/NetworkSpace/networknode.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2018-2020 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 NETWORKNODE_H +#define NETWORKNODE_H + +#include <databasenode.h> +#include <dbobject.h> +#include <hostaddress.h> +#include <nodeobject.h> + + +namespace NP { + +class NetworkMember; +class MemberPermisionObject; +class KnowAddresses; +class KeyStorage; +class Router; +class NetworkNodeInfo; + +/** + * @brief The BaseNode class - base inplementation of nodes. This implementation contains methods for work with database and work with data transopt on network. + * BaseNode - is thread save class + */ +class NETWORKPROTOCOLSHARED_EXPORT NetworkNode : public DataBaseNode +{ + Q_OBJECT +public: + + /** + * @brief BaseNode + * @param mode + * @param ptr + */ + NetworkNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr); + ~NetworkNode() override; + + /** + * @brief run server on address an port + * @param addres - If address is empty then serve weel be listen all addreses of all interfaces + * @param port + * @return recomendet befor invoke this method call the intSqlDb. + * If you skeap a call of intSqlDb method then data base inited with default parameters. + */ + bool run(const QString &addres, unsigned short port) override; + + /** + * @brief run server on address an port with local name of storage of keys + * @param addres - network address of node + * @param port - port of node + * @return true if node is deployed successful + */ + bool run(const QString &addres, unsigned short port, + const QString &localNodeName) override; + + /** + * @brief stop - this implementation stop work database and push to database all cache data. + */ + void stop() override; + + /** + * @brief ping - ping node by node id + * @param address + * @return + */ + bool ping( const BaseId& id); + + /** + * @brief nodeId + * @return + */ + BaseId nodeId() const; + +protected: + + /** + * @brief sendDataToId - send data to node or clientby them id. + * @param resp - responce package + * @param nodeId - id of target node + * @param req - header of request + * @return true if data sendet seccussful + */ + bool sendData(const AbstractData *resp, const BaseId &nodeId, + const Header *req = nullptr) override; + + bool sendData(AbstractData *resp, const BaseId &nodeId, + const Header *req = nullptr) override; + bool sendData(const AbstractData *resp, const HostAddress &nodeId, + const Header *req = nullptr) override; + bool sendData(AbstractData *resp, const HostAddress &nodeId, + const Header *req = nullptr) override; + + /** + * @brief initDefaultDbObjects create default cache and db writer if pointer is null + * @param cache + * @param writer + */ + void initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer); + + /** + * @brief parsePackage + * @param pkg + * @param sender + * @return + */ + ParserResult parsePackage(const Package &pkg, + const AbstractNodeInfo* sender) override; + + /** + * @brief createNodeInfo - this method create a new node from socket. override this mehod if you want to create a own clasess of nodes. + * @param socket + * @return pointer to new node info + */ + AbstractNodeInfo* createNodeInfo(QAbstractSocket *socket, const HostAddress *clientAddress) const override; + + /** + * @brief savePermision - this method save a new changes in to permisions table. + * Befor save new data node can be validate new data with consensus. + * @param permision - data of new permision + * @return true if new cghanges saved successful. + */ + bool savePermision(const NodeObject &node, const MemberPermisionObject& permision); + /** + * @brief checkSignOfRequest + * @param request - package + * @return true if request signed. + */ + virtual bool checkSignOfRequest(const AbstractData *request); + + /** + * @brief thisNode + * @return This node object value. + */ + NodeObject thisNode() const; + + /** + * @brief myKnowAddresses + * @return set of know addresses + */ + QSet<BaseId> myKnowAddresses() const; + + /** + * @brief welcomeAddress - this method send to the ip information about yaster self. + * @param ip - host address of the peer node obeject + * @return true if all iformation sendet succesful + */ + bool welcomeAddress(const HostAddress &ip) override; + + /** + * @brief connectionRegistered - this impletation send incomming node welcom message with information about yaster self. + * @param info incominng node info. + */ + void nodeConnected(const HostAddress& node) override; + + /** + * @brief nodeConfirmend - this implementation test nodes to double connections + * @param mode + */ + void nodeConfirmend(const HostAddress& sender) override; + + /** + * @brief nodeDisconnected - this implementation remove nodes info from connection cache + * @param sender + */ + void nodeDisconnected(const HostAddress& node) override; + + /** + * @brief incomingData - this signal invoked when node get command or ansver + * @param pkg - received package + * @param sender - sender of the package + * @note override this method for get a signals. + */ + virtual void incomingData(AbstractData* pkg, + const BaseId& sender); + + /** + * @brief keyStorageLocation - return location of storagge of keys. + * @return path to the location of keys storage + */ + QString keyStorageLocation() const; + +private: + + /** + * @brief workWithNodeObjectData - this method working with received node object data. + * @param node + * @param nodeInfo + * @return true if function finished successful + */ + bool workWithNodeObjectData(NodeObject &node, const AbstractNodeInfo *nodeInfo); + + /** + * @brief workWithKnowAddresses + * @param node + * @param nodeInfo + * @return + */ + bool workWithKnowAddresses(const KnowAddresses &obj, const AbstractNodeInfo *nodeInfo); + + /** + * @brief workWithTransportData + * @param transportData + * @param sender + * @param pkg + * @return + */ + ParserResult workWithTransportData(AbstractData* transportData, const AbstractNodeInfo *sender, const Package &pkg); + + /** + * @brief workWithNetworkRequest + * @param networkRequest + * @param sender + * @param pkg + * @return + */ + ParserResult workWithNetworkRequest(AbstractData* networkRequest, const AbstractNodeInfo *sender); + + + /** + * @brief optimizeRoute - this method reduces the size of the route by removing unnecessary nodes. + * @param node + * @param rawRoute + * @return + */ + bool optimizeRoute(const BaseId& node, + const HostAddress& currentNodeAddress, const AbstractNodeInfo *sender, + QList<HostAddress> rawRoute); + + /** + * @brief incomingData - this implementation move old incoming method into private section + * becouse base node work with BaseID addresses. + * @warning Do not call this implementation on this class, + * use the ncomingData(AbstractData* pkg, const HostAddress& sender) implementation. + */ + void incomingData(AbstractData* pkg, + const HostAddress& sender) override final; + + + KeyStorage *_nodeKeys = nullptr; + + Router *_router = nullptr; + + QHash<BaseId, NetworkNodeInfo*> _connections; + + mutable QMutex _connectionsMutex; + +}; + + +} +#endif // NETWORKNODE_H diff --git a/Heart/NetworkSpace/networknodeinfo.cpp b/Heart/NetworkSpace/networknodeinfo.cpp new file mode 100644 index 0000000..7be1158 --- /dev/null +++ b/Heart/NetworkSpace/networknodeinfo.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018-2020 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 "networknodeinfo.h" +#include "dbaddress.h" +#include <QTcpSocket> +#include <hostaddress.h> + +namespace NP { + + +NetworkNodeInfo::NetworkNodeInfo(QAbstractSocket *tcp, const HostAddress* address): + BaseNodeInfo(tcp, address){} + +NetworkNodeInfo::~NetworkNodeInfo() = default; + +bool NetworkNodeInfo::isValid() const { + return BaseNodeInfo::isValid(); +} + +bool NetworkNodeInfo::isKnowAddress(const BaseId &address) const { + return _knowAddresses.contains(address); +} + +void NetworkNodeInfo::setSelfId(const BaseId &selfId) { + BaseNodeInfo::setSelfId(selfId); + _knowAddresses.insert(_selfId); +} + +void NetworkNodeInfo::addKnowAddresses(const QSet<BaseId> &newAddressses) { + _knowAddresses += newAddressses; +} + +bool NetworkNodeInfo::confirmData() const { + return BaseNodeInfo::confirmData() && _selfId.isValid(); +} + +} diff --git a/Heart/NetworkSpace/networknodeinfo.h b/Heart/NetworkSpace/networknodeinfo.h new file mode 100644 index 0000000..b66112c --- /dev/null +++ b/Heart/NetworkSpace/networknodeinfo.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018-2020 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 NETWORKCONNECTIONINFO_H +#define NETWORKCONNECTIONINFO_H + +#include "basenodeinfo.h" +#include "accesstoken.h" +#include "baseid.h" +#include "heart_global.h" +#include <QByteArray> + +class QAbstractSocket; +namespace NP { + +class DbAddress; + +/** + * @brief The BaseNodeInfo class contaisn list of nodes id of know this node. + */ +class NETWORKPROTOCOLSHARED_EXPORT NetworkNodeInfo: public BaseNodeInfo { + +public: + + /** + * @brief NetworkNodeInfo - create node info from the tcp descriptor + * @param tcp - tcp socket dsscriptor + */ + explicit NetworkNodeInfo(QAbstractSocket * tcp = nullptr, + const HostAddress* clientAddress = nullptr); + ~NetworkNodeInfo() override; + + /** + * @brief isValid + * @return true if node is valid. + */ + bool isValid() const override; + + /** + * @brief isKnowAddress + * @param address + * @return + */ + bool isKnowAddress(const BaseId& address) const; + + /** + * @brief setSelfId + * @param selfId + */ + void setSelfId(const BaseId &selfId); + + /** + * @brief addKnowAddresses + */ + void addKnowAddresses(const QSet<BaseId> &newAddressses); + + /** + * @brief confirmData - this implementaton check self id of node. + * @return true if node contains valid self id. + */ + bool confirmData() const override; + +protected: + QSet<BaseId> _knowAddresses; +}; + +} + +#endif // NETWORKCONNECTIONINFO_H diff --git a/Heart/NetworkSpace/packages/badnoderequest.cpp b/Heart/NetworkSpace/packages/badnoderequest.cpp new file mode 100644 index 0000000..b85ba75 --- /dev/null +++ b/Heart/NetworkSpace/packages/badnoderequest.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018-2020 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 "badnoderequest.h" +namespace NP { + +BadNodeRequest::BadNodeRequest() { + +} + +BadNodeRequest::BadNodeRequest(const QString &err):BadRequest(err) { + +} + +BadNodeRequest::BadNodeRequest(const Package &package): BadRequest(package) { + +} + +bool BadNodeRequest::isValid() const { + return BadRequest::isValid() && senderID().isValid(); +} + +bool BadNodeRequest::copyFrom(const AbstractData * other) { + if (!BadRequest::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const BadNodeRequest*>(other); + if (!otherObject) + return false; + + setSenderID(otherObject->senderID()); + return true; +} + +QDataStream &BadNodeRequest::fromStream(QDataStream &stream) { + BadRequest::fromStream(stream); + + BaseId senderNode; + stream >> senderNode; + setSenderID(senderNode); + + return stream; +} + +QDataStream &BadNodeRequest::toStream(QDataStream &stream) const { + BadRequest::toStream(stream); + stream << senderID(); + + return stream; +} +} diff --git a/Heart/NetworkSpace/packages/badnoderequest.h b/Heart/NetworkSpace/packages/badnoderequest.h new file mode 100644 index 0000000..f0b0fae --- /dev/null +++ b/Heart/NetworkSpace/packages/badnoderequest.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2018-2020 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 BADNODEREQUEST_H +#define BADNODEREQUEST_H + +#include "senderdata.h" + +#include <badrequest.h> + +namespace NP { + +/** + * @brief The BadNodeRequest class - bad request command for bae node level + */ +class NETWORKPROTOCOLSHARED_EXPORT BadNodeRequest: public BadRequest, public SenderData +{ +public: + explicit BadNodeRequest(); + explicit BadNodeRequest(const QString & err = ""); + explicit BadNodeRequest(const Package& package); + + // AbstractData interface + bool isValid() const; + bool copyFrom(const AbstractData *); + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream); + QDataStream &toStream(QDataStream &stream) const; +}; +} +#endif // BADNODEREQUEST_H diff --git a/Heart/NetworkSpace/packages/knowaddresses.cpp b/Heart/NetworkSpace/packages/knowaddresses.cpp new file mode 100644 index 0000000..cc78236 --- /dev/null +++ b/Heart/NetworkSpace/packages/knowaddresses.cpp @@ -0,0 +1,57 @@ +#include "knowaddresses.h" + +#include <QDataStream> + +namespace NP { + +KnowAddresses::KnowAddresses() { + +} + +KnowAddresses::KnowAddresses(const Package &pkg) { + fromBytes(pkg.toBytes()); + +} + +bool KnowAddresses::isValid() const { + return AbstractData::isValid(); +} + +bool KnowAddresses::copyFrom(const AbstractData * other) { + if (!AbstractData::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const KnowAddresses*>(other); + if (!otherObject) + return false; + + this->_knowAddresses = otherObject->_knowAddresses; + + return true; +} + +QDataStream &KnowAddresses::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + + stream >> _knowAddresses; + + return stream; +} + +QDataStream &KnowAddresses::toStream(QDataStream &stream) const { + AbstractData::toStream(stream); + + stream << _knowAddresses; + + return stream; +} + +QSet<BaseId> KnowAddresses::knowAddresses() const { + return _knowAddresses; +} + +void KnowAddresses::setKnowAddresses(const QSet<BaseId> &knowAddresses) { + _knowAddresses = knowAddresses; +} + +} diff --git a/Heart/NetworkSpace/packages/knowaddresses.h b/Heart/NetworkSpace/packages/knowaddresses.h new file mode 100644 index 0000000..a4c8e59 --- /dev/null +++ b/Heart/NetworkSpace/packages/knowaddresses.h @@ -0,0 +1,36 @@ +#ifndef KNOWADDRESSES_H +#define KNOWADDRESSES_H + +#include <QSet> +#include <abstractdata.h> +#include <baseid.h> + +namespace NP { + +/** + * @brief The KnowAddresses class - this class is package for send the list of know addresses of node to other node object. + */ +class NETWORKPROTOCOLSHARED_EXPORT KnowAddresses: public AbstractData +{ +public: + KnowAddresses(); + KnowAddresses(const Package &pkg); + + // AbstractData interface + bool isValid() const override; + bool copyFrom(const AbstractData *) override; + + QSet<BaseId> knowAddresses() const; + void setKnowAddresses(const QSet<BaseId> &knowAddresses); + + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + +private: + QSet<BaseId> _knowAddresses; +}; +} +#endif // KNOWADDRESSES_H diff --git a/Heart/NetworkSpace/packages/longping.cpp b/Heart/NetworkSpace/packages/longping.cpp new file mode 100644 index 0000000..37931a2 --- /dev/null +++ b/Heart/NetworkSpace/packages/longping.cpp @@ -0,0 +1,42 @@ +#include "longping.h" + +namespace NP { + +LongPing::LongPing(const BaseId& sender) { + + setSenderID(sender); +} + +LongPing::LongPing(const Package &from) { + fromBytes(from.data); +} + +bool LongPing::isValid() const { + return Ping::isValid() && _senderID.isValid(); +} + +bool LongPing::copyFrom(const AbstractData * other) { + if (!Ping::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const LongPing*>(other); + if (!otherObject) + return false; + + this->_senderID = otherObject->_senderID; + return true; +} + +QDataStream &NP::LongPing::fromStream(QDataStream &stream) { + Ping::fromStream(stream); + stream >> _senderID; + return stream; +} + +QDataStream &LongPing::toStream(QDataStream &stream) const { + Ping::toStream(stream); + stream << _senderID; + return stream; +} + +} diff --git a/Heart/NetworkSpace/packages/longping.h b/Heart/NetworkSpace/packages/longping.h new file mode 100644 index 0000000..bbd8db8 --- /dev/null +++ b/Heart/NetworkSpace/packages/longping.h @@ -0,0 +1,29 @@ +#ifndef LONGPING_H +#define LONGPING_H + +#include "ping.h" +#include <senderdata.h> + +namespace NP { + +/** + * @brief The LongPing class - test class for big network with return addresse + */ +class NETWORKPROTOCOLSHARED_EXPORT LongPing: public Ping, public SenderData +{ +public: + LongPing(const BaseId &sender); + LongPing(const Package& from); + + // AbstractData interface + bool isValid() const override; + bool copyFrom(const AbstractData *) override; + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + +}; +} +#endif // LONGPING_H diff --git a/Heart/NetworkSpace/packages/networkrequest.cpp b/Heart/NetworkSpace/packages/networkrequest.cpp new file mode 100644 index 0000000..0563c40 --- /dev/null +++ b/Heart/NetworkSpace/packages/networkrequest.cpp @@ -0,0 +1,88 @@ +#include "networkrequest.h" + +#include <QDataStream> +namespace NP { + +NetworkRequest::NetworkRequest() { + +} + +NetworkRequest::NetworkRequest(const Package &package): + NetworkRequest() { + + fromBytes(package.data); +} + +bool NetworkRequest::isValid() const { + return AbstractData::isValid() && _askedNodes.size() && _dataRequest.isValid(); +} + +bool NetworkRequest::copyFrom(const AbstractData * other) { + if (!AbstractData::copyFrom(other)) + return false; + + auto otherObject = dynamic_cast<const NetworkRequest*>(other); + if (!otherObject) + return false; + + this->_dataRequest = otherObject->_dataRequest; + this->_askedNodes = otherObject->_askedNodes; + this->_dataResponce = otherObject->_dataResponce; + + return true; +} + +Package NetworkRequest::dataRequest() const { + return _dataRequest; +} + +void NetworkRequest::setDataRequest(const Package &data) { + _dataRequest = data; +} + +Package NetworkRequest::dataResponce() const { + return _dataResponce; +} + +void NetworkRequest::setDataResponce(const Package &data) { + _dataResponce = data; +} + +bool NetworkRequest::isComplete() const { + return _dataResponce.isValid(); +} + +void NetworkRequest::addNodeRequiringData(const BaseId &node) { + _askedNodes.insert(node); +} + +QDataStream &NetworkRequest::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + + stream >> _dataRequest; + stream >> _askedNodes; + stream >> _dataResponce; + return stream; + +} + +QDataStream &NetworkRequest::toStream(QDataStream &stream) const { + AbstractData::toStream(stream); + + stream << _dataRequest; + stream << _askedNodes; + stream << _dataResponce; + + return stream; +} + +QSet<BaseId> NetworkRequest::askedNodes() const { + return _askedNodes; +} + +void NetworkRequest::removeNodeFromAskedList(const BaseId &node) { + _askedNodes.remove(node); +} + + +} diff --git a/Heart/NetworkSpace/packages/networkrequest.h b/Heart/NetworkSpace/packages/networkrequest.h new file mode 100644 index 0000000..23b5d88 --- /dev/null +++ b/Heart/NetworkSpace/packages/networkrequest.h @@ -0,0 +1,98 @@ +#ifndef NETWORKREQUEST_H +#define NETWORKREQUEST_H + +#include <QSet> +#include <abstractdata.h> +#include <baseid.h> + + +namespace NP { + +/** + * @brief The NetworkRequest class - this is pakcage wraper for sending requests to network. + * this packages generated when current node can not process a request from client node. + * This request moving by network while do not get a ansver. + * The Ansver (or Responce) it is package with all needed data for processing of a request. + */ +class NETWORKPROTOCOLSHARED_EXPORT NetworkRequest: public AbstractData +{ +public: + explicit NetworkRequest(); + explicit NetworkRequest(const Package& package); + + // AbstractData interface + /** + * @brief isValid chck this package + * @return true if package is valid + */ + bool isValid() const override; + + /** + * @brief copyFrom - create a copy of this pacakge + * @return + */ + bool copyFrom(const AbstractData *) override; + + /** + * @brief dataRequest - this is package of not processed reqest. + * @return Package of request + */ + Package dataRequest() const; + + /** + * @brief setDataRequest - set Data of Reqest Package. + * @param data new pakcage. + */ + void setDataRequest(const Package &data); + + /** + * @brief dataResponce - this is package of responce of request. + * The Responce package contains all needed data for procesing a request. + * @return pakage of Responce + */ + Package dataResponce() const; + + /** + * @brief setDataResponce - set Data of Responce package. + * @note If this package contains a responce of request then package is completed. + * @param data - is Responce pacakge + */ + void setDataResponce(const Package &data); + + /** + * @brief isComplete - return complete status. If this package contains a responce of request then package is completed. + * @return true if package is complete. + */ + bool isComplete() const; + + /** + * @brief addNodeRequiringData - add a node to the list of nodes that need a responce of the request + * @param node - id of node + */ + void addNodeRequiringData(const BaseId& node); + + /** + * @brief askedNodes - return list of nodes that need a responce of the request + * @return list of nodes id. + */ + QSet<BaseId> askedNodes() const; + + /** + * @brief removeNodeFromAskedList - remove a node from list of nodes that need a responce of the request. + * Invoke this method when the node will get a responce. + * @param node + */ + void removeNodeFromAskedList(const BaseId& node); + +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + +private: + Package _dataRequest; + QSet<BaseId> _askedNodes; + Package _dataResponce; + +}; +} +#endif // NETWORKREQUEST_H diff --git a/Heart/NetworkSpace/packages/nodeobject.cpp b/Heart/NetworkSpace/packages/nodeobject.cpp new file mode 100644 index 0000000..77121bd --- /dev/null +++ b/Heart/NetworkSpace/packages/nodeobject.cpp @@ -0,0 +1,33 @@ +#include "nodeobject.h" +namespace NP { + +NodeObject::NodeObject() { + +} + +NodeObject::NodeObject(const Package &pkg): + NetworkMember(pkg) { + +} + +QDataStream &NodeObject::fromStream(QDataStream &stream) { + + NetworkMember::fromStream(stream); + + stream >> _senderID; + + return stream; +} + +QDataStream &NodeObject::toStream(QDataStream &stream) const { + NetworkMember::toStream(stream); + + stream << _senderID; + + return stream; +} + +DBObject *NodeObject::factory() const { + return create<NodeObject>(); +} +} diff --git a/Heart/NetworkSpace/packages/nodeobject.h b/Heart/NetworkSpace/packages/nodeobject.h new file mode 100644 index 0000000..ebff06a --- /dev/null +++ b/Heart/NetworkSpace/packages/nodeobject.h @@ -0,0 +1,27 @@ +#ifndef NODEOBJECT_H +#define NODEOBJECT_H + +#include <networkmember.h> +#include <senderdata.h> +namespace NP { + +/** + * @brief The NodeObject class + */ +class NETWORKPROTOCOLSHARED_EXPORT NodeObject: public NetworkMember, public SenderData +{ +public: + NodeObject(); + NodeObject(const Package& pkg); + + // StreamBase interface +protected: + QDataStream &fromStream(QDataStream &stream) override; + QDataStream &toStream(QDataStream &stream) const override; + + // DBObject interface +public: + DBObject *factory() const override; +}; +} +#endif // NODEOBJECT_H diff --git a/Heart/NetworkSpace/packages/transportdata.cpp b/Heart/NetworkSpace/packages/transportdata.cpp new file mode 100644 index 0000000..0c4c355 --- /dev/null +++ b/Heart/NetworkSpace/packages/transportdata.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2018-2020 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 "transportdata.h" +#include <QCryptographicHash> +#include <QDataStream> +#include <QDateTime> +namespace NP { + +TransportData::TransportData() { + +} + +TransportData::TransportData(const HostAddress &sender): + TransportData() { + + addNodeToRoute(sender); +} + +TransportData::TransportData(const Package &package): + TransportData() { + + fromBytes(package.data); +} + +void TransportData::completeRoute(bool fRouteIsComplete) { + _fRouteIsComplete = fRouteIsComplete; +} + +const Package &TransportData::data() const { + return _data; +} + +void TransportData::setData(const Package &data) { + _data = data; + + QByteArray tmp = _data.data; + quint64 time = QDateTime::currentMSecsSinceEpoch(); + tmp.insert(sizeof(time), reinterpret_cast<char*>(&time)); + + _packageId.fromRaw(QCryptographicHash::hash(tmp, QCryptographicHash::Sha256)); +} + +bool TransportData::setData(const AbstractData &data) { + Package pkg; + if (!data.toPackage(pkg)) { + return false; + } + + setData(pkg); + return true; +} + +QDataStream &TransportData::fromStream(QDataStream &stream) { + AbstractData::fromStream(stream); + + stream >> _targetAddress; + stream >> _senderID; + stream >> _packageId; + stream >> _fRouteIsComplete; + stream >> _route; + + QByteArray array; + stream >> array; + _data.fromBytes(array); + + return stream; +} + +QDataStream &TransportData::toStream(QDataStream &stream) const { + + AbstractData::toStream(stream); + + stream << _targetAddress; + stream << _senderID; + stream << _packageId; + stream << _fRouteIsComplete; + stream << _route; + + stream << _data.toBytes(); + + return stream; +} + +BaseId TransportData::packageId() const { + return _packageId; +} + +const QList<HostAddress>& TransportData::route() const { + return _route; +} + +bool TransportData::setRoute(const QList<HostAddress> &route) { + + QSet<HostAddress> test; + for (const auto& address: route) { + if (test.contains(address)) + return false; + + test.insert(address); + } + + _route = route; + completeRoute(_route.size()); + + return _route.size(); +} + +void TransportData::addNodeToRoute(const HostAddress &node) { + _route.push_back(node); +} + +bool TransportData::strip(const HostAddress &correntAddress, + const HostAddress &availabelTarget) { + + QList<HostAddress>::Iterator begin = _route.end(); + QList<HostAddress>::Iterator end = _route.end(); + + for (auto it = _route.begin(); it != _route.end(); ++it) { + if (correntAddress == *it) { + begin = it; + } + + if (availabelTarget == *it) { + end = it; + break; + } + } + + if (begin != _route.end() && end != _route.end()) { + _route.erase(begin, end); + return true; + } + + return false; +} + +BaseId TransportData::targetAddress() const { + return _targetAddress; +} + +void TransportData::setTargetAddress(const BaseId &targetAddress) { + _targetAddress = targetAddress; +} + +bool TransportData::isValid() const { + return AbstractData::isValid() && _data.isValid() && _targetAddress.isValid(); +} + +bool TransportData::isHaveRoute() const { + return isValid() && _route.size() && _fRouteIsComplete; +} +} diff --git a/Heart/NetworkSpace/packages/transportdata.h b/Heart/NetworkSpace/packages/transportdata.h new file mode 100644 index 0000000..f8ce744 --- /dev/null +++ b/Heart/NetworkSpace/packages/transportdata.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018-2020 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 TRANSPORTDATA_H +#define TRANSPORTDATA_H + +#include "abstractdata.h" +#include "senderdata.h" + +#include "hostaddress.h" + +namespace NP { + +class NETWORKPROTOCOLSHARED_EXPORT TransportData: public AbstractData, public SenderData +{ + +public: + + explicit TransportData(const HostAddress& sender); + explicit TransportData(const Package& package); + + const Package& data() const; + void setData(const Package &data); + bool setData(const AbstractData& data); + bool isValid() const; + bool isHaveRoute() const; + + /** + * @brief targetAddress - targetAddress + * @return + */ + BaseId targetAddress() const; + void setTargetAddress(const BaseId &targetAddress); + + /** + * @brief route - is list of addresses of node was the TransportData has been moved. + * @return + */ + const QList<HostAddress> &route() const; + + /** + * @brief setRoute - set and validate route. + * @param route + * @return true if a new route is valid + */ + bool setRoute(const QList<HostAddress> &route); + + /** + * @brief addNodeToRoute - push back new node to route + * @param node - node address + */ + void addNodeToRoute(const HostAddress &node); + + /** + * @brief strip - this method remove a range addresses from route of transport data. from correntAddress to availabelTarget + * @param correntAddress - begin of remove + * @param availabelTarget - end of remove + * @return true if all addresses is removed + */ + bool strip(const HostAddress& correntAddress, const HostAddress& availabelTarget); + + /** + * @brief packageId + * @return unique package id. + */ + BaseId packageId() const; + + /** + * @brief completeRoute - set bool variable of route complete. + * @param fRouteIsComplete - new value for complete route default is true + */ + void completeRoute(bool fRouteIsComplete = true); + +protected: + QDataStream &fromStream(QDataStream &stream); + QDataStream &toStream(QDataStream &stream) const; + +private: + explicit TransportData(); + + Package _data; + BaseId _targetAddress; + QList<HostAddress> _route; + BaseId _packageId; + bool _fRouteIsComplete = false; + + + +}; + +} +#endif // TRANSPORTDATA_H diff --git a/Heart/NetworkSpace/router.cpp b/Heart/NetworkSpace/router.cpp new file mode 100644 index 0000000..d1fd9dc --- /dev/null +++ b/Heart/NetworkSpace/router.cpp @@ -0,0 +1,56 @@ +#include "router.h" +#include <config.h> + +#include <QDateTime> +#include <quasarapp.h> +namespace NP { + +Router::Router() { +} + +QList<HostAddress> Router::getRoute(const BaseId &node) const { + QMutexLocker locker(&_routesMutex); + return _routes.value(node); +} + +bool Router::contains(const BaseId &node) const { + QMutexLocker locker(&_routesMutex); + return _routes.contains(node); +} + +void Router::updateRoute(const BaseId &node, const QList<HostAddress> &route) { + QMutexLocker locker(&_routesMutex); + + debug_assert(node.isValid()); + + if (!_routes.contains(node) || _routes.value(node).size() > route.size()) { + + _routesTimeMap.insert(QDateTime::currentSecsSinceEpoch(), node); + _routes.insert(node, route); + + if (ROUTE_COUNT_LIMIT < _processedPackages.size()) { + _routes.remove(*_routesTimeMap.begin()); + _routesTimeMap.erase(_routesTimeMap.begin()); + } + } +} + +void Router::addProcesedPackage(const BaseId &id) { + QMutexLocker locker(&_processedPackagesMutex); + + _processedPackages.insert(id); + _processedPackagesTimeMap.insert(QDateTime::currentSecsSinceEpoch(), id); + + if (TRANSPORT_PACKAGES_CACHE < _processedPackages.size()) { + _processedPackages.remove(*_processedPackagesTimeMap.begin()); + _processedPackagesTimeMap.erase(_processedPackagesTimeMap.begin()); + } +} + +bool Router::isProcessed(const BaseId &id) const { + QMutexLocker locker(&_processedPackagesMutex); + + return _processedPackages.contains(id); + +} +} diff --git a/Heart/NetworkSpace/router.h b/Heart/NetworkSpace/router.h new file mode 100644 index 0000000..fa6cf5b --- /dev/null +++ b/Heart/NetworkSpace/router.h @@ -0,0 +1,64 @@ +#ifndef ROUTER_H +#define ROUTER_H +#include <QHash> +#include "baseid.h" +#include <QMutex> +#include <hostaddress.h> +#include <QMap> + +namespace NP { + +/** + * @brief The Router class - this class contains routes of nodes and optimise exists routes + * router - is thread save class. + */ +class Router +{ +public: + Router(); + + /** + * @brief getRoute + * @return return route to node from this node + */ + QList<HostAddress> getRoute(const BaseId& node) const; + + /** + * @brief contains - check contains route fo node id. + * @param node - id of node + * @return true if route findet. + */ + bool contains(const BaseId& node) const; + + + /** + * @brief updateRoute - set a new route for a node if the new route is shorter than the old route + * @param node + * @param route + */ + void updateRoute(const BaseId& node, const QList<HostAddress>& route); + + /** + * @brief addProcesedPackage - add id of processed package + * @param id + */ + void addProcesedPackage(const BaseId& id); + + /** + * @brief isProcessed + * @param id + * @return true if package is processed + */ + bool isProcessed(const BaseId& id) const; +private: + QHash<BaseId, QList<HostAddress>> _routes; + QMap<qint64, BaseId> _routesTimeMap; + mutable QMutex _routesMutex; + + QSet<BaseId> _processedPackages; + QMap<qint64, BaseId> _processedPackagesTimeMap; + mutable QMutex _processedPackagesMutex; + +}; +} +#endif // ROUTER_H diff --git a/Heart/NetworkSpace/senderdata.cpp b/Heart/NetworkSpace/senderdata.cpp new file mode 100644 index 0000000..ed7a6d2 --- /dev/null +++ b/Heart/NetworkSpace/senderdata.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2018-2020 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 "senderdata.h" +namespace NP { + +SenderData::SenderData() { + +} + +const BaseId &SenderData::senderID() const { + return _senderID; +} + +void SenderData::setSenderID(const BaseId &senderID) { + _senderID = senderID; +} +} diff --git a/Heart/NetworkSpace/senderdata.h b/Heart/NetworkSpace/senderdata.h new file mode 100644 index 0000000..6fd2787 --- /dev/null +++ b/Heart/NetworkSpace/senderdata.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2018-2020 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 SENDERDATA_H +#define SENDERDATA_H +#include "baseid.h" + +namespace NP { + +/** + * @brief The SenderData class - this is base interface class for get sender id of data base objects + */ +class NETWORKPROTOCOLSHARED_EXPORT SenderData +{ +public: + SenderData(); + + const BaseId& senderID() const; + void setSenderID(const BaseId &senderID); + +protected: + BaseId _senderID; +}; +} +#endif // SENDERDATA_H diff --git a/Heart/NetworkSpace/sign.cpp b/Heart/NetworkSpace/sign.cpp new file mode 100644 index 0000000..96f0f05 --- /dev/null +++ b/Heart/NetworkSpace/sign.cpp @@ -0,0 +1,16 @@ +#include "sign.h" +namespace NP { + +Sign::Sign() +{ + +} + +QByteArray Sign::sign() const { + return _sign; +} + +void Sign::setSign(const QByteArray &sign) { + _sign = sign; +} +} diff --git a/Heart/NetworkSpace/sign.h b/Heart/NetworkSpace/sign.h new file mode 100644 index 0000000..ac821bf --- /dev/null +++ b/Heart/NetworkSpace/sign.h @@ -0,0 +1,33 @@ +#ifndef SIGN_H +#define SIGN_H + +#include <QByteArray> +#include "heart_global.h" + + +namespace NP { + +/** + * @brief The Sign class - this class contains sign of child data package. + */ +class NETWORKPROTOCOLSHARED_EXPORT Sign +{ +public: + Sign(); + + QByteArray sign() const; + void setSign(const QByteArray &sign); + + QByteArray& sign(); + + /** + * @brief dataForSigned - thism metho return byte array for signed + * @return data array + */ + virtual QByteArray dataForSigned() const = 0; + +private: + QByteArray _sign; +}; +} +#endif // SIGN_H diff --git a/Heart/ProtockolResusces.qrc b/Heart/ProtockolResusces.qrc new file mode 100644 index 0000000..ac86a4f --- /dev/null +++ b/Heart/ProtockolResusces.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/sql"> + <file>DataBaseSpace/Res/DbConfig.json</file> + <file>DataBaseSpace/Res/BaseDB.sql</file> + </qresource> +</RCC> diff --git a/Heart/Qt-Secret b/Heart/Qt-Secret new file mode 160000 index 0000000..6bdff9a --- /dev/null +++ b/Heart/Qt-Secret @@ -0,0 +1 @@ +Subproject commit 6bdff9ab99c5deef7739cf9b852c3855d9fcced5 diff --git a/Heart/heart.cpp b/Heart/heart.cpp new file mode 100644 index 0000000..f6cd684 --- /dev/null +++ b/Heart/heart.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2018-2020 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 "heart.h" + +#include <QDataStream> +#include <QVariantMap> + +namespace NP { + +} diff --git a/Heart/heart.h b/Heart/heart.h new file mode 100644 index 0000000..2dd3cc0 --- /dev/null +++ b/Heart/heart.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018-2020 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 NETWORKPROTOCOL_H +#define NETWORKPROTOCOL_H + +#include "package.h" +#include "abstractnode.h" + +/** + * NP - Network protocol + * defirent values: + * SP - shared pointer + * WP - weak pointer + */ +namespace NP { +} + +#endif // NETWORKPROTOCOL_H diff --git a/Heart/heart_global.h b/Heart/heart_global.h new file mode 100644 index 0000000..f3cd281 --- /dev/null +++ b/Heart/heart_global.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2018-2020 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 NETWORKPROTOCOL_GLOBAL_H +#define NETWORKPROTOCOL_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(NETWORKPROTOCOL_LIBRARY) +# define NETWORKPROTOCOLSHARED_EXPORT Q_DECL_EXPORT +#else +# define NETWORKPROTOCOLSHARED_EXPORT Q_DECL_IMPORT +#endif + +#endif // NETWORKPROTOCOL_GLOBAL_H diff --git a/ProtocolTests/.gitignore b/HeartTests/.gitignore similarity index 100% rename from ProtocolTests/.gitignore rename to HeartTests/.gitignore diff --git a/HeartTests/AbstractSpace/abstractnodetest.cpp b/HeartTests/AbstractSpace/abstractnodetest.cpp new file mode 100644 index 0000000..e237d66 --- /dev/null +++ b/HeartTests/AbstractSpace/abstractnodetest.cpp @@ -0,0 +1,157 @@ +#include "abstractnodetest.h" +#include "testutils.h" + +#include <abstractnode.h> +#include <keystorage.h> +#include <ping.h> +#include <qsecretrsa2048.h> + +class TestingClient: public NP::AbstractNode { + + + // AbstractNode interface +public: + const NP::Ping& getPing() const { + return _ping; + } + +protected: + void incomingData(NP::AbstractData *pkg, const NP::HostAddress &sender) { + Q_UNUSED(sender); + + auto ping = dynamic_cast<NP::Ping*>(pkg); + if (ping) + _ping.copyFrom(ping); + } + +private: + NP::Ping _ping; +}; + +AbstractNodeTest::AbstractNodeTest() { + _nodeA = new NP::AbstractNode(); + _nodeB = new TestingClient(); +} + +AbstractNodeTest::~AbstractNodeTest() { + delete _nodeA; + delete _nodeB; +} + +void AbstractNodeTest::test() { + QVERIFY(connectTest()); + QVERIFY(sendDataTest()); +} + +bool AbstractNodeTest::connectTest() { + + if (!_nodeA->run(TEST_LOCAL_HOST, TEST_PORT)) { + return false; + } + + return connectFunc(_nodeB, TEST_LOCAL_HOST, TEST_PORT); +} + +bool AbstractNodeTest::sendDataTest() { + + auto request = [this](){ + return _nodeB->ping(NP::HostAddress(TEST_LOCAL_HOST, TEST_PORT)); + }; + + auto client = dynamic_cast<TestingClient*>(_nodeB); + + auto check = [client](){ + return client->getPing().ansver(); + }; + + return funcPrivateConnect(request, check); +} + +template<class Crypto> +bool validationCrypto() { + // create crypto oject + auto crypto = new NP::KeyStorage(new Crypto()); + + + // get test pair keys + auto keys = crypto->getNextPair("TEST_KEY"); + + // must be failed becouse crypto object still not inited. + if (keys.isValid()) { + delete crypto; + return false; + } + + if (!crypto->initDefaultStorageLocation()) { + delete crypto; + return false; + } + + // get test pair keys + keys = crypto->getNextPair("TEST_KEY"); + + // chekck keys + if (!keys.isValid()) { + delete crypto; + return false; + } + + // remove crypto object, after remove crypto object most be save all generated keys + delete crypto; + + // second initialisin of crypto object + crypto = new NP::KeyStorage(new Crypto()); + if (!crypto->initDefaultStorageLocation()) { + delete crypto; + return false; + } + + // check get generated key pair + if (keys != crypto->getNextPair("TEST_KEY", 0)) { + delete crypto; + return false; + } + + QByteArray msg = "test_message"; + + // check sign data + if (!crypto->sign(&msg, keys.privKey())) { + delete crypto; + return false; + } + + if (!crypto->check(msg, keys.publicKey())) { + delete crypto; + return false; + } + + // check genesis generation of keys + auto ThisIsKey = crypto->getNextPair("key", "this is key"); + auto ThisIsKey2 = crypto->getNextPair("key2", "this is key"); + + if (ThisIsKey != ThisIsKey2) { + delete crypto; + return false; + } + + + delete crypto; + + crypto = new NP::KeyStorage(new Crypto()); + if (!crypto->initDefaultStorageLocation()) { + delete crypto; + return false; + } + + auto lastKeys = crypto->getNextPair("key2", RAND_KEY, 0); + return lastKeys == ThisIsKey2; +} + +bool AbstractNodeTest::testICtypto() { + // check + if (!validationCrypto<NP::QSecretRSA2048>()) { + return false; + } + + return true; +} diff --git a/HeartTests/AbstractSpace/abstractnodetest.h b/HeartTests/AbstractSpace/abstractnodetest.h new file mode 100644 index 0000000..395ca2d --- /dev/null +++ b/HeartTests/AbstractSpace/abstractnodetest.h @@ -0,0 +1,32 @@ +#ifndef ABSTRACTNODETEST_H +#define ABSTRACTNODETEST_H +#include "test.h" +#include "testutils.h" + +#include <QtTest> +#include <abstractnode.h> + + +class AbstractNodeTest: public Test, protected TestUtils +{ +public: + AbstractNodeTest(); + ~AbstractNodeTest(); + + void test(); + +private: + NP::AbstractNode *_nodeA = nullptr; + NP::AbstractNode *_nodeB = nullptr; + + bool connectTest(); + bool sendDataTest(); + + /** + * @brief testICtypto - testing ictypto class + * @return + */ + bool testICtypto(); +}; + +#endif // ABSTRACTNODETEST_H diff --git a/HeartTests/AbstractSpace/test.cpp b/HeartTests/AbstractSpace/test.cpp new file mode 100644 index 0000000..33296cc --- /dev/null +++ b/HeartTests/AbstractSpace/test.cpp @@ -0,0 +1 @@ +#include "test.h" diff --git a/HeartTests/AbstractSpace/test.h b/HeartTests/AbstractSpace/test.h new file mode 100644 index 0000000..72b6474 --- /dev/null +++ b/HeartTests/AbstractSpace/test.h @@ -0,0 +1,15 @@ +#ifndef TEST_H +#define TEST_H + +#define TEST_LOCAL_HOST "127.0.0.1" +#define TEST_PORT 27777 + +class Test +{ +public: + Test() = default; + virtual ~Test() = default; + virtual void test() = 0; +}; + +#endif // TEST_H diff --git a/HeartTests/AbstractSpace/testutils.cpp b/HeartTests/AbstractSpace/testutils.cpp new file mode 100644 index 0000000..36ff67c --- /dev/null +++ b/HeartTests/AbstractSpace/testutils.cpp @@ -0,0 +1,63 @@ +#include "testutils.h" + +#include <QCoreApplication> +#include <QDateTime> +#include <QVariantMap> +#include <abstractnode.h> +#include <hostaddress.h> + +bool TestUtils::funcPrivateConnect(const std::function<bool()> &requestFunc, + const std::function<bool()> &checkFunc, + const std::function<QMetaObject::Connection()> &connectFunction) const { + + QMetaObject::Connection m_connection = connectFunction(); + if (requestFunc && !requestFunc()) { + QObject::disconnect(m_connection); + return false; + } + + bool return_value = TestUtils::wait(checkFunc, WAIT_RESPOCE_TIME); + QObject::disconnect(m_connection); + + return return_value; +} + +bool TestUtils::funcPrivateConnect(const std::function<bool ()> &requestFunc, + const std::function<bool ()> &checkFunc) const { + return funcPrivateConnect(requestFunc, checkFunc, [](){return QMetaObject::Connection();}); +} + +TestUtils::TestUtils() +{ + +} + +TestUtils::~TestUtils() { + +} + +bool TestUtils::wait(const std::function<bool()> &forWait, int msec) const { + auto curmsec = QDateTime::currentMSecsSinceEpoch() + msec; + while (curmsec > QDateTime::currentMSecsSinceEpoch() && !forWait()) { + QCoreApplication::processEvents(); + } + QCoreApplication::processEvents(); + return forWait(); +} + +bool TestUtils::connectFunc( + NP::AbstractNode *cli, + const QString& address, + unsigned short port) const { + + auto wraper = [&cli, address, port]() { + cli->addNode(NP::HostAddress{address, port}); + return true; + }; + + auto check = [&cli]() { + return cli->connectionsCount(); + }; + + return funcPrivateConnect(wraper, check, [](){ return QMetaObject::Connection{};}); +} diff --git a/HeartTests/AbstractSpace/testutils.h b/HeartTests/AbstractSpace/testutils.h new file mode 100644 index 0000000..18b5e61 --- /dev/null +++ b/HeartTests/AbstractSpace/testutils.h @@ -0,0 +1,28 @@ +#ifndef TESTUTILS_H +#define TESTUTILS_H + +#include <abstractnode.h> +#include <heart.h> + + +class TestUtils +{ +public: + TestUtils(); + virtual ~TestUtils(); + bool wait(const std::function<bool()> &forWait, int msec) const; + + bool connectFunc(NP::AbstractNode *cli, + const QString &address, + unsigned short port) const; + + bool funcPrivateConnect(const std::function<bool ()> &requestFunc, + const std::function<bool ()> &checkFunc, + const std::function<QMetaObject::Connection ()> &connectFunction) const; + + bool funcPrivateConnect(const std::function<bool ()> &requestFunc, + const std::function<bool ()> &checkFunc) const; + +}; + +#endif // TESTUTILS_H diff --git a/HeartTests/CMakeLists.txt b/HeartTests/CMakeLists.txt new file mode 100644 index 0000000..539b0a6 --- /dev/null +++ b/HeartTests/CMakeLists.txt @@ -0,0 +1,64 @@ +# +# Copyright (C) 2018-2020 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. +# + +cmake_minimum_required(VERSION 3.10) + +set(CURRENT_PROJECT ${PROJECT_NAME}Test) + +include(../QuasarAppLib/CMake/ProjectOut.cmake) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_definitions(-DBUILD_LVL=${BUILD_LVL}) + + +if (${BUILD_LVL} GREATER_EQUAL 0) + message("BUILD LVL >= 0") + file(GLOB SOURCE_CPP_LVL_0 + "*.cpp" "*.qrc" + "AbstractSpace/*.cpp" "AbstractSpace/*.qrc" + ) + set(PUBLIC_INCUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/AbstractSpace") +endif() + +if (${BUILD_LVL} GREATER_EQUAL 1) + message("BUILD LVL >= 1") + file(GLOB SOURCE_CPP_LVL_1 + "DataBaseSpace/*.cpp" "DataBaseSpace/*.qrc" + ) + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/DataBaseSpace") + +endif() + +if (${BUILD_LVL} GREATER_EQUAL 2) + message("BUILD LVL >= 2") + file(GLOB SOURCE_CPP_LVL_2 + "NetworkSpace/*.cpp" "NetworkSpace/*.qrc" + ) + set(PUBLIC_INCUDE_DIR ${PUBLIC_INCUDE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/NetworkSpace") + +endif() + +set(SOURCE_CPP ${SOURCE_CPP_LVL_0} ${SOURCE_CPP_LVL_1} ${SOURCE_CPP_LVL_2}) + +message(SOURCE_CPP = ${SOURCE_CPP}) + +add_executable(${CURRENT_PROJECT} ${SOURCE_CPP}) +target_link_libraries(${CURRENT_PROJECT} PRIVATE Qt5::Test Heart) + +target_include_directories(${CURRENT_PROJECT} PUBLIC ${PUBLIC_INCUDE_DIR}) +target_include_directories(${CURRENT_PROJECT} PRIVATE ${PRIVATE_INCUDE_DIR}) + + +include(../QuasarAppLib/CMake/QuasarAppCITargets.cmake) +initTests() +addTests("NetworkProtokol" ${CURRENT_PROJECT}) diff --git a/HeartTests/DataBaseSpace/basenodetest.cpp b/HeartTests/DataBaseSpace/basenodetest.cpp new file mode 100644 index 0000000..773cef2 --- /dev/null +++ b/HeartTests/DataBaseSpace/basenodetest.cpp @@ -0,0 +1,136 @@ +#include "basenodetest.h" +#include "basenodeunittests.h" +#include "testutils.h" + +#include <databasenode.h> +#include <hostaddress.h> +#include <keystorage.h> +#include <ping.h> +#include <qsecretrsa2048.h> + +class TestingBaseClient: public NP::DataBaseNode { + + + // AbstractNode interface +public: + const NP::Ping& getPing() const { + return _ping; + } + +protected: + void incomingData(NP::AbstractData *pkg, const NP::HostAddress& sender) { + Q_UNUSED(sender); + + auto ping = dynamic_cast<NP::Ping*>(pkg); + if (ping) + _ping.copyFrom(ping); + } + +private: + NP::Ping _ping; +}; + +class BadTstClient: public NP::DataBaseNode { + +}; + +BaseNodeTest::BaseNodeTest() { + _client1 = new TestingBaseClient(); + _client2 = new TestingBaseClient(); + + _server = new NP::DataBaseNode(); + +} + +BaseNodeTest::~BaseNodeTest() { + delete _client1; + delete _client2; + delete _server; + +} + +void BaseNodeTest::test() { + QVERIFY(dbTest()); + QVERIFY(powerTest()); + QVERIFY(connectNetworkTest()); + QVERIFY(securityTest()); + +} + +bool BaseNodeTest::powerTest() { + auto _nodeAPtr = new NP::DataBaseNode(); + + if (!_nodeAPtr->run(TEST_LOCAL_HOST, TEST_PORT, "powerTest")) { + return false; + }; + + delete _nodeAPtr; + + return true; +} + +bool BaseNodeTest::dbTest() { + auto node = new BaseNodeUnitTests; + + if (!node->test()) { + return false; + } + + delete node; + + return true; +} + +bool BaseNodeTest::connectNetworkTest() { + + auto client1 = dynamic_cast<NP::DataBaseNode*>(_client1); + auto client2 = dynamic_cast<NP::DataBaseNode*>(_client2); + auto server = dynamic_cast<NP::DataBaseNode*>(_server); + + if (!server->run(TEST_LOCAL_HOST, TEST_PORT, "ServerDataBaseNode")) { + return false; + } + + auto addNodeRequest = [client1, client2]() { + client1->addNode(NP::HostAddress(TEST_LOCAL_HOST, TEST_PORT)); + client2->addNode(NP::HostAddress(TEST_LOCAL_HOST, TEST_PORT)); + + return true; + }; + + auto checkNode = [server](){ + return server->connectionsCount() == 2; + }; + + if (!funcPrivateConnect(addNodeRequest, checkNode)) { + return false; + } + + // need to wait for add node + + auto request = [client1, client2]() { + return client1->ping(NP::HostAddress(TEST_LOCAL_HOST, TEST_PORT)) && + client2->ping(NP::HostAddress(TEST_LOCAL_HOST, TEST_PORT)); + }; + + auto tstclient1 = dynamic_cast<TestingBaseClient*>(client1); + auto tstclient2 = dynamic_cast<TestingBaseClient*>(client1); + + auto check = [tstclient1, tstclient2]() { + return tstclient1->getPing().ansver() && + tstclient2->getPing().ansver(); + }; + + return funcPrivateConnect(request, check); + +} + +bool BaseNodeTest::securityTest() { + + + + return true; +} + + + diff --git a/HeartTests/DataBaseSpace/basenodetest.h b/HeartTests/DataBaseSpace/basenodetest.h new file mode 100644 index 0000000..c1427a0 --- /dev/null +++ b/HeartTests/DataBaseSpace/basenodetest.h @@ -0,0 +1,53 @@ +#ifndef BASENODETEST_H +#define BASENODETEST_H +#include "basetestutils.h" +#include "test.h" +#include "testutils.h" + +#include <QtTest> +#include <heart.h> + + +class BaseNodeTest: public Test, protected BaseTestUtils +{ +public: + BaseNodeTest(); + ~BaseNodeTest(); + + void test(); + +private: + NP::AbstractNode *_server = nullptr; + NP::AbstractNode *_client1 = nullptr; + NP::AbstractNode *_client2 = nullptr; + + + /** + * @brief powerTest - this test just create a new object of node and distruct it. + * check constructors and distructors of nodes objects. + * @return true if the test finished successful + */ + bool powerTest(); + + /** + * @brief dbTest - test base functions of database of nodes. + * @return true if test finished successful. + */ + bool dbTest(); + + /** + * @brief connectNetworkTest + * this test check nodes connections greatThen 3 node + * @return + */ + bool connectNetworkTest(); + + /** + * @brief securityTest - this test create 2 clinet app and try get or change data of another client. + * @return + */ + bool securityTest(); + +}; + +#endif // BASENODETEST_H diff --git a/HeartTests/DataBaseSpace/basenodeunittests.cpp b/HeartTests/DataBaseSpace/basenodeunittests.cpp new file mode 100644 index 0000000..1efaa94 --- /dev/null +++ b/HeartTests/DataBaseSpace/basenodeunittests.cpp @@ -0,0 +1,206 @@ +#include "basenodeunittests.h" +#include "test.h" +#include "sqldbcache.h" +#include <QFileInfo> +#include <QFile> +#include <networkmember.h> + +#define DB_NODE_NAME "DatabaseTestNode" + +QByteArray randomArray(int length) { + char *buf = static_cast<char*>(malloc(length)); + QByteArray data; + data.insert(0, buf, length); + + free(buf); + + return data; +} + +const NP::NetworkMember* randomMember() { + NP::NetworkMember *res = new NP::NetworkMember(); + + res->setAuthenticationData(randomArray(64)); + res->setTrust(0); + + res->prepareToSend(); + + return res; +} + +BaseNodeUnitTests::BaseNodeUnitTests():NP::DataBaseNode(), + testObjec(randomMember()) { + +} + +bool BaseNodeUnitTests::test() { + + if (!init()) { + return false; + } + + if (!testReadWrite()) { + return false; + } + + if (!testUpdate()) { + return false; + } + + if (!testChangeTrust()) { + return false; + } + + return true; +} + +bool BaseNodeUnitTests::init() { + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + QString database = dbLocation(); + stop(); + + + if (QFileInfo(database).exists() && !QFile::remove(database)) { + return false; + } + + return true; +} + +bool BaseNodeUnitTests::testReadWrite() { + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + + auto objectFromDataBase = db()->getObject(*testObjec); + + if (objectFromDataBase) { + return false; + } + + if (!db()->saveObject(testObjec)) { + return false; + } + + auto object = db()->getObject(*testObjec); + + if (!object || !object->isValid()) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(*testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() == 0) { + return true; + } + + return false; +} + +bool BaseNodeUnitTests::testUpdate() { + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + + auto objectFromDataBase = db()->getObject(*testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 0) { + return false; + } + + auto clone = objectFromDataBase->clone().staticCast<NP::NetworkMember>(); + + clone->setTrust(20); + + if (!db()->saveObject(clone.data())) { + return false; + } + + objectFromDataBase = db()->getObject(*testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() != 20) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(*testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 20) { + return false; + } + + return true; +} + +bool BaseNodeUnitTests::testChangeTrust() { + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + if(!changeTrust(testObjec->getId(), -10)) { + return false; + }; + + auto objectFromDataBase = db()->getObject(*testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() != 10) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(*testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 10) { + return false; + } + + if(!changeTrust(testObjec->getId(), -10)) { + return false; + }; + + objectFromDataBase = db()->getObject(*testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() != 0) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(*testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 0) { + return false; + } + + return isBanned(testObjec->getId()); + +} diff --git a/HeartTests/DataBaseSpace/basenodeunittests.h b/HeartTests/DataBaseSpace/basenodeunittests.h new file mode 100644 index 0000000..0f7d727 --- /dev/null +++ b/HeartTests/DataBaseSpace/basenodeunittests.h @@ -0,0 +1,53 @@ +#ifndef DBTESTS_H +#define DBTESTS_H + +#include <databasenode.h> + +/** + * @brief The DbTestsNode class - this implementation of node gor testing database + */ + +namespace NP { + class NetworkMember; +}; + +class BaseNodeUnitTests: public NP::DataBaseNode +{ +public: + BaseNodeUnitTests(); + /** + * @brief test - test work database + * @return true if database of node work is correctly. + */ + bool test(); + +private: + /** + * @brief init - init database. + * @return return true if test module initialized successful + */ + bool init(); + + /** + * @brief testReadWrite - test save and get object functions + * @return true if all test finished successful + */ + bool testReadWrite(); + + /** + * @brief testUpdate - test update functions + * @return true if all test finished successful. + */ + bool testUpdate(); + + /** + * @brief testChangeTrust - this test check bad request responce for node + * @return true if all test finished successful + */ + bool testChangeTrust(); + + const NP::NetworkMember *testObjec = nullptr; + +}; + +#endif // DBTESTS_H diff --git a/HeartTests/DataBaseSpace/basetestutils.cpp b/HeartTests/DataBaseSpace/basetestutils.cpp new file mode 100644 index 0000000..f97fb59 --- /dev/null +++ b/HeartTests/DataBaseSpace/basetestutils.cpp @@ -0,0 +1,11 @@ +#include "basetestutils.h" + +#include "test.h" + +BaseTestUtils::BaseTestUtils() { + +} + +BaseTestUtils::~BaseTestUtils() { +} + diff --git a/HeartTests/DataBaseSpace/basetestutils.h b/HeartTests/DataBaseSpace/basetestutils.h new file mode 100644 index 0000000..f9f4d14 --- /dev/null +++ b/HeartTests/DataBaseSpace/basetestutils.h @@ -0,0 +1,18 @@ +#ifndef BASETESTUTILS_H +#define BASETESTUTILS_H + +#include <testutils.h> +namespace NP { +class DataBaseNode; +class BaseId; +} + +class BaseTestUtils: public TestUtils +{ +public: + BaseTestUtils(); + ~BaseTestUtils(); + +}; + +#endif // BASETESTUTILS_H diff --git a/HeartTests/NetworkSpace/networknodetest.cpp b/HeartTests/NetworkSpace/networknodetest.cpp new file mode 100644 index 0000000..2913fac --- /dev/null +++ b/HeartTests/NetworkSpace/networknodetest.cpp @@ -0,0 +1,157 @@ +#include "networknodetest.h" +#include "networknodeunittests.h" +#include "testutils.h" + +#include <networknode.h> +#include <keystorage.h> +#include <ping.h> +#include <qsecretrsa2048.h> + +class TestingNetworkClient: public NP::NetworkNode { + + + // AbstractNode interface +public: + const NP::Ping& getPing() const { + return _ping; + } + +protected: + void incomingData(NP::AbstractData *pkg, const NP::BaseId &sender) { + Q_UNUSED(sender); + + auto ping = dynamic_cast<NP::Ping*>(pkg); + if (ping) + _ping.copyFrom(ping); + } + +private: + NP::Ping _ping; +}; + +NetworkNodeTest::NetworkNodeTest() { + _nodeA = new TestingNetworkClient(); + _nodeB = new NP::NetworkNode(); + _nodeC = new TestingNetworkClient(); + +} + +NetworkNodeTest::~NetworkNodeTest() { + delete _nodeA; + delete _nodeB; + delete _nodeC; + +} + +void NetworkNodeTest::test() { + QVERIFY(dbTest()); + QVERIFY(powerTest()); + QVERIFY(connectNetworkTest()); + QVERIFY(transportDataTest()); + +// QVERIFY(performanceTest()); +// QVERIFY(securityTest()); + +} + +bool NetworkNodeTest::powerTest() { + auto _nodeAPtr = new NP::NetworkNode(); + + if (!_nodeAPtr->run(TEST_LOCAL_HOST, TEST_PORT, "powerTest")) { + return false; + }; + + delete _nodeAPtr; + + return true; +} + +bool NetworkNodeTest::dbTest() { + auto node = new NetworkNodeUnitTests; + + if (!node->test()) { + return false; + } + + delete node; + + return true; +} + +bool NetworkNodeTest::connectNetworkTest() { + int nodeAPort = TEST_PORT + 0; + int nodeBPort = TEST_PORT + 1; + int nodeCPort = TEST_PORT + 2; + + + auto _nodeAPtr = dynamic_cast<NP::NetworkNode*>(_nodeA); + auto _nodeBPtr = dynamic_cast<NP::NetworkNode*>(_nodeB); + auto _nodeCPtr = dynamic_cast<NP::NetworkNode*>(_nodeC); + + if (!_nodeAPtr->run(TEST_LOCAL_HOST, nodeAPort, "TestNodeA")) { + return false; + } + if (!_nodeBPtr->run(TEST_LOCAL_HOST, nodeBPort, "TestNodeB")) { + return false; + }; + if (!_nodeCPtr->run(TEST_LOCAL_HOST, nodeCPort, "TestNodeC")) { + return false; + }; + + auto nodeA = _nodeAPtr->nodeId(); + auto nodeB = _nodeBPtr->nodeId(); + auto nodeC = _nodeCPtr->nodeId(); + + + auto addNodeRequest = [_nodeAPtr, nodeBPort, nodeCPort, _nodeBPtr, nodeC]() { + _nodeAPtr->addNode(NP::HostAddress(TEST_LOCAL_HOST, nodeBPort)); + _nodeBPtr->addNode(NP::HostAddress(TEST_LOCAL_HOST, nodeCPort)); + return true; + }; + + auto checkNode = [_nodeAPtr, _nodeBPtr](){ + return _nodeAPtr->confirmendCount() && _nodeBPtr->confirmendCount(); + }; + + if (!funcPrivateConnect(addNodeRequest, checkNode)) { + return false; + } + + // need to wait for add node + + auto request = [_nodeAPtr, nodeC]() { + return _nodeAPtr->ping(nodeC); + }; + + auto client = dynamic_cast<TestingNetworkClient*>(_nodeAPtr); + + auto check = [client](){ + return client->getPing().ansver(); + }; + + return funcPrivateConnect(request, check); + +} + +bool NetworkNodeTest::transportDataTest() { + auto coreNode = getCoreNode(); + + auto network = generateNetworkNode(30); + + if (!(network.size() && coreNode->confirmendCount() == 30)) { + return false; + } + + return true; +} + +bool NetworkNodeTest::performanceTest() { + return false; +} + +bool NetworkNodeTest::securityTest() { + return false; +} + + + diff --git a/HeartTests/NetworkSpace/networknodetest.h b/HeartTests/NetworkSpace/networknodetest.h new file mode 100644 index 0000000..c9cbb3b --- /dev/null +++ b/HeartTests/NetworkSpace/networknodetest.h @@ -0,0 +1,67 @@ +#ifndef NETWORKNODETEST_H +#define NETWORKNODETEST_H +#include "networktestutils.h" +#include "test.h" +#include "testutils.h" + +#include <QtTest> + + +class NetworkNodeTest: public Test, protected NetworkTestUtils +{ +public: + NetworkNodeTest(); + ~NetworkNodeTest(); + + void test(); + +private: + NP::AbstractNode *_nodeA = nullptr; + NP::AbstractNode *_nodeB = nullptr; + NP::AbstractNode *_nodeC = nullptr; + + + + /** + * @brief powerTest - this test just create a new object of node and distruct it. + * check constructors and distructors of nodes objects. + * @return true if the test finished successful + */ + bool powerTest(); + + /** + * @brief dbTest - test base functions of database of nodes. + * @return true if test finished successful. + */ + bool dbTest(); + + /** + * @brief connectNetworkTest + * this test check nodes connections greatThen 3 node + * @return + */ + bool connectNetworkTest(); + + /** + * @brief transportDataTest + * this test create a small network and sending data to next route : A >> B >> C and C >> B >> A + * @return + */ + bool transportDataTest(); + + /** + * @brief performanceTest + * this test crate a big network from 100 or biger nodes count and send data for all nodes of network. + * @return + */ + bool performanceTest(); + + /** + * @brief securityTest - this test create big network and create not valid nodes. After created the network a not valid nodes try conquer network. + * @return + */ + bool securityTest(); + +}; + +#endif // NETWORKNODETEST_H diff --git a/HeartTests/NetworkSpace/networknodeunittests.cpp b/HeartTests/NetworkSpace/networknodeunittests.cpp new file mode 100644 index 0000000..35137cd --- /dev/null +++ b/HeartTests/NetworkSpace/networknodeunittests.cpp @@ -0,0 +1,187 @@ +#include "networknodeunittests.h" +#include "test.h" +#include "sqldbcache.h" +#include <QFileInfo> +#include <QFile> + +#define DB_NODE_NAME "DbTestNetworkNode" + +NetworkNodeUnitTests::NetworkNodeUnitTests():NP::NetworkNode() { + +} + +bool NetworkNodeUnitTests::test() { + + if (!init()) { + return false; + } + + if (!testReadWrite()) { + return false; + } + + if (!testUpdate()) { + return false; + } + + if (!testChangeTrust()) { + return false; + } + + return true; +} + +bool NetworkNodeUnitTests::init() { + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + QString database = dbLocation(); + stop(); + + + if (QFileInfo(database).exists() && !QFile::remove(database)) { + return false; + } + + return true; +} + +bool NetworkNodeUnitTests::testReadWrite() { + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + NP::NodeObject testObjec = thisNode(); + + auto objectFromDataBase = db()->getObject(testObjec); + + if (objectFromDataBase) { + return false; + } + + if (!db()->saveObject(&testObjec)) { + return false; + } + + auto object = db()->getObject(testObjec); + + if (!object || !object->isValid()) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() == 0) { + return true; + } + + return false; +} + +bool NetworkNodeUnitTests::testUpdate() { + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + NP::NodeObject testObjec = thisNode(); + + auto objectFromDataBase = db()->getObject(testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 0) { + return false; + } + + auto clone = objectFromDataBase->clone().staticCast<NP::NodeObject>(); + + clone->setTrust(20); + + if (!db()->saveObject(clone.data())) { + return false; + } + + objectFromDataBase = db()->getObject(testObjec); + + if (objectFromDataBase && objectFromDataBase->trust() != 20) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = db()->getObject(testObjec); + + if (!objectFromDataBase || objectFromDataBase->trust() != 20) { + return false; + } + + return true; +} + +bool NetworkNodeUnitTests::testChangeTrust() { + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + NP::NodeObject testObjec = thisNode(); + + if(!changeTrust(testObjec.getId(), -10)) { + return false; + }; + + auto objectFromDataBase = static_cast<const NP::NodeObject*>(db()->getObjectRaw(testObjec)); + + if (objectFromDataBase && objectFromDataBase->trust() != 10) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = static_cast<const NP::NodeObject*>(db()->getObjectRaw(testObjec)); + + if (!objectFromDataBase || objectFromDataBase->trust() != 10) { + return false; + } + + if(!changeTrust(testObjec.getId(), -10)) { + return false; + }; + + objectFromDataBase = static_cast<const NP::NodeObject*>(db()->getObjectRaw(testObjec)); + + if (objectFromDataBase && objectFromDataBase->trust() != 0) { + return false; + } + + stop(); + + if (!run(TEST_LOCAL_HOST, TEST_PORT, DB_NODE_NAME)) { + return false; + } + + objectFromDataBase = static_cast<const NP::NodeObject*>(db()->getObjectRaw(testObjec)); + + if (!objectFromDataBase || objectFromDataBase->trust() != 0) { + return false; + } + + return isBanned(testObjec.getId()); + +} diff --git a/HeartTests/NetworkSpace/networknodeunittests.h b/HeartTests/NetworkSpace/networknodeunittests.h new file mode 100644 index 0000000..615594c --- /dev/null +++ b/HeartTests/NetworkSpace/networknodeunittests.h @@ -0,0 +1,45 @@ +#ifndef DBTESTS_H +#define DBTESTS_H + +#include <networknode.h> + +/** + * @brief The DbTestsNode class - this implementation of node gor testing database + */ +class NetworkNodeUnitTests: public NP::NetworkNode +{ +public: + NetworkNodeUnitTests(); + /** + * @brief test - test work database + * @return true if database of node work is correctly. + */ + bool test(); + +private: + /** + * @brief init - init database. + * @return return true if test module initialized successful + */ + bool init(); + + /** + * @brief testReadWrite - test save and get object functions + * @return true if all test finished successful + */ + bool testReadWrite(); + + /** + * @brief testUpdate - test update functions + * @return true if all test finished successful. + */ + bool testUpdate(); + + /** + * @brief testChangeTrust - this test check bad request responce for node + * @return true if all test finished successful + */ + bool testChangeTrust(); +}; + +#endif // DBTESTS_H diff --git a/HeartTests/NetworkSpace/networktestutils.cpp b/HeartTests/NetworkSpace/networktestutils.cpp new file mode 100644 index 0000000..507e6f7 --- /dev/null +++ b/HeartTests/NetworkSpace/networktestutils.cpp @@ -0,0 +1,116 @@ +#include "networktestutils.h" + +#include <networknode.h> +#include "test.h" + +NetworkTestUtils::NetworkTestUtils() { + +} + +NetworkTestUtils::~NetworkTestUtils() { + if (coreNode) { + delete coreNode; + } +} + +NP::NetworkNode *NetworkTestUtils::initNewNode() const { + int port = nextPort(); + QString name = (coreNode)? QString("TestNode-%0").arg(port): QString("CoreNode-%0").arg(port); + + auto node = new NP::NetworkNode(); + + if (!node->run(TEST_LOCAL_HOST, port, name)) { + delete node; + return nullptr; + } + + return node; +} + +const NP::NetworkNode *NetworkTestUtils::getCoreNode() { + if (!coreNode) + coreNode = initNewNode(); + + + return coreNode; +} + +bool NetworkTestUtils::deployNewNode(NP::NetworkNode* node) const { + + if (!node) + return false; + + if (coreNode) { + + auto addNodeRequest = [node, this]() { + node->addNode(coreNode->address()); + return true; + }; + + auto checkNode = [node](){ + return node->confirmendCount(); + }; + + if (!funcPrivateConnect(addNodeRequest, checkNode)) { + delete node; + return false; + } + } + + return true; +} + +QHash<NP::BaseId, NP::NetworkNode *> +NetworkTestUtils::generateNetworkNode(int count) const { + + QHash<NP::BaseId, NP::NetworkNode *> result; + QSet<NP::NetworkNode *> tmp; + + auto deinit = [&tmp]() { + for (NP::NetworkNode * node : tmp) { + delete node; + } + tmp.clear(); + }; + + for (int i = 0; i < count; ++i) { + NP::NetworkNode *tmpNode = initNewNode(); + if (tmpNode) + tmp.insert(tmpNode); + } + + if (tmp.size() != count) { + deinit(); + return {}; + } + + for (NP::NetworkNode *node: tmp) { + if (!deployNewNode(node)) { + deinit(); + return {}; + } + } + + for (auto i : tmp) { + result.insert(i->nodeId(), i); + } + + auto check = [this, count](){ + return coreNode->confirmendCount() == count; + }; + + if (!funcPrivateConnect(nullptr, check)) { + deinit(); + return {}; + } + + result.insert(coreNode->nodeId(), coreNode); + + return result; +} + +int NetworkTestUtils::nextPort() const { + static int port = 0; + int baseTestPort = TEST_PORT + 1000; + return baseTestPort + port++; +} diff --git a/HeartTests/NetworkSpace/networktestutils.h b/HeartTests/NetworkSpace/networktestutils.h new file mode 100644 index 0000000..e50df43 --- /dev/null +++ b/HeartTests/NetworkSpace/networktestutils.h @@ -0,0 +1,29 @@ +#ifndef NETWORKTESTUTILS_H +#define NETWORKTESTUTILS_H + +#include <basetestutils.h> +namespace NP { +class NetworkNode; +class BaseId; +} + +class NetworkTestUtils: public BaseTestUtils +{ +public: + NetworkTestUtils(); + ~NetworkTestUtils(); + + bool deployNewNode(NP::NetworkNode* node) const; + QHash<NP::BaseId, NP::NetworkNode*> generateNetworkNode(int count) const; + + NP::NetworkNode *initNewNode() const; + +protected: + const NP::NetworkNode* getCoreNode(); +private: + int nextPort() const; + + NP::NetworkNode* coreNode = nullptr; +}; + +#endif // NETWORKTESTUTILS_H diff --git a/ProtocolTests/ProtocolTests.pro b/HeartTests/ProtocolTests.pro similarity index 100% rename from ProtocolTests/ProtocolTests.pro rename to HeartTests/ProtocolTests.pro diff --git a/HeartTests/tst_testprotockol.cpp b/HeartTests/tst_testprotockol.cpp new file mode 100644 index 0000000..7be3f29 --- /dev/null +++ b/HeartTests/tst_testprotockol.cpp @@ -0,0 +1,80 @@ +#include <QtTest> + +#if BUILD_LVL >= 0 +#include "abstractnodetest.h" +#endif +#if BUILD_LVL >= 1 +#include <basenodetest.h> +#include <networknodetest.h> +#endif +#if BUILD_LVL >= 2 +#endif + + +class testProtockol : public QObject +{ + Q_OBJECT + +private: + QList<Test*> _tests; + + +public: + testProtockol(); + + ~testProtockol(); + +private slots: + void initTestCase(); + void unitTests(); + +}; + +testProtockol::testProtockol() { + +#if BUILD_LVL >= 0 + _tests.push_back(new AbstractNodeTest); +#endif +#if BUILD_LVL >= 1 + _tests.push_back(new BaseNodeTest); +#endif +#if BUILD_LVL >= 2 + _tests.push_back(new NetworkNodeTest); +#endif +} + +testProtockol::~testProtockol() { + +} + +void testProtockol::initTestCase() { +} + +void testProtockol::unitTests() { + int argc =0; + char * argv[] = {nullptr}; + + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName("TestQNP"); + QCoreApplication::setOrganizationName("QuasarApp"); + + auto path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + + QDir(path).removeRecursively(); + + QTimer::singleShot(0, [&app, this]() { + + for (auto test : _tests ) { + test->test(); + delete test; + } + + app.exit(0); + }); + + app.exec(); +} + +QTEST_APPLESS_MAIN(testProtockol) + +#include "tst_testprotockol.moc" diff --git a/NetworkProtocol.pri b/NetworkProtocol.pri deleted file mode 100644 index 1210f1c..0000000 --- a/NetworkProtocol.pri +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (C) 2018 - 2019 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($$PWD/NetworkProtocol/NetworkProtocol.pri) diff --git a/NetworkProtocol.pro b/NetworkProtocol.pro deleted file mode 100644 index 536ada7..0000000 --- a/NetworkProtocol.pro +++ /dev/null @@ -1,16 +0,0 @@ -# -# Copyright (C) 2018 - 2019 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. -# - -TEMPLATE = subdirs -CONFIG += ordered - -SUBDIRS += \ - QuasarAppLib \ - NetworkProtocol \ - ProtocolTests \ - -QuasarAppLib.file = $$PWD/QuasarAppLib/QuasarApp.pro diff --git a/NetworkProtocol/CMakeLists.txt b/NetworkProtocol/CMakeLists.txt deleted file mode 100644 index 6bbdb5f..0000000 --- a/NetworkProtocol/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -# -# Copyright (C) 2018-2020 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. -# - -cmake_minimum_required(VERSION 3.1) - -project(NetworkProtocol LANGUAGES CXX) - -include(../QuasarAppLib/CMake/ProjectOut.cmake) -include(../QuasarAppLib/CMake/Version.cmake) - - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -find_package(Qt5 COMPONENTS Core Network Sql Concurrent REQUIRED) - -file(GLOB SOURCE_CPP - "*.cpp" "DataPacakages/*.cpp" -) - -add_library(${PROJECT_NAME} SHARED ${SOURCE_CPP}) -target_link_libraries(${PROJECT_NAME} PUBLIC Qt5::Core Qt5::Network Qt5::Sql Qt5::Concurrent QuasarApp crypto ssl) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/DataPacakages) - -setVersion(1 1 0) diff --git a/NetworkProtocol/DataPacakages/abstractdata.cpp b/NetworkProtocol/DataPacakages/abstractdata.cpp deleted file mode 100644 index 22f6fb7..0000000 --- a/NetworkProtocol/DataPacakages/abstractdata.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "abstractdata.h" -#include <QDataStream> -#include <QMap> -#include <typeinfo> -#include "networkprotocol.h" -#include <limits> - -namespace NP { - -unsigned int AbstractData::cmd() const { - return _cmd; -} - -AbstractData::AbstractData() { - _cmd = 0; -} - -bool AbstractData::fromBytes(const QByteArray &data) { - return StreamBase::fromBytes(data); -} - -QByteArray AbstractData::toBytes() const { - return StreamBase::toBytes(); -} - -bool AbstractData::toPackage(Package &package, - unsigned short trigeredCommand) const { - - if (!isValid()) { - return false; - } - - package.data = toBytes(); - - package.hdr.command = _cmd; - package.hdr.triggerCommnad = trigeredCommand; - package.hdr.size = static_cast<unsigned short>(package.data.size()); - - return package.isValid(); -} - -QDataStream &AbstractData::fromStream(QDataStream &stream) { - stream >> _cmd; - return stream; -} - -QDataStream &AbstractData::toStream(QDataStream &stream) const { - stream << _cmd; - return stream; -} - -bool AbstractData::isValid() const { - return _cmd; -} - -bool AbstractData::copyFrom(const AbstractData *other) { - return other; -} - -AbstractData::~AbstractData() { - -} - - -} diff --git a/NetworkProtocol/DataPacakages/abstractdata.h b/NetworkProtocol/DataPacakages/abstractdata.h deleted file mode 100644 index 838fe26..0000000 --- a/NetworkProtocol/DataPacakages/abstractdata.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef ABSTRACTDATA_H -#define ABSTRACTDATA_H -#include "package.h" -#include <streambase.h> - -#define INIT_COMMAND generateId<decltype (*this)>(); - -namespace NP { - -/** - * @brief The AbstractData class - * all data packages inherited this class. - */ -class NETWORKPROTOCOLSHARED_EXPORT AbstractData : public StreamBase -{ -private: - /** - * @brief _cmd - unique id of class using in Header of package for identification. - */ - unsigned short _cmd = 0; - -protected: - /** - * @brief AbstractData - */ - explicit AbstractData(); - - /** - * @brief fromBytes - private initialisation of object from byte array - * @return true if all good - */ - bool fromBytes(const QByteArray&); - - /** - * @brief generateId - * @return generate cmd function - */ - template<typename T> - void generateId() { - _cmd = qHash(typeid(T).name()) % std::numeric_limits<unsigned short>::max(); - } - -public: - - /** - * @brief cmd - * @return command of package - */ - unsigned int cmd() const; - - /** - * @brief toBytes - * @return byte array for package - */ - QByteArray toBytes() const; - - - /** - * @brief toPackage - * @param package - return value - * @param trigeredCommand - old cmd - * @return retorn package object created from this object. - */ - bool toPackage(Package &package, unsigned short trigeredCommand = 0) const; - - /** - * @brief fromStream - * @param stream - * @return stream - */ - QDataStream& fromStream(QDataStream& stream) override; - - /** - * @brief toStream - * @param stream - * @return stream - */ - QDataStream& toStream(QDataStream& stream) const override; - /** - * @brief isValid - * @return true if class isValid - */ - virtual bool isValid() const; - - /** - * @brief copyFrom this function try cast other object to this class type - * and invoke copy operation. cmd option is ignored; - * @param other - * @return true if all good - */ - virtual bool copyFrom(const AbstractData*); - - virtual ~AbstractData() override; - -}; - - -} - - -#endif // ABSTRACTDATA_H diff --git a/NetworkProtocol/DataPacakages/availabledata.cpp b/NetworkProtocol/DataPacakages/availabledata.cpp deleted file mode 100644 index 1a7a715..0000000 --- a/NetworkProtocol/DataPacakages/availabledata.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "availabledata.h" - -#include <QDataStream> - -namespace NP { - -AvailableData::AvailableData() { - INIT_COMMAND -} - -AvailableData::AvailableData(const Package &pkg):AvailableData() { - fromBytes(pkg.toBytes()); -} - -QDataStream &AvailableData::fromStream(QDataStream &stream) { - AbstractData::fromStream(stream); - stream >> _data; - return stream; -} - -QDataStream &AvailableData::toStream(QDataStream &stream) const { - AbstractData::toStream(stream); - stream << _data; - return stream; -} - -bool AvailableData::isValid() const { - return AbstractData::isValid() && _data.size(); -} - -QHash<QString, QList<int> > AvailableData::data() const { - return _data; -} - -void AvailableData::setData(const QHash<QString, QList<int> > &data) { - _data = data; -} - -QList<int>& AvailableData::operator[](const QString &key) { - return _data[key]; -} - -} - diff --git a/NetworkProtocol/DataPacakages/availabledata.h b/NetworkProtocol/DataPacakages/availabledata.h deleted file mode 100644 index 6b0b4df..0000000 --- a/NetworkProtocol/DataPacakages/availabledata.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef GETAVAILABLEDATA_H -#define GETAVAILABLEDATA_H - -#include "abstractdata.h" - -namespace NP { - -class NETWORKPROTOCOLSHARED_EXPORT AvailableData : public AbstractData -{ -public: - AvailableData(); - AvailableData(const Package& pkg); - - // StreamBase interface - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - // AbstractData interface - bool isValid() const; - - QHash<QString, QList<int> > data() const; - void setData(const QHash<QString, QList<int> > &data); - - QList<int>& operator[](const QString& key); - -private: - QHash<QString, QList<int>> _data; - - - -}; - -} -#endif // GETAVAILABLEDATA_H diff --git a/NetworkProtocol/DataPacakages/availabledatarequest.cpp b/NetworkProtocol/DataPacakages/availabledatarequest.cpp deleted file mode 100644 index a1d737e..0000000 --- a/NetworkProtocol/DataPacakages/availabledatarequest.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "availabledatarequest.h" -namespace NP { - -AvailableDataRequest::AvailableDataRequest() { - INIT_COMMAND -} - - -AvailableDataRequest::AvailableDataRequest(const Package &pkg):AvailableData(pkg) { - INIT_COMMAND -} -AccessToken AvailableDataRequest::token() const -{ - return _token; -} - -void AvailableDataRequest::setToken(const AccessToken &token) -{ - _token = token; -} - -QDataStream &AvailableDataRequest::fromStream(QDataStream &stream) { - AvailableData::fromStream(stream); - - stream >> _token; - - return stream; -} - -QDataStream &AvailableDataRequest::toStream(QDataStream &stream) const { - AvailableData::toStream(stream); - - stream << _token; - - return stream; -} - -} diff --git a/NetworkProtocol/DataPacakages/availabledatarequest.h b/NetworkProtocol/DataPacakages/availabledatarequest.h deleted file mode 100644 index 500c057..0000000 --- a/NetworkProtocol/DataPacakages/availabledatarequest.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef AVAILABLEDATAREQUEST_H -#define AVAILABLEDATAREQUEST_H - -#include "availabledata.h" - -#include <accesstoken.h> - - -namespace NP { - -class AvailableDataRequest :public AvailableData { -public: - AvailableDataRequest(); - AvailableDataRequest(const Package &pkg); - - void setData(const QHash<QString, QList<int> > &data) = delete; - AccessToken token() const; - void setToken(const AccessToken &token); - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - -private: - - AccessToken _token; - - -}; - -} - -#endif // AVAILABLEDATAREQUEST_H diff --git a/NetworkProtocol/DataPacakages/dbobject.cpp b/NetworkProtocol/DataPacakages/dbobject.cpp deleted file mode 100644 index 370148f..0000000 --- a/NetworkProtocol/DataPacakages/dbobject.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "dbobject.h" -#include "dbtablebase.h" -#include <QDataStream> -#include <QDateTime> -#include <QSqlQuery> -#include <QHash> -#include <QSqlRecord> -#include <QVariantMap> - -namespace NP { - -DBObject::DBObject(const QString &tableName) { - clear(); - _tableName = tableName; -} - -DBObject::~DBObject() { - -} - -QString DBObject::tableName() const { - return _tableName; -} - -void DBObject::setTableName(const QString &tableName) { - _tableName = tableName; -} - -bool DBObject::isCached() const { - return true; -} - -DbAddress DBObject::dbAddress() const { - return {tableName(), getId()}; -} - -bool DBObject::remove(QSqlQuery &q) { - QString queryString = "DELETE FROM %0 where id=" + QString::number(getId()); - queryString = queryString.arg(tableName()); - - if (!q.prepare(queryString)) { - return false; - } - - return q.exec(); -} - -QDataStream &DBObject::fromStream(QDataStream &stream) { - AbstractData::fromStream(stream); - - stream >> _tableName; - stream >> _id; - return stream; -} - -QDataStream &DBObject::toStream(QDataStream &stream) const { - AbstractData::toStream(stream); - - stream << _tableName; - stream << _id; - return stream; -} - -bool DBObject::isValid() const { - return AbstractData::isValid() && _tableName.size(); -} - -bool DBObject::copyFrom(const AbstractData * other) { - if (!AbstractData::copyFrom(other)) - return false; - - auto otherObject = dynamic_cast<const DBObject*>(other); - if (!otherObject) - return false; - - this->_tableName = otherObject->_tableName; - this->_id = otherObject->_id; - - return true; -} - -int DBObject::getId() const { - return _id; -} - -void DBObject::setId(int id) { - _id = id; -} - -void DBObject::clear() { - _id = -1; -} - -} diff --git a/NetworkProtocol/DataPacakages/dbobject.h b/NetworkProtocol/DataPacakages/dbobject.h deleted file mode 100644 index 1040b66..0000000 --- a/NetworkProtocol/DataPacakages/dbobject.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef DBOBJECT_H -#define DBOBJECT_H -#include <QVariantMap> -#include <dbtablebase.h> -#include "abstractdata.h" -#include "networkprotocol_global.h" -#include "dbaddress.h" -#include "defines.h" - -class QSqlQuery; - -namespace NP { - -/** - * @brief The DBObject class - */ -class NETWORKPROTOCOLSHARED_EXPORT DBObject : public AbstractData -{ -public: - /** - * @brief DBObject - */ - DBObject(const QString& tableName); - - ~DBObject() override; - - //// AbstractData interface - bool isValid() const override; - bool copyFrom(const AbstractData *) override; - - /** - * @brief getId - * @return id of objcet - */ - int getId() const; - - /** - * @brief getId - * @return id of objcet - */ - void setId(int); - - /** - * @brief clear - */ - virtual void clear(); - - QString tableName() const; - - void setTableName(const QString &tableName); - - /** - * @brief factory - * @return self object pointer - */ - virtual SP<DBObject> factory() = 0; - - virtual bool select(QSqlQuery& q) = 0; - virtual bool save(QSqlQuery& q) = 0; - virtual bool remove(QSqlQuery& q) = 0; - virtual bool isCached() const; - - DbAddress dbAddress() const; - - -protected: - - QString _tableName; - int _id = -1; - - //// StreamBase interface - QDataStream &fromStream(QDataStream &stream) override; - QDataStream &toStream(QDataStream &stream) const override; - -}; -} - - -#endif // DBOBJECT_H diff --git a/NetworkProtocol/DataPacakages/dbobjectquery.cpp b/NetworkProtocol/DataPacakages/dbobjectquery.cpp deleted file mode 100644 index a70c47b..0000000 --- a/NetworkProtocol/DataPacakages/dbobjectquery.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "dbobjectquery.h" - -#include <QDataStream> - -namespace NP { - -DBObjectQuery::DBObjectQuery(const QString& table): - DBObject(table) { - -} - -short DBObjectQuery::updateIntervalSec() const { - return _updateIntervalSec; -} - -void DBObjectQuery::setUpdateIntervalSec(short updateIntervalSec) { - _updateIntervalSec = updateIntervalSec; -} - -QDataStream &DBObjectQuery::fromStream(QDataStream &stream) { - DBObject::fromStream(stream); - stream >> _updateIntervalSec; - return stream; -} - -QDataStream &DBObjectQuery::toStream(QDataStream &stream) const { - DBObject::toStream(stream); - stream << _updateIntervalSec; - return stream; -} - -bool DBObjectQuery::isCached() const { - return false; -} - -bool DBObjectQuery::isUpdateAllowed() { - int current = static_cast<int>(time(nullptr)); - bool result = _lastUpdateSec + _updateIntervalSec < current; - - _lastUpdateSec = current; - - return result; -} -} diff --git a/NetworkProtocol/DataPacakages/dbobjectquery.h b/NetworkProtocol/DataPacakages/dbobjectquery.h deleted file mode 100644 index b2b8d17..0000000 --- a/NetworkProtocol/DataPacakages/dbobjectquery.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef DBOBJECTQUERY_H -#define DBOBJECTQUERY_H - -#include "dbobject.h" - -namespace NP { - -class NETWORKPROTOCOLSHARED_EXPORT DBObjectQuery : public DBObject -{ -public: - DBObjectQuery(const QString& table); - - short updateIntervalSec() const; - void setUpdateIntervalSec(short updateIntervalSec); - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - bool isCached() const; - -protected: - bool isUpdateAllowed(); - -private: - short _updateIntervalSec = 0; - int _lastUpdateSec = 0; - - -}; - -} -#endif // DBOBJECTQUERY_H diff --git a/NetworkProtocol/DataPacakages/ratingtable.cpp b/NetworkProtocol/DataPacakages/ratingtable.cpp deleted file mode 100644 index 5d0a74b..0000000 --- a/NetworkProtocol/DataPacakages/ratingtable.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "ratingtable.h" - -#include <QDataStream> -#include <QSharedPointer> -#include <QSqlQuery> - -namespace NP { - -int RatingTable::id = 0; -QString RatingTable::table = "users"; - - -RatingTable::RatingTable():DBObjectQuery(table) { - INIT_COMMAND - setId(id); -} -RatingTable::RatingTable(const Package &package):RatingTable() { - fromBytes(package.data); -} - -QDataStream &RatingTable::fromStream(QDataStream &stream) { - DBObjectQuery::fromStream(stream); - - stream >> _data; - - return stream; -} - -QDataStream &RatingTable::toStream(QDataStream &stream) const { - DBObjectQuery::toStream(stream); - - stream << _data; - - return stream; -} - -SP<DBObject> RatingTable::factory() { - return SP<RatingTable>::create(); -} - -bool RatingTable::select(QSqlQuery &q) { - - if (!isUpdateAllowed()) { - return false; - } - - QString query; - - query = "SELECT name, points from '" + tableName() + - " ORDER BY points LIMIT 32000"; - - if (!q.prepare(query)) - return false; - - if (!q.exec()) - return false; - - _data.clear(); - - short number = 0; - while (q.next()) { - UserRecord rec; - - rec.setName(q.value("name").toString()); - rec.setRecord(static_cast<short>(q.value("points").toInt())); - - _data.insert(++number, rec); - } - return isValid(); -} - -bool RatingTable::save(QSqlQuery &) { - return true; -} - -bool RatingTable::remove(QSqlQuery &) { - return true; -} - -bool RatingTable::isValid() const { - return _data.size(); -} - -void RatingTable::clear() { - _data.clear(); - - DBObjectQuery::clear(); - -} - -const QMap<short, UserRecord>& RatingTable::data() const { - return _data; -} - -DbAddress RatingTable::getDBAddress() { - return {table, id}; -} - -} - diff --git a/NetworkProtocol/DataPacakages/ratingtable.h b/NetworkProtocol/DataPacakages/ratingtable.h deleted file mode 100644 index a0202d0..0000000 --- a/NetworkProtocol/DataPacakages/ratingtable.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef RATINGTABLE_H -#define RATINGTABLE_H - -#include "dbobjectquery.h" -#include "userrecord.h" - - -namespace NP { - -class NETWORKPROTOCOLSHARED_EXPORT RatingTable : public DBObjectQuery -{ -public: - RatingTable(); - RatingTable(const Package& package); - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - SP<DBObject> factory(); - bool select(QSqlQuery &q); - bool save(QSqlQuery &q); - bool remove(QSqlQuery &q); - - bool isValid() const; - void clear(); - - const QMap<short, UserRecord> &data() const; - - static QString table; - static int id; - static DbAddress getDBAddress(); - -private: - QMap<short, UserRecord> _data; - -}; -} -#endif // RATINGTABLE_H diff --git a/NetworkProtocol/DataPacakages/request.cpp b/NetworkProtocol/DataPacakages/request.cpp deleted file mode 100644 index 9a63b04..0000000 --- a/NetworkProtocol/DataPacakages/request.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "request.h" -namespace NP { - -Request::Request() { - -} - -unsigned char Request::getRequestCmd() const { - return requestCmd; -} - -void Request::setRequestCmd(unsigned char value) { - requestCmd = value; -} - -} diff --git a/NetworkProtocol/DataPacakages/request.h b/NetworkProtocol/DataPacakages/request.h deleted file mode 100644 index 01bf00d..0000000 --- a/NetworkProtocol/DataPacakages/request.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef IREQUEST_H -#define IREQUEST_H - -namespace NP { - -class Request -{ -public: - Request(); - unsigned char getRequestCmd() const; - void setRequestCmd(unsigned char value); - -protected: - unsigned char requestCmd = 0; - -}; -} -#endif // IREQUEST_H diff --git a/NetworkProtocol/DataPacakages/transportdata.cpp b/NetworkProtocol/DataPacakages/transportdata.cpp deleted file mode 100644 index de04ab7..0000000 --- a/NetworkProtocol/DataPacakages/transportdata.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "transportdata.h" -namespace NP { - -TransportData::TransportData() { - INIT_COMMAND - -} - -TransportData::TransportData(const Package &package):TransportData() { - fromBytes(package.data); - -} - -const Package &TransportData::data() const { - return _data; -} - -void TransportData::setData(const Package &data) { - _data = data; -} - -QHostAddress TransportData::address() const { - return _address; -} - -void TransportData::setAddress(const QHostAddress &address) { - _address = address; -} - -QDataStream &TransportData::fromStream(QDataStream &stream) { - stream >> _address; - QByteArray array; - stream >> array; - _data.fromBytes(array); - - return stream; -} - -QDataStream &TransportData::toStream(QDataStream &stream) const { - stream << _address; - stream << _data.toBytes(); - - return stream; -} - -bool TransportData::isValid() const { - return !_address.isNull() && _data.isValid(); -} -} diff --git a/NetworkProtocol/DataPacakages/transportdata.h b/NetworkProtocol/DataPacakages/transportdata.h deleted file mode 100644 index 9b91a4d..0000000 --- a/NetworkProtocol/DataPacakages/transportdata.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef TRANSPORTDATA_H -#define TRANSPORTDATA_H - -#include "abstractdata.h" - -#include <QHostAddress> - - -namespace NP { - -class NETWORKPROTOCOLSHARED_EXPORT TransportData: public AbstractData -{ - -public: - TransportData(); - TransportData(const Package& package); - - const Package& data() const; - void setData(const Package &data); - - QHostAddress address() const; - void setAddress(const QHostAddress &address); - - bool isValid() const; - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; -private: - Package _data; - QHostAddress _address; - - -}; - -} -#endif // TRANSPORTDATA_H diff --git a/NetworkProtocol/DataPacakages/userdata.cpp b/NetworkProtocol/DataPacakages/userdata.cpp deleted file mode 100644 index 1fcfe88..0000000 --- a/NetworkProtocol/DataPacakages/userdata.cpp +++ /dev/null @@ -1,235 +0,0 @@ -#include "userdata.h" - -#include <QDataStream> -#include <QSharedPointer> -#include <QSqlQuery> - -namespace NP { - -UserData::UserData(): - DBObject("users") { - clear(); - INIT_COMMAND - -} - -UserData::UserData(const Package &package): UserData() { - fromBytes(package.data); -} - -UserData::~UserData() { - -} - -QString UserData::name() const { - return _name; -} - -void UserData::setName(const QString &name) { - _name = name; -} - -QString UserData::passSHA256() const { - return _passSHA256; -} - -void UserData::setPassSHA256(const QString &passSHA256) { - _passSHA256 = passSHA256; -} - -QString UserData::mail() const { - return _mail; -} - -void UserData::setMail(const QString &mail) { - _mail = mail; -} - -int UserData::lastOnline() const { - return _lastOnline; -} - -void UserData::setLastOnline(int lastOnline) { - _lastOnline = lastOnline; -} - -int UserData::onlineTime() const { - return _onlineTime; -} - -void UserData::setOnlineTime(int onlineTime) { - _onlineTime = onlineTime; -} - -QVariantMap UserData::extraData() const { - return _extraData; -} - -QVariantMap &UserData::extraData() { - return _extraData; -} - -void UserData::setExtraData(const QVariantMap &extraData) { - _extraData = extraData; -} - -QDataStream &UserData::fromStream(QDataStream &stream) { - DBObject::fromStream(stream); - - stream >> _name; - stream >> _passSHA256; - stream >> _mail; - stream >> _lastOnline; - stream >> _onlineTime; - stream >> _extraData; - stream >> _token; - stream >> _points; - - return stream; -} - -QDataStream &UserData::toStream(QDataStream &stream) const { - DBObject::toStream(stream); - - stream << _name; - stream << _passSHA256; - stream << _mail; - stream << _lastOnline; - stream << _onlineTime; - stream << _extraData; - stream << _token; - stream << _points; - - return stream; -} - -bool UserData::select(QSqlQuery &q) { - QString query; - - if (getId() > 0) { - query = "SELECT * from '" + tableName() + - "' where id='" + QString::number(getId()) + "'"; - } else { - query = "SELECT * from '" + tableName() + - "' where gmail='" + QString::number(getId()) + "'"; - } - - if (!q.prepare(query)) - return false; - - if (!q.exec()) - return false; - - if (!q.next()) - return false; - - setId(q.value("id").toInt()); - _name = q.value("name").toString(); - _passSHA256 = q.value("pass").toString(); - _mail = q.value("gmail").toString(); - _lastOnline = q.value("lastOnline").toInt(); - _onlineTime = q.value("onlinetime").toInt(); - _points = q.value("points").toInt(); - - auto array = q.value("data").toByteArray(); - QDataStream s(&array, QIODevice::ReadWrite); - s >> _extraData; - - return isValid(); - -} - -bool UserData::save(QSqlQuery &q) { - - QString queryString = "INSERT INTO %0(%1) VALUES (%2)"; - - queryString = queryString.arg(tableName()); - - queryString = queryString.arg( - "name, pass, gmail, lastOnline, onlinetime, points, data"); - - QString values; - - values += "'" + _name + "', "; - values += "'" + _passSHA256 + "', "; - values += "'" + _mail + "', "; - values += "'" + QString::number(_lastOnline) + "', "; - values += "'" + QString::number(_onlineTime) + "', "; - values += "'" + QString::number(_points) + "', "; - values += ":bytes"; - - if (!q.prepare(queryString)) { - return false; - } - - queryString = queryString.arg(values); - - QByteArray array; - QDataStream s(&array, QIODevice::ReadWrite); - s << _extraData; - - q.bindValue(":bytes", array); - - return q.exec(); -} - -bool UserData::remove(QSqlQuery &q) { - return DBObject::remove(q); -} - -void UserData::clear() { - _name = ""; - _passSHA256 = ""; - _mail = ""; - _lastOnline = 0; - _onlineTime = 0; - _extraData = {}; - _points = 0; - - DBObject::clear(); -} - -bool UserData::isValid() const { - return DBObject::isValid() && _mail.size(); -} - -SP<DBObject> UserData::factory() { - return SP<UserData>::create(); -} - -const AccessToken &UserData::token() const { - return _token; -} - -void UserData::setToken(const AccessToken &token) { - _token = token; -} - -bool UserData::copyFrom(const AbstractData * other) { - if (!DBObject::copyFrom(other)) - return false; - - auto otherUser = dynamic_cast<const UserData*>(other); - if (!otherUser) - return false; - - this->_name = otherUser->_name; - this->_passSHA256 = otherUser->_passSHA256; - this->_mail = otherUser->_mail; - this->_lastOnline = otherUser->_lastOnline; - this->_onlineTime = otherUser->_onlineTime; - this->_extraData = otherUser->_extraData; - this->_points = otherUser->_points; - - return true; -} - -int UserData::points() const { - return _points; -} - -void UserData::setPoints(int points) { - _points = points; -} - -} diff --git a/NetworkProtocol/DataPacakages/userdata.h b/NetworkProtocol/DataPacakages/userdata.h deleted file mode 100644 index f6d09bb..0000000 --- a/NetworkProtocol/DataPacakages/userdata.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef USERDATA_H -#define USERDATA_H - -#include "dbobject.h" - -#include <accesstoken.h> - -namespace NP { - -/** - * @brief The UserData class - is default implementation of users items of database - */ -class NETWORKPROTOCOLSHARED_EXPORT UserData : public DBObject -{ -public: - UserData(); - UserData(const Package& package); - - ~UserData() override; - QString name() const; - void setName(const QString &name); - - QString passSHA256() const; - void setPassSHA256(const QString &passSHA256); - - QString mail() const; - void setMail(const QString &mail); - - int lastOnline() const; - void setLastOnline(int lastOnline); - - int onlineTime() const; - void setOnlineTime(int onlineTime); - - QVariantMap extraData() const; - QVariantMap& extraData(); - - void setExtraData(const QVariantMap &extraData); - - // StreamBase interface - QDataStream &fromStream(QDataStream &stream) override; - QDataStream &toStream(QDataStream &stream) const override; - - bool select(QSqlQuery &q) override; - bool save(QSqlQuery &q) override; - bool remove(QSqlQuery &q) override; - - void clear() override; - bool isValid() const override; - SP<DBObject> factory() override; - - - const AccessToken& token() const; - void setToken(const AccessToken &token); - bool copyFrom(const AbstractData *) override; - - int points() const; - void setPoints(int points); - -protected: - QString _name; - QString _passSHA256; - QString _mail; - int _lastOnline; // unix time - int _onlineTime; // unix time - int _points; - - QVariantMap _extraData; - AccessToken _token; - - -}; - -} - -#endif // USERDATA_H diff --git a/NetworkProtocol/DataPacakages/userdatarequest.cpp b/NetworkProtocol/DataPacakages/userdatarequest.cpp deleted file mode 100644 index 6aa02e7..0000000 --- a/NetworkProtocol/DataPacakages/userdatarequest.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "userdatarequest.h" - -#include <QDataStream> - -namespace NP { - -UserDataRequest::UserDataRequest() - : UserData() { - INIT_COMMAND - -} - -UserDataRequest::UserDataRequest(const Package &package): - UserDataRequest() { - fromBytes(package.data); -} - -QDataStream &UserDataRequest::fromStream(QDataStream &stream) { - UserData::fromStream(stream); - stream >> requestCmd; - - return stream; -} - -QDataStream &UserDataRequest::toStream(QDataStream &stream) const { - UserData::toStream(stream); - stream << requestCmd; - - return stream; -} - -bool UserDataRequest::isValid() const { - return UserData::isValid() && - requestCmd > static_cast<unsigned char>(UserDataRequestCmd::Invalid) && - requestCmd <= static_cast<unsigned char>(UserDataRequestCmd::Delete); -} - -void UserDataRequest::clear() { - UserData::clear(); - requestCmd = static_cast<unsigned char>(UserDataRequestCmd::Invalid); -} -} diff --git a/NetworkProtocol/DataPacakages/userdatarequest.h b/NetworkProtocol/DataPacakages/userdatarequest.h deleted file mode 100644 index c463f7a..0000000 --- a/NetworkProtocol/DataPacakages/userdatarequest.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef USERDATAREQUEST_H -#define USERDATAREQUEST_H - -#include "request.h" -#include "userdata.h" - - -namespace NP { - -enum class UserDataRequestCmd: unsigned char { - Invalid, - Get, - Login, - Save, - Delete -}; - -class NETWORKPROTOCOLSHARED_EXPORT UserDataRequest: public UserData, public Request -{ -public: - UserDataRequest(); - UserDataRequest(const Package& package); - - // StreamBase interface - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - // AbstractData interface - bool isValid() const; - - // DBObject interface - void clear(); - -}; - -} -#endif // USERDATAREQUEST_H diff --git a/NetworkProtocol/DataPacakages/userrecord.cpp b/NetworkProtocol/DataPacakages/userrecord.cpp deleted file mode 100644 index ce5ac81..0000000 --- a/NetworkProtocol/DataPacakages/userrecord.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "userrecord.h" - -#include <QDataStream> - -namespace NP { - - -UserRecord::UserRecord() -{ - INIT_COMMAND -} - -UserRecord::UserRecord(const Package &package): - UserRecord() { - fromBytes(package.data); -} - -QDataStream &NP::UserRecord::fromStream(QDataStream &stream) { - AbstractData::fromStream(stream); - stream >> name; - stream >> record; - return stream; -} - -QDataStream &NP::UserRecord::toStream(QDataStream &stream) const { - AbstractData::toStream(stream); - stream << name; - stream << record; - return stream; -} - -bool UserRecord::isValid() const { - return !name.isEmpty() && record > 0 && AbstractData::isValid(); -} - -QString UserRecord::getName() const { - return name; -} - -void UserRecord::setName(const QString &value) { - name = value; -} - -short UserRecord::getRecord() const { - return record; -} - -void UserRecord::setRecord(short value) { - record = value; -} - -} diff --git a/NetworkProtocol/DataPacakages/userrecord.h b/NetworkProtocol/DataPacakages/userrecord.h deleted file mode 100644 index d8e1db4..0000000 --- a/NetworkProtocol/DataPacakages/userrecord.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef USERRECORD_H -#define USERRECORD_H - -#include "abstractdata.h" - - -namespace NP { - -/** - * @brief The UserRecord class - * This is simple class for viewing minimal user information. - */ -class NETWORKPROTOCOLSHARED_EXPORT UserRecord : public AbstractData -{ -public: - UserRecord(); - UserRecord(const Package& package); - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - bool isValid() const; - - QString getName() const; - void setName(const QString &value); - - short getRecord() const; - void setRecord(short value); - -private: - QString name; - short record; -}; - -} - -#endif // USERRECORD_H diff --git a/NetworkProtocol/DataPacakages/websocket.cpp b/NetworkProtocol/DataPacakages/websocket.cpp deleted file mode 100644 index 7482f1b..0000000 --- a/NetworkProtocol/DataPacakages/websocket.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "websocket.h" - -#include <QDataStream> -#include <QSharedPointer> -namespace NP { - -WebSocket::WebSocket(): DBObject(""){ - INIT_COMMAND - -} - -WebSocket::WebSocket(const Package &package): - WebSocket() { - fromBytes(package.data); - -} - -QDataStream &WebSocket::fromStream(QDataStream &stream) { - DBObject::fromStream(stream); - return stream >> requestCmd; -} - -QDataStream &WebSocket::toStream(QDataStream &stream) const { - DBObject::toStream(stream); - return stream << requestCmd; -} - -bool WebSocket::isValid() const { - return requestCmd > static_cast<int>(WebSocketRequest::Invalied) - && AbstractData::isValid(); -} - -SP<DBObject> WebSocket::factory() {return {nullptr};} - -bool WebSocket::select(QSqlQuery &) { return false; } - -bool WebSocket::save(QSqlQuery &) { return false; } - -bool WebSocket::remove(QSqlQuery &) { return false; } - -} diff --git a/NetworkProtocol/DataPacakages/websocket.h b/NetworkProtocol/DataPacakages/websocket.h deleted file mode 100644 index 42c59ab..0000000 --- a/NetworkProtocol/DataPacakages/websocket.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef WEBSOCKET_H -#define WEBSOCKET_H - -#include "dbobject.h" -#include "request.h" - - -namespace NP { - -enum class WebSocketRequest { - Invalied = 0, - Subscribe = 1, - Unsubscribe = 2, - SubscribeList = 3 -}; - -class NETWORKPROTOCOLSHARED_EXPORT WebSocket: - public DBObject, public Request -{ -public: - WebSocket(); - WebSocket(const Package& package); - - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - bool isValid() const; - - SP<DBObject> factory(); - bool select(QSqlQuery &); - bool save(QSqlQuery &); - bool remove(QSqlQuery &); -}; - -} -#endif // WEBSOCKET_H diff --git a/NetworkProtocol/NetworkProtocol.pri b/NetworkProtocol/NetworkProtocol.pri deleted file mode 100644 index 978a1de..0000000 --- a/NetworkProtocol/NetworkProtocol.pri +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (C) 2018 - 2019 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. -# - -!isEmpty(NETWORKPROTOCOL_LIB):error("NetworkProtocol.pri already included") -NETWORKPROTOCOL_LIB = 1 - -#DEPENDS -CONFIG(release, debug|release): { - NETWORKPROTOCOL_LIB_OUTPUT_DIR="$$PWD/build/release" -} else { - NETWORKPROTOCOL_LIB_OUTPUT_DIR="$$PWD/build/debug" -} - -LIBS += -L$$NETWORKPROTOCOL_LIB_OUTPUT_DIR -lNetworkProtocol - -include($$PWD/NetworkProtocolIncludes.pri) - - - diff --git a/NetworkProtocol/NetworkProtocol.pro b/NetworkProtocol/NetworkProtocol.pro deleted file mode 100644 index 31ceaf1..0000000 --- a/NetworkProtocol/NetworkProtocol.pro +++ /dev/null @@ -1,122 +0,0 @@ -# -# Copyright (C) 2018 - 2019 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. -# - -#------------------------------------------------- -# -# Project created by QtCreator 2019-02-12T11:08:54 -# -#------------------------------------------------- - -QT -= gui -QT += network sql concurrent - -CONFIG += c++14 -TARGET = NetworkProtocol -TEMPLATE = lib - -DEFINES += NETWORKPROTOCOL_LIBRARY - -# The following define makes your compiler emit warnings if you use -# any feature of Qt which has been marked as deprecated (the exact warnings -# depend on your compiler). Please consult the documentation of the -# deprecated API in order to know how to port your code away from it. -DEFINES += QT_DEPRECATED_WARNINGS - -# You can also make your code fail to compile if you use deprecated APIs. -# In order to do so, uncomment the following line. -# You can also select to disable deprecated APIs only up to a certain version of Qt. -#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 - -CONFIG(release, debug|release): { - DESTDIR = $$PWD/build/release - -} else { - DESTDIR = $$PWD/build/debug -} - -SOURCES += \ - DataPacakages/abstractdata.cpp \ - DataPacakages/availabledata.cpp \ - DataPacakages/availabledatarequest.cpp \ - DataPacakages/badrequest.cpp \ - DataPacakages/dbobject.cpp \ - DataPacakages/dbobjectquery.cpp \ - DataPacakages/ratingtable.cpp \ - DataPacakages/request.cpp \ - DataPacakages/transportdata.cpp \ - DataPacakages/userdata.cpp \ - DataPacakages/userdatarequest.cpp \ - DataPacakages/userrecord.cpp \ - DataPacakages/websocket.cpp \ - DataPacakages/websocketsubscriptions.cpp \ - accesstoken.cpp \ - client.cpp \ - databaseaddress.cpp \ - dbaddress.cpp \ - dbobjectsfactory.cpp \ - dbtablebase.cpp \ - abstractnode.cpp \ - abstractnodeinfo.cpp \ - asyncsqldbwriter.cpp \ - basenode.cpp \ - basenodeinfo.cpp \ - header.cpp \ - iobjectprovider.cpp \ - networkprotocol.cpp \ - package.cpp \ - ratingusernode.cpp \ - sqldbcache.cpp \ - sqldbwriter.cpp \ - streambase.cpp \ - websocketcontroller.cpp \ - workstate.cpp - - -HEADERS += \ - DataPacakages/abstractdata.h \ - DataPacakages/availabledata.h \ - DataPacakages/availabledatarequest.h \ - DataPacakages/badrequest.h \ - DataPacakages/dbobject.h \ - DataPacakages/dbobjectquery.h \ - DataPacakages/ratingtable.h \ - DataPacakages/request.h \ - DataPacakages/transportdata.h \ - DataPacakages/userdata.h \ - DataPacakages/userdatarequest.h \ - DataPacakages/userrecord.h \ - DataPacakages/websocket.h \ - DataPacakages/websocketsubscriptions.h \ - accesstoken.h \ - client.h \ - databaseaddress.h \ - dbaddress.h \ - dbobjectsfactory.h \ - dbtablebase.h \ - abstractnode.h \ - abstractnodeinfo.h \ - asyncsqldbwriter.h \ - basenode.h \ - basenodeinfo.h \ - config.h \ - header.h \ - iobjectprovider.h \ - networkprotocol.h \ - networkprotocol_global.h \ - package.h \ - ratingusernode.h \ - sqldbcache.h \ - sqldbwriter.h \ - streambase.h \ - websocketcontroller.h \ - workstate.h \ - defines.h - -include($$PWD/NetworkProtocolIncludes.pri) - -RESOURCES += \ - ProtockolResusces.qrc diff --git a/NetworkProtocol/NetworkProtocolIncludes.pri b/NetworkProtocol/NetworkProtocolIncludes.pri deleted file mode 100644 index 2972695..0000000 --- a/NetworkProtocol/NetworkProtocolIncludes.pri +++ /dev/null @@ -1,7 +0,0 @@ -INCLUDEPATH += "$$PWD/" -INCLUDEPATH += "$$PWD/DataPacakages" -INCLUDEPATH += "$$PWD/Tables" - -LIBS += -L$$NETWORKPROTOCOL_LIB_OUTPUT_DIR -lcrypto - -include($$PWD/../QuasarAppLib/QuasarLib.pri) diff --git a/NetworkProtocol/ProtockolResusces.qrc b/NetworkProtocol/ProtockolResusces.qrc deleted file mode 100644 index 537f115..0000000 --- a/NetworkProtocol/ProtockolResusces.qrc +++ /dev/null @@ -1,6 +0,0 @@ -<RCC> - <qresource prefix="/sql"> - <file alias="default">Res/Default.sql</file> - <file alias="defaultConfig">Res/DefaultDbConfig.json</file> - </qresource> -</RCC> diff --git a/NetworkProtocol/Res/Default.sql b/NetworkProtocol/Res/Default.sql deleted file mode 100644 index 9248d71..0000000 --- a/NetworkProtocol/Res/Default.sql +++ /dev/null @@ -1,12 +0,0 @@ - -CREATE TABLE IF NOT EXISTS users( - id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - name VARCHAR(100) NOT NULL UNIQUE, - pass VARCHAR(32) DEFAULT NULL, - gmail VARCHAR(64) DEFAULT NULL UNIQUE, - lastOnline INTEGER NOT NULL DEFAULT 0, - onlinetime INTEGER NOT NULL DEFAULT 0, - points INTEGER NOT NULL DEFAULT 0, - data BLOB DEFAULT NULL - -); diff --git a/NetworkProtocol/abstractnode.cpp b/NetworkProtocol/abstractnode.cpp deleted file mode 100644 index 889a22f..0000000 --- a/NetworkProtocol/abstractnode.cpp +++ /dev/null @@ -1,617 +0,0 @@ -#include "abstractnode.h" -#include "workstate.h" -#include <QSslCertificate> -#include <QSslKey> -#include <QSslKey> -#include <QSslSocket> -#include <badrequest.h> -#include <quasarapp.h> -#include <openssl/rsa.h> -#include <openssl/x509.h> -#include <openssl/pem.h> - -namespace NP { - -AbstractNode::AbstractNode(SslMode mode, QObject *ptr): - QTcpServer(ptr) { - _mode = mode; - - setMode(_mode); -} - -bool AbstractNode::run(const QString &addres, unsigned short port) { - if (!listen(QHostAddress(addres), port)) { - QuasarAppUtils::Params::log("Run fail " + this->errorString(), - QuasarAppUtils::Error); - return false; - } - - return true; -} - -void AbstractNode::stop() { - close(); - - for (auto &&i : _connections) { - i.info->disconnect(); - } -} - -WP<AbstractNodeInfo> AbstractNode::getInfoPtr(const QHostAddress &id) { - if (!_connections.contains(id)) { - return {nullptr}; - } - - return _connections[id].info; -} - -AbstractNodeInfo AbstractNode::getInfo(const QHostAddress &id) const{ - auto info = _connections.value(id).info; - - if (info.isNull()) - return {}; - - return *_connections.value(id).info.get(); -} - -void AbstractNode::ban(const QHostAddress &target) { - - auto info = getInfoPtr(target); - - if (info.isNull()) - _connections[target] = NodeInfoData{}; - - _connections[target].info->ban(); -} - -void AbstractNode::unBan(const QHostAddress &target) { - if (!_connections.contains(target) || _connections[target].info.isNull()) { - return; - } - - _connections[target].info->unBan(); -} - -void AbstractNode::connectToHost(const QHostAddress &ip, unsigned short port, SslMode mode) { - QTcpSocket *socket; - if (mode == SslMode::NoSSL) { - socket = new QTcpSocket(nullptr); - } else { - socket = new QSslSocket(nullptr); - } - - registerSocket(socket, &ip); - socket->connectToHost(ip, port); -} - -unsigned short AbstractNode::port() const { - return serverPort(); -} - -QHostAddress AbstractNode::address() const { - return serverAddress(); -} - -AbstractNode::~AbstractNode() { - stop(); -} - -QSslConfiguration AbstractNode::getSslConfig() const { - return _ssl; -} - -bool AbstractNode::generateRSAforSSL(EVP_PKEY *pkey) const { - RSA * rsa = nullptr; - if (!pkey) { - return false; - } - - if (!RSA_generate_key_ex(rsa, 2048, nullptr, nullptr)) { - return false; - } - - q_check_ptr(rsa); - if (EVP_PKEY_assign_RSA(pkey, rsa) <= 0) - return false; - - return true; -} - -bool AbstractNode::generateSslDataPrivate(const SslSrtData &data, QSslCertificate& r_srt, QSslKey& r_key) { - - EVP_PKEY *pkey = EVP_PKEY_new(); - - if (!generateRSAforSSL(pkey)) { - return false; - } - - X509 * x509 = nullptr; - X509_NAME * name = nullptr; - BIO * bp_public = nullptr, * bp_private = nullptr; - const char *buffer = nullptr; - int size; - - x509 = X509_new(); - q_check_ptr(x509); - ASN1_INTEGER_set(X509_get_serialNumber(x509), 1); - X509_gmtime_adj(X509_get_notBefore(x509), 0); // not before current time - X509_gmtime_adj(X509_get_notAfter(x509), data.endTime); // not after a year from this point - X509_set_pubkey(x509, pkey); - name = X509_get_subject_name(x509); - q_check_ptr(name); - - unsigned char *C = reinterpret_cast<unsigned char *>(data.country.toLatin1().data()); - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, C, -1, -1, 0); - - unsigned char *O = reinterpret_cast<unsigned char *>(data.organization.toLatin1().data()); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, O, -1, -1, 0); - - unsigned char *CN = reinterpret_cast<unsigned char *>(data.commonName.toLatin1().data()); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, CN, -1, -1, 0); - - X509_set_issuer_name(x509, name); - X509_sign(x509, pkey, EVP_sha256()); - bp_private = BIO_new(BIO_s_mem()); - q_check_ptr(bp_private); - if(PEM_write_bio_PrivateKey(bp_private, pkey, nullptr, nullptr, 0, nullptr, nullptr) != 1) { - EVP_PKEY_free(pkey); - X509_free(x509); - BIO_free_all(bp_private); - qCritical("PEM_write_bio_PrivateKey"); - return false; - - } - - bp_public = BIO_new(BIO_s_mem()); - q_check_ptr(bp_public); - if(PEM_write_bio_X509(bp_public, x509) != 1){ - EVP_PKEY_free(pkey); - X509_free(x509); - BIO_free_all(bp_public); - BIO_free_all(bp_private); - qCritical("PEM_write_bio_PrivateKey"); - return false; - - } - - size = static_cast<int>(BIO_get_mem_data(bp_public, &buffer)); - q_check_ptr(buffer); - - r_srt = QSslCertificate(QByteArray(buffer, size)); - - if(r_srt.isNull()) { - EVP_PKEY_free(pkey); - X509_free(x509); - BIO_free_all(bp_public); - BIO_free_all(bp_private); - qCritical("Failed to generate a random client certificate"); - return false; - - } - - size = static_cast<int>(BIO_get_mem_data(bp_private, &buffer)); - q_check_ptr(buffer); - r_key = QSslKey(QByteArray(buffer, size), QSsl::Rsa); - if(r_key.isNull()) { - EVP_PKEY_free(pkey); - X509_free(x509); - BIO_free_all(bp_public); - BIO_free_all(bp_private); - qCritical("Failed to generate a random private key"); - return false; - - } - - EVP_PKEY_free(pkey); // this will also free the rsa key - X509_free(x509); - BIO_free_all(bp_public); - BIO_free_all(bp_private); - - return true; -} - -QSslConfiguration AbstractNode::selfSignedSslConfiguration() { - QSslConfiguration res = QSslConfiguration::defaultConfiguration(); - - QSslKey pkey; - QSslCertificate crt; - SslSrtData sslData; - - if (!generateSslDataPrivate(sslData, crt, pkey)) { - - QuasarAppUtils::Params::log("fail to create ssl certificate. node svitch to InitFromSystem mode", - QuasarAppUtils::Warning); - - return res; - } - - res.setPrivateKey(pkey); - res.setLocalCertificate(crt); - - return res; -} - -SP<AbstractNodeInfo> AbstractNode::createNodeInfo(QAbstractSocket *socket) const { - return SP<AbstractNodeInfo>::create(socket); -} - -bool AbstractNode::registerSocket(QAbstractSocket *socket, const QHostAddress* clientAddress) { - - if (connectionsCount() >= maxPendingConnections()) { - return false; - } - - auto info = createNodeInfo(socket); - - if (clientAddress) - _connections[*clientAddress] = {info, {}}; - else - _connections[info->id()] = {info, {}}; - - - connect(socket, &QAbstractSocket::readyRead, this, &AbstractNode::avelableBytes); - connect(socket, &QAbstractSocket::disconnected, this, &AbstractNode::handleDisconnected); - - return true; -} - -ParserResult AbstractNode::parsePackage(const Package &pkg, - const WP<AbstractNodeInfo> &sender) { - - auto senderPtr = sender.toStrongRef(); - - if (senderPtr.isNull() || !senderPtr->isValid()) { - QuasarAppUtils::Params::log("sender socket is not valid!", - QuasarAppUtils::Error); - changeTrust(senderPtr->id(), LOGICK_ERROOR); - return ParserResult::Error; - } - - if (!pkg.isValid()) { - QuasarAppUtils::Params::log("incomming package is not valid!", - QuasarAppUtils::Error); - changeTrust(senderPtr->id(), CRITICAL_ERROOR); - return ParserResult::Error; - } - - - - return ParserResult::NotProcessed; -} - -bool AbstractNode::sendPackage(const Package &pkg, QAbstractSocket *target) { - if (!pkg.isValid()) { - return false; - } - - if (!target || !target->isValid()) { - QuasarAppUtils::Params::log("destination server not valid!", - QuasarAppUtils::Error); - return false; - } - - if (!target->waitForConnected()) { - QuasarAppUtils::Params::log("no connected to server! " + target->errorString(), - QuasarAppUtils::Error); - return false; - } - - auto bytes = pkg.toBytes(); - bool sendet = bytes.size() == target->write(bytes); - - return sendet; -} - -bool AbstractNode::sendData(const WP<AbstractData> &resp, const QHostAddress &addere, - const Header *req) { - auto client = getInfoPtr(addere).toStrongRef(); - - if (client.isNull()) { - QuasarAppUtils::Params::log("Response not sent because client == null", - QuasarAppUtils::Error); - return false; - } - - auto responce = resp.toStrongRef(); - if (responce.isNull()) { - return false; - } - - Package pkg; - bool convert = false; - if (req) { - convert = responce->toPackage(pkg, req->command); - } else { - convert = responce->toPackage(pkg); - } - - if (!convert) { - QuasarAppUtils::Params::log("Response not sent because dont create package from object", - QuasarAppUtils::Error); - return false; - } - - - if (!sendPackage(pkg, client->sct())) { - QuasarAppUtils::Params::log("Response not sent!", - QuasarAppUtils::Error); - return false; - } - - return true; -} - -void AbstractNode::badRequest(const QHostAddress &address, const Header &req, - const QString msg) { - auto client = getInfoPtr(address).toStrongRef(); - - if (client.isNull()) { - - QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" - " because client == null", - QuasarAppUtils::Error); - return; - } - - if (!changeTrust(address, REQUEST_ERROR)) { - - QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" - " because trust not changed", - QuasarAppUtils::Error); - - return; - } - - auto bad = BadRequest(msg); - Package pcg; - - if (!bad.toPackage(pcg, req.command)) { - QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" - " because package not created", - QuasarAppUtils::Error); - } - - if (!sendPackage(pcg, client->sct())) { - - QuasarAppUtils::Params::log("Bad request detected, bud responce command not sendet!" - " because karma not changed", - QuasarAppUtils::Error); - return; - } - - QuasarAppUtils::Params::log("Bad request sendet to adderess: " + - client->sct()->peerAddress().toString(), - QuasarAppUtils::Info); -} - -WorkState AbstractNode::getWorkState() const { - WorkState state; - - state.setConnectionCount(connectionsCount()); - state.setMaxConnectionCount(maxPendingConnections()); - state.setBanedList(banedList()); - - return state; - -} - -QString AbstractNode::getWorkStateString() const { - if (isListening()) { - if (connectionsCount() >= maxPendingConnections()) - return "overload"; - else { - return "Work"; - } - } - - return "Not running"; -} - -QString AbstractNode::connectionState() const { - return QString("%0 / %1").arg(connectionsCount()).arg(maxPendingConnections()); -} - -QList<QHostAddress> AbstractNode::banedList() const { - QList<QHostAddress> list = {}; - for (auto i = _connections.begin(); i != _connections.end(); ++i) { - if (i.value().info->isBaned()) { - list.push_back(i.key()); - } - } - - return list; -} - -int AbstractNode::connectionsCount() const { - int count = 0; - for (auto i : _connections) { - if (i.info->sct()) { - if (!i.info->sct()->isValid()) { - QuasarAppUtils::Params::log("connection count, findet not valid socket", - QuasarAppUtils::Warning); - } - - count++; - } - } - return count; -} - -bool AbstractNode::isBaned(QAbstractSocket *socket) const { - auto info = getInfo(socket->peerAddress()); - - if (!info.isValid()) { - return false; - } - - return info.isBaned(); -} - -void AbstractNode::incomingConnection(qintptr handle) { - - if (_mode == SslMode::NoSSL) { - incomingTcp(handle); - } else { - incomingSsl(handle); - } -} - -bool AbstractNode::changeTrust(const QHostAddress &id, int diff) { - auto ptr = getInfoPtr(id).toStrongRef(); - if (ptr.isNull()) { - return false; - } - - auto objTrust = ptr->trust(); - - if (objTrust >= static_cast<int>(TrustNode::Undefined)) { - return false; - } - - if (objTrust <= static_cast<int>(TrustNode::Baned)) { - return false; - } - - ptr->setTrust(objTrust + diff); - return true; -} - -void AbstractNode::incomingSsl(qintptr socketDescriptor) { - QSslSocket *socket = new QSslSocket; - - socket->setSslConfiguration(_ssl); - - if (!isBaned(socket) && socket->setSocketDescriptor(socketDescriptor)) { - connect(socket, &QSslSocket::encrypted, [this, socket](){ - if (!registerSocket(socket)) { - socket->deleteLater(); - } - }); - - connect(socket, QOverload<const QList<QSslError> &>::of(&QSslSocket::sslErrors), - [socket](const QList<QSslError> &errors){ - - for (auto &error : errors) { - QuasarAppUtils::Params::log(error.errorString(), QuasarAppUtils::Error); - } - - socket->deleteLater(); - }); - - socket->startServerEncryption(); - } else { - delete socket; - } -} - -void AbstractNode::incomingTcp(qintptr socketDescriptor) { - QTcpSocket *socket = new QTcpSocket; - if (!isBaned(socket) && socket->setSocketDescriptor(socketDescriptor)) { - if (!registerSocket(socket)) { - delete socket; - } - } else { - delete socket; - } -} - - -void AbstractNode::avelableBytes() { - - auto client = dynamic_cast<QAbstractSocket*>(sender()); - - if (!client) { - return; - } - - auto id = client->peerAddress(); - - if (!_connections.contains(id)) { - return; - } - - auto &val = _connections[id]; - - auto array = client->readAll(); - if (val.pkg.hdr.isValid()) { - val.pkg.data.append(array); - - } else { - val.pkg.reset(); - - memcpy(&val.pkg.hdr, - array.data(), sizeof(Header)); - - val.pkg.data.append(array.mid(sizeof(Header))); - } - - if (val.pkg.isValid()) { - parsePackage(val.pkg, val.info); - } - - if (val.pkg.data.size() >= val.pkg.hdr.size) { - val.pkg.reset(); - } -} - -void AbstractNode::handleDisconnected() { - auto _sender = dynamic_cast<QTcpSocket*>(sender()); - - if (_sender) { - // log error - - auto ptr = getInfoPtr(_sender->peerAddress()).toStrongRef(); - if (!ptr.isNull()) { - ptr->disconnect(); - } else { - QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" - " address not valid", - QuasarAppUtils::Error); - } - return; - } - - QuasarAppUtils::Params::log("system error in void Server::handleDisconected()" - "dynamic_cast fail!", - QuasarAppUtils::Error); -} - -SslMode AbstractNode::getMode() const { - return _mode; -} - -bool AbstractNode::setMode(const SslMode &mode) { - - if (_mode == mode) { - return true; - } - - if (isListening()) { - return false; - } - - _mode = mode; - - switch (_mode) { - case SslMode::InitFromSystem: { - _ssl = QSslConfiguration::defaultConfiguration(); - break; - - } - case SslMode::InitSelfSigned: { - _ssl = selfSignedSslConfiguration(); - break; - - } - default: { - _ssl = QSslConfiguration(); - break; - } - - } - - return true; - -} - -} diff --git a/NetworkProtocol/abstractnode.h b/NetworkProtocol/abstractnode.h deleted file mode 100644 index 4bf6b3b..0000000 --- a/NetworkProtocol/abstractnode.h +++ /dev/null @@ -1,306 +0,0 @@ -#ifndef ABSTRACTNODE_H -#define ABSTRACTNODE_H - -#include "abstractnodeinfo.h" -#include "networkprotocol.h" -#include <openssl/evp.h> - -#include <QAbstractSocket> -#include <QSslConfiguration> -#include <QTcpServer> -#include "abstractdata.h" -#include "workstate.h" -#include "defines.h" - -class QSslCertificate; -class QSslKey; -class QSslConfiguration; - -namespace NP { - -/** - * @brief The ParserResult enum - * Error - parser detect a errorob package - * NotProcessed - the parser does not know what to do with the package or has not finished processing it. - * Processed - the parser finished processing correctly - */ -enum class ParserResult { - Error = 0, - NotProcessed = 1, - Processed = 2 -}; - -enum class SslMode { - NoSSL, - InitFromSystem, - InitSelfSigned -}; - -/** - * @brief The NodeInfoData struct - */ -struct NodeInfoData { - SP<AbstractNodeInfo> info; - Package pkg; -}; - -/** - * @brief The SslSrtData struct - */ -struct SslSrtData { - QString country = "BY"; - QString organization = "QuasarApp"; - QString commonName = "Dev"; - long long endTime = 31536000L; //1 year -}; - -#define CRITICAL_ERROOR -50 -#define LOGICK_ERROOR -20 -#define REQUEST_ERROR -5 - -class Abstract; - -/** - * @brief The AbstractNode class - */ -class AbstractNode : public QTcpServer -{ - Q_OBJECT - -public: - - /** - * @brief AbstractNode - * @param ssl - * @param ptr - */ - AbstractNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr); - - /** - * @brief run - * @param addres - * @param port - * @return - */ - virtual bool run(const QString& addres, unsigned short port); - - /** - * @brief stop stop this node - */ - virtual void stop(); - - /** - * @brief getInfo - * @param id of selected node - * @return pointer to information about node - */ - virtual WP<AbstractNodeInfo> getInfoPtr(const QHostAddress &id); - - /** - * @brief getInfo - * @param id peer adders - * @return information about Node - */ - virtual AbstractNodeInfo getInfo(const QHostAddress &id) const; - - /** - * @brief ban - * @param target id of ban node - */ - virtual void ban(const QHostAddress& target); - - /** - * @brief unBan - * @param target id of unban node - */ - virtual void unBan(const QHostAddress& target); - - /** - * @brief connectToHost - */ - virtual void connectToHost(const QHostAddress &ip, unsigned short port, SslMode mode = SslMode::NoSSL); - - /** - * @brief port - * @return current node port - */ - unsigned short port() const; - - /** - * @brief address - * @return return current adders - */ - QHostAddress address() const; - - /** - * @brief getSslConfig - * @return current ssl configuration on this nod - */ - QSslConfiguration getSslConfig() const; - - ~AbstractNode() override; - - SslMode getMode() const; - - /** - * @brief getWorkState - * @return - */ - virtual WorkState getWorkState() const; - - -protected: - - /** - * @brief generateRSAforSSL - * @param pkey - - * @return - */ - virtual bool generateRSAforSSL(EVP_PKEY* pkey) const; - - /** - * @brief generateSslData - generate new ssl data - * @param data - sign data - * @param r_srt - result srt - * @param r_key - result private key - * @return true if all good - */ - virtual bool generateSslDataPrivate(const SslSrtData& data, QSslCertificate& r_srt, QSslKey& r_key); - - /** - * @brief selfSignedSslConfiguration - * @return generate new keys and use it - */ - virtual QSslConfiguration selfSignedSslConfiguration(); - - /** - * @brief createNodeInfo - * @return nodeinfo for new connection - * override this metho for set your own nodeInfo objects; - */ - virtual SP<AbstractNodeInfo> createNodeInfo(QAbstractSocket *socket) const; - - /** - * @brief registerSocket - * @param socket - * @return - */ - virtual bool registerSocket(QAbstractSocket *socket, - const QHostAddress *clientAddress = nullptr); - - /** - * @brief parsePackage - * @param pkg - * @param sender - * @return item of ParserResult () - */ - virtual ParserResult parsePackage(const Package &pkg, const WP<AbstractNodeInfo> &sender); - - /** - * @brief sendPackage - * @param pkg - * @param target - * @return - */ - virtual bool sendPackage(const Package &pkg, QAbstractSocket *target); - - /** - * @brief sendResponse - * @param resp - * @param address - * @param req - * @return - */ - virtual bool sendData(const WP<AbstractData> &resp, const QHostAddress& addere, - const Header *req = nullptr); - - /** - * @brief badRequest - * @param address - * @param req - * @param msg - message of error - */ - virtual void badRequest(const QHostAddress &address, const Header &req, - const QString msg = ""); - - /** - * @brief getWorkStateString - * @return string of work state - */ - virtual QString getWorkStateString() const; - - /** - * @brief connectionState - * @return string with count users state - */ - virtual QString connectionState() const; - - /** - * @brief banedList - * @return list of baned nodes - */ - QList<QHostAddress> banedList() const; - - /** - * @brief connectionsCount - * @return - */ - int connectionsCount() const; - - /** - * @brief isBaned - * @param socket - * @return - */ - bool isBaned(QAbstractSocket* socket) const; - - /** - * @brief incomingConnection - * @param handle - */ - void incomingConnection(qintptr handle) override; - - /** - * @brief changeTrust change trust of connected node - * @param id - id of select node - * @param diff - * @return true if all good - */ - bool changeTrust(const QHostAddress& id, int diff); - - /** - * @brief incomingConnection for ssl sockets - * @param handle - handle of socket - */ - virtual void incomingSsl(qintptr handle); - - /** - * @brief incomingConnection for tcp sockets - * @param handle - handle of socket - */ - virtual void incomingTcp(qintptr handle); - - - /** - * @brief setMode - invoke this method befor run method - * @param mode - */ - bool setMode(const SslMode &mode); - - -private slots: - - void avelableBytes(); - void handleDisconnected(); - - -private: - SslMode _mode; - QSslConfiguration _ssl; - QHash<QHostAddress, NodeInfoData> _connections; - - friend class WebSocketController; - -}; -} -#endif // ABSTRACTNODE_H diff --git a/NetworkProtocol/abstractnodeinfo.cpp b/NetworkProtocol/abstractnodeinfo.cpp deleted file mode 100644 index ccf0d3b..0000000 --- a/NetworkProtocol/abstractnodeinfo.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "abstractnodeinfo.h" -#include <QHostAddress> -#include <QAbstractSocket> -#include <QDataStream> - -namespace NP { - -AbstractNodeInfo::AbstractNodeInfo(QAbstractSocket *sct) { - setSct(sct); -} - -AbstractNodeInfo::~AbstractNodeInfo() {} - -QAbstractSocket *AbstractNodeInfo::sct() const { - return _sct; -} - -void AbstractNodeInfo::disconnect() { - if (_sct) { - _sct->close(); - _sct->deleteLater(); - _sct = nullptr; - } -} - -QHostAddress AbstractNodeInfo::id() const { - if (_sct) - return (_sct->peerAddress()); - - return _id; -} - -void AbstractNodeInfo::ban() { - _trust = static_cast<int>(TrustNode::Baned); - disconnect(); -} - -bool AbstractNodeInfo::isBaned() const { - return _trust < 1; -} - -void AbstractNodeInfo::unBan() { - _trust = static_cast<int>(TrustNode::Restore); -} - -void AbstractNodeInfo::setSct(QAbstractSocket *sct) { - _sct = sct; - if (_sct) - _id = _sct->peerAddress(); -} - -int AbstractNodeInfo::trust() const { - return _trust; -} - -void AbstractNodeInfo::setTrust(int trust) { - _trust = trust; - - if (isBaned()) { - disconnect(); - } -} - -bool AbstractNodeInfo::isValid() const { - return _sct; -} - -QDataStream &AbstractNodeInfo::fromStream(QDataStream &stream) { - stream >> _id; - return stream; -} - -QDataStream &AbstractNodeInfo::toStream(QDataStream &stream) const { - stream << id(); - return stream; -} - -} diff --git a/NetworkProtocol/abstractnodeinfo.h b/NetworkProtocol/abstractnodeinfo.h deleted file mode 100644 index 792295c..0000000 --- a/NetworkProtocol/abstractnodeinfo.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef ABSTRACTNODEINFO_H -#define ABSTRACTNODEINFO_H -#include "networkprotocol_global.h" - -#include <QHostAddress> - - -class QAbstractSocket; -namespace NP { - -/** - * @brief The TrustNode enum - */ -enum class TrustNode: unsigned char { - Undefined = 0xFF, - Default = 100, - Restore = 20, - Baned = 0 -}; - -/** - * @brief The AbstractNodeInfo class - */ -class NETWORKPROTOCOLSHARED_EXPORT AbstractNodeInfo -{ - -public: - - /** - * @brief AbstractNodeInfo - * @param sct socket of connection - */ - AbstractNodeInfo(QAbstractSocket *sct = nullptr); - - /** - * @brief ~AbstractNodeInfo - */ - virtual ~AbstractNodeInfo(); - - /** - * @brief sct - * @return return socket of connection - */ - QAbstractSocket *sct() const; - - /** - * @brief disconnect disconnect from host - */ - virtual void disconnect(); - - /** - * @brief id - * @return unique id of socket - */ - virtual QHostAddress id() const; - - /** - * @brief ban this node - */ - virtual void ban(); - - /** - * @brief isBaned - * @return true if node baned - */ - virtual bool isBaned() const; - - /** - * @brief unBan - */ - virtual void unBan(); - - /** - * @brief trust - * @return rtust - */ - virtual int trust() const; - - /** - * @brief setTrust manual set value of trust - * @param trust - new value - */ - virtual void setTrust(int trust); - - /** - * @brief isValid - * @return true if all data valid - */ - virtual bool isValid() const; - - /** - * @brief fromStream - * @param stream - * @return stream - */ - virtual QDataStream& fromStream(QDataStream& stream); - - /** - * @brief toStream - * @param stream - * @return stream - */ - virtual QDataStream& toStream(QDataStream& stream) const; - -protected: - /** - * @brief setSct - * @param sct - */ - void setSct(QAbstractSocket *sct); - -private: - - QHostAddress _id; - QAbstractSocket *_sct = nullptr; - int _trust = static_cast<int>(TrustNode::Default); - -}; - -} -#endif // ABSTRACTNODEINFO_H diff --git a/NetworkProtocol/asyncsqldbwriter.cpp b/NetworkProtocol/asyncsqldbwriter.cpp deleted file mode 100644 index 2a0695c..0000000 --- a/NetworkProtocol/asyncsqldbwriter.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "asyncsqldbwriter.h" - -#include <QMetaMethod> -#include <QThread> -#include <dbobject.h> -#include <quasarapp.h> - -namespace NP { - - -AsyncSqlDbWriter::AsyncSqlDbWriter(QObject *ptr): - QObject(ptr) -{ - QThread *own = new QThread(this); - moveToThread(own); -} - -bool AsyncSqlDbWriter::saveObject(const WP<AbstractData>& saveObject) { - auto obj = saveObject.toStrongRef(); - auto z = obj.dynamicCast<DBObject>(); - return QMetaObject::invokeMethod(this, - "handleSaveObject", - Qt::QueuedConnection, - Q_ARG(SP<DBObject>, - z)); - -} - -bool AsyncSqlDbWriter::deleteObject(const WP<AbstractData>& deleteObject) { - return QMetaObject::invokeMethod(this, - "handleDeleteObject", - Qt::QueuedConnection, - Q_ARG(SP<DBObject>, - deleteObject.toStrongRef().dynamicCast<DBObject>())); -} - -void AsyncSqlDbWriter::handleSaveObject(SP<DBObject> saveObject) { - if (!SqlDBWriter::saveObject(saveObject)) { - QuasarAppUtils::Params::log("AsyncSqlDbWriter: save object fail!", - QuasarAppUtils::Error); - } -} - -void AsyncSqlDbWriter::handleDeleteObject(SP<DBObject> deleteObject) { - if (!SqlDBWriter::deleteObject(deleteObject)) { - QuasarAppUtils::Params::log("AsyncSqlDbWriter: delete object fail!", - QuasarAppUtils::Error); - } -} - -} diff --git a/NetworkProtocol/asyncsqldbwriter.h b/NetworkProtocol/asyncsqldbwriter.h deleted file mode 100644 index 232e47e..0000000 --- a/NetworkProtocol/asyncsqldbwriter.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ASYNCSQLDBWRITER_H -#define ASYNCSQLDBWRITER_H - -#include "sqldbwriter.h" - -namespace NP { - - -/** - * @brief The AsyncSqlDbWriter class some as SqlDBWriter bud run all commnad in own thread - */ -class AsyncSqlDbWriter :public QObject, public SqlDBWriter -{ - Q_OBJECT -public: - AsyncSqlDbWriter(QObject* ptr = nullptr); - - // iObjectProvider interface - bool saveObject(const WP<AbstractData> &saveObject) override; - bool deleteObject(const WP<AbstractData> & deleteObject) override; - -private slots: - void handleSaveObject(SP<DBObject> saveObject); - void handleDeleteObject(SP<DBObject> deleteObject); - -}; - -} -#endif // ASYNCSQLDBWRITER_H diff --git a/NetworkProtocol/basenode.cpp b/NetworkProtocol/basenode.cpp deleted file mode 100644 index 52242ac..0000000 --- a/NetworkProtocol/basenode.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include "accesstoken.h" -#include "basenode.h" -#include "basenodeinfo.h" -#include "sqldbcache.h" -#include "sqldbwriter.h" -#include "websocketcontroller.h" - -#include <badrequest.h> -#include <userdata.h> -#include <userdatarequest.h> -#include <quasarapp.h> -#include <transportdata.h> -#include <availabledatarequest.h> -#include <websocket.h> -#include <websocketsubscriptions.h> -#include <websocketcontroller.h> - -namespace NP { - -BaseNode::BaseNode(NP::SslMode mode, QObject *ptr): - AbstractNode(mode, ptr) { - - _webSocketWorker = new WebSocketController(this); -} - -bool BaseNode::intSqlDb(QString DBparamsFile, - SqlDBCache *cache, - SqlDBWriter *writer) { - - initDefaultDbObjects(cache, writer); - - QVariantMap params; - - if (DBparamsFile.isEmpty()) { - params = defaultDbParams(); - return _db->init(params); - } - - if (!_db->init(DBparamsFile)) { - return false; - } - - return true; -} - -bool BaseNode::isSqlInited() const { - return !_db.isNull(); -} - -bool BaseNode::run(const QString &addres, unsigned short port) { - if (!isSqlInited() && !intSqlDb()) { - return false; - } - - return AbstractNode::run(addres, port); -} - -BaseNode::~BaseNode() { - -} - -void BaseNode::initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer) { - if (!writer) { - writer = new SqlDBWriter(); - } - - if (!cache) { - cache = new SqlDBCache(); - } - - cache->setWriter(SP<SqlDBWriter>(writer)); - _db = SP<SqlDBCache>(cache); - - connect(_db.data(), &SqlDBCache::sigItemChanged, - _webSocketWorker, &WebSocketController::handleItemChanged); -} - -ParserResult BaseNode::parsePackage(const Package &pkg, - const WP<AbstractNodeInfo>& sender) { - auto parentResult = AbstractNode::parsePackage(pkg, sender); - if (parentResult != ParserResult::NotProcessed) { - return parentResult; - } - - auto strongSender = sender.toStrongRef(); - - if (BadRequest().cmd() == pkg.hdr.command) { - auto cmd = SP<BadRequest>::create(pkg); - emit requestError(cmd->err()); - emit incomingData(cmd, strongSender->id()); - - return ParserResult::Processed; - - } else if (TransportData().cmd() == pkg.hdr.command) { - auto cmd = SP<TransportData>::create(pkg); - - if (cmd->address() == serverAddress()) { - return parsePackage(cmd->data(), sender); - } - - auto receiver = getInfoPtr(cmd->address()).toStrongRef(); - - if (!receiver.isNull()) { - sendData(cmd, receiver->id()); - return ParserResult::Processed; - } - - return ParserResult::Processed; - - } else if (AvailableDataRequest().cmd() == pkg.hdr.command) { - auto cmd = SP<AvailableDataRequest>::create(pkg); - - if (!cmd->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - if (!workWithAvailableDataRequest(cmd, strongSender->id(), &pkg.hdr)) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - return ParserResult::Processed; - - - } else if (AvailableData().cmd() == pkg.hdr.command) { - auto obj = SP<AvailableData>::create(pkg); - if (!obj->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - emit incomingData(obj, strongSender->id()); - return ParserResult::Processed; - - } else if (WebSocket().cmd() == pkg.hdr.command) { - auto obj = SP<WebSocket>::create(pkg); - if (!obj->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - if (!workWithSubscribe(obj, strongSender->id())) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - return ParserResult::Processed; - - } else if (WebSocketSubscriptions().cmd() == pkg.hdr.command) { - auto obj = SP<WebSocketSubscriptions>::create(pkg); - if (!obj->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - emit incomingData(obj, strongSender->id()); - return ParserResult::Processed; - } - - return ParserResult::NotProcessed; - -} - -bool BaseNode::workWithAvailableDataRequest(const WP<AbstractData> &rec, - const QHostAddress &address, - const Header *rHeader) { - - auto obj = rec.toStrongRef(); - if (obj.isNull()) - return false; - - auto info = getInfoPtr(address).toStrongRef().dynamicCast<BaseNodeInfo>(); - if (info.isNull()) - return false; - - auto av = SP<AvailableData>::create(); - av->setData({}); - - return sendData(av, address, rHeader); - -} - -QString BaseNode::hashgenerator(const QByteArray &pass) { - return QCryptographicHash::hash( - QCryptographicHash::hash(pass, QCryptographicHash::Sha256) + "QuassarAppSoult", - QCryptographicHash::Sha256); -} - -SP<AbstractNodeInfo> BaseNode::createNodeInfo(QAbstractSocket *socket) const { - return SP<BaseNodeInfo>::create(socket); -} - -WP<SqlDBCache> BaseNode::db() const { - return _db; -} - -// TO-DO -bool BaseNode::workWithSubscribe(const WP<AbstractData> &rec, - const QHostAddress &address) { - - auto obj = rec.toStrongRef().dynamicCast<UserDataRequest>(); - if (obj.isNull()) - return false; - - auto info = getInfoPtr(address).toStrongRef(); - if (info.isNull()) - return false; - - auto _db = db().toStrongRef(); - - if (_db.isNull()) - return false; - - switch (static_cast<WebSocketRequest>(obj->getRequestCmd())) { - - case WebSocketRequest::Subscribe: { - return _webSocketWorker->subscribe(info, {obj->tableName(), obj->getId()}); - } - - case WebSocketRequest::Unsubscribe: { - _webSocketWorker->unsubscribe(info, {obj->tableName(), obj->getId()}); - return true; - } - - case WebSocketRequest::SubscribeList: { - - auto resp = SP<WebSocketSubscriptions>::create(); - resp->setAddresses(_webSocketWorker->list(info)); - - return sendData(resp, address); - } - - default: break; - } - - return false; -} - -QVariantMap BaseNode::defaultDbParams() const { - - return { - {"DBDriver", "QSQLITE"}, - {"DBFilePath", DEFAULT_DB_PATH}, - {"DBInitFile", DEFAULT_DB_INIT_FILE_PATH} - }; -} - -} - diff --git a/NetworkProtocol/basenode.h b/NetworkProtocol/basenode.h deleted file mode 100644 index 6c2bd29..0000000 --- a/NetworkProtocol/basenode.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef BASENODE_H -#define BASENODE_H - -#include "abstractnode.h" - -#include <dbobject.h> - -namespace NP { - -class SqlDBCache; -class SqlDBWriter; -class UserData; -class UserDataRequest; -class AvailableDataRequest; -class WebSocket; -class WebSocketController; -/** - * @brief The BaseNode class - base inplementation of nodes - */ -class BaseNode : public AbstractNode -{ - Q_OBJECT -public: - - /** - * @brief BaseNode - * @param mode - * @param ptr - */ - BaseNode(SslMode mode = SslMode::NoSSL, QObject * ptr = nullptr); - - /** - * @brief intSqlDb - this function init database of node - * @param DBparamsFile - path to json file with all patarams - * @param cache - new SqlDBCache object - * @param writer - new SqlDBWriter - * @return true if all good - */ - virtual bool intSqlDb( QString DBparamsFile = "", - SqlDBCache * cache = nullptr, - SqlDBWriter* writer = nullptr); - - /** - * @brief isSqlInited - * @return return true if intSqlDb invocked correctly; - */ - bool isSqlInited() const; - - /** - * @brief run server on address an port - * @param addres - * @param port - * @return recomendet befor invoke this method call the intSqlDb. - * If you skeap a call of intSqlDb method then data base inited with default parameters. - */ - bool run(const QString &addres, unsigned short port) override; - - ~BaseNode() override; - - /** - * @brief defaultDbParams - * @return - */ - virtual QVariantMap defaultDbParams() const; - -signals: - void incomingData(SP<AbstractData> pkg, - const QHostAddress& sender); - - void requestError(QString msg); - -protected: - - /** - * @brief initDefaultDbObjects create default cache and db writer if pointer is null - * @param cache - * @param writer - */ - void initDefaultDbObjects(SqlDBCache *cache, SqlDBWriter *writer); - - /** - * @brief parsePackage - * @param pkg - * @param sender - * @return - */ - ParserResult parsePackage(const Package &pkg, - const WP<AbstractNodeInfo> &sender) override; - - - /** - * @brief hashgenerator - * @param pass - */ - virtual QString hashgenerator(const QByteArray &pass); - - SP<AbstractNodeInfo> createNodeInfo(QAbstractSocket *socket) const override; - - WP<SqlDBCache> db() const; - - bool workWithSubscribe(const WP<AbstractData> &rec, - const QHostAddress &address); - -private: - SP<SqlDBCache> _db; - bool workWithAvailableDataRequest(const WP<AbstractData> &rec, - const QHostAddress &addere, - const Header *rHeader); - - WebSocketController *_webSocketWorker = nullptr; -}; - -} -#endif // BASENODE_H diff --git a/NetworkProtocol/basenodeinfo.cpp b/NetworkProtocol/basenodeinfo.cpp deleted file mode 100644 index 9b53da7..0000000 --- a/NetworkProtocol/basenodeinfo.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "basenodeinfo.h" -#include <QTcpSocket> -#include <QHostAddress> - -namespace NP { - -bool BaseNodeInfo::isValid() const { - return AbstractNodeInfo::isValid(); -} - -BaseNodeInfo::BaseNodeInfo(QAbstractSocket *tcp): - AbstractNodeInfo(tcp){} - -BaseNodeInfo::~BaseNodeInfo(){} - -const AccessToken &BaseNodeInfo::token() const { - return _token; -} - -void BaseNodeInfo::setToken(const AccessToken &token) { - _token = token; -} - -Permission BaseNodeInfo::permision(const QString &table, int id) const { - auto allTablePermision = _permision.value(table).value(-1); - auto itemPermision = _permision.value(table).value(id); - - return std::max(allTablePermision, itemPermision); -} - -void BaseNodeInfo::setPermision(const QString &table, int id, const Permission &permision) { - _permision[table][id] = permision; -} - -} diff --git a/NetworkProtocol/basenodeinfo.h b/NetworkProtocol/basenodeinfo.h deleted file mode 100644 index 51da56b..0000000 --- a/NetworkProtocol/basenodeinfo.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef CONNECTIONINFO_H -#define CONNECTIONINFO_H - -#include "abstractnodeinfo.h" -#include "accesstoken.h" -#include "networkprotocol_global.h" - -#include <QByteArray> - -class QAbstractSocket; -namespace NP { - -/** - * @brief The Permission enum - * permision to data in database - */ -enum class Permission { - NoPermission = 0x00, - Read = 0x01, - Write = 0x02, -}; - -/** - * @brief The BaseNodeInfo class with tocken support - */ -class NETWORKPROTOCOLSHARED_EXPORT BaseNodeInfo: public AbstractNodeInfo { - -public: - bool isValid() const override; - - explicit BaseNodeInfo(QAbstractSocket * tcp = nullptr); - ~BaseNodeInfo() override; - - /** - * @brief token - * @return token - */ - const AccessToken& token() const; - - /** - * @brief setToken - * @param token set token - */ - void setToken(const AccessToken &token); - - /** - * @brief permision return permision on table item of node - * @param table name of table - * @param id of item, - * @return return permision - */ - Permission permision(const QString& table, int id) const; - - /** - * @brief setPermision - set new permision for table object - * @param table - table of set permision - * @param id - id of object( set -1 if you need set permision for all items of table) - * @param permision new value of permision - */ - void setPermision(const QString& table, int id ,const Permission &permision); - -protected: - AccessToken _token; - QHash<QString, QHash<int, Permission>> _permision; - - -}; -} - -#endif // CONNECTIONINFO_H diff --git a/NetworkProtocol/client.cpp b/NetworkProtocol/client.cpp deleted file mode 100644 index 86e9b98..0000000 --- a/NetworkProtocol/client.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include "client.h" - -#include <userdata.h> -#include <userdatarequest.h> -namespace NP { - -Client::Client(const QHostAddress &address, unsigned short port) { - setHost(address, port); - - connect(this, &BaseNode::incomingData, - this, &Client::handleIncomingData, - Qt::DirectConnection); - - _user = SP<UserData>::create(); -} - -Client::Client(const QString &address, unsigned short port): - Client(QHostAddress(address), port){ -} - -bool Client::connectClient() { - connectToHost(_address, _port); - - auto info = getInfoPtr(_address).toStrongRef(); - - if (info.isNull()) { - return false; - } - - connect(info->sct(), &QAbstractSocket::stateChanged, - this, &Client::socketStateChanged); - - return true; - -} - -void Client::setHost(const QHostAddress &address, unsigned short port) { - _address = address; - _port = port; -} - -bool Client::login(const QString &userMail, const QByteArray &rawPath) { - auto user = SP<UserDataRequest>::create(); - user->setMail(userMail); - user->setPassSHA256(hashgenerator(rawPath)); - user->setRequestCmd(static_cast<quint8>(UserDataRequestCmd::Login)); - - - return _user->copyFrom(user.data()) && sendData(user, _address); -} - -bool Client::logout() { - _user->setToken(AccessToken()); - - if (status() == Logined) - setStatus(Online); - return !_user->token().isValid(); -} - -bool Client::syncUserData() { - if (_status == Status::Offline) { - return false; - } - - if (!_user->isValid()) { - return false; - } - - SP<UserDataRequest> request; - *request.dynamicCast<UserData>() = *_user; - request->setRequestCmd(static_cast<unsigned char>(UserDataRequestCmd::Save)); - - return sendData(request, _address); -} - -int Client::status() const { - return _status; -} - -QString Client::lastMessage() const { - return _lastMessage; -} - -void Client::handleIncomingData(SP<AbstractData> obj, - const QHostAddress&) { - - auto userData = obj.dynamicCast<UserData>(); - - if (userData.isNull()) { - return; - } - - if (_user->mail() == userData->mail() - && _user->passSHA256() == userData->passSHA256()) { - _user = userData; - setStatus(Status::Logined); - } - -} - -void Client::setLastMessage(QString lastMessage) { - if (_lastMessage == lastMessage) - return; - - _lastMessage = lastMessage; - emit lastMessageChanged(_lastMessage); -} - -void Client::socketStateChanged(QAbstractSocket::SocketState state) { - if (state < QAbstractSocket::ConnectedState) { - setStatus(Status::Offline); - - } else if (_status != Logined) { - setStatus(Status::Online); - } -} - -void Client::setStatus(Client::Status status) { - if (status != _status) { - _status = status; - emit statusChanged(_status); - } -} - -} diff --git a/NetworkProtocol/client.h b/NetworkProtocol/client.h deleted file mode 100644 index 9bde0c9..0000000 --- a/NetworkProtocol/client.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef CLIENT_H -#define CLIENT_H - -#include "basenode.h" -#include "ratingusernode.h" - -namespace NP { - - -class NETWORKPROTOCOLSHARED_EXPORT Client: public RatingUserNode -{ - Q_OBJECT - Q_PROPERTY(int status READ status NOTIFY statusChanged) - Q_PROPERTY(QString lastMessage READ lastMessage WRITE setLastMessage NOTIFY lastMessageChanged) - -public: - enum Status { - Offline, - Online, - Logined - }; - - explicit Client(const QHostAddress& address, unsigned short port); - explicit Client(const QString& address, unsigned short port); - - bool connectClient(); - void setHost(const QHostAddress& address, unsigned short port); - bool login(const QString& userMail, const QByteArray& rawPath); - bool logout(); - bool syncUserData(); - - Q_INVOKABLE int status() const; - Q_INVOKABLE QString lastMessage() const; - -private slots: - void handleIncomingData(SP<AbstractData> obj, const QHostAddress &); - void setLastMessage(QString lastMessage); - void socketStateChanged(QAbstractSocket::SocketState); - -private: - Status _status = Offline; - QHostAddress _address; - unsigned short _port; - - QString _lastMessage; - SP<UserData> _user; - - void setStatus(Status); - -signals: - void statusChanged(int status); - - void lastMessageChanged(QString lastMessage); -}; - -} - -#endif // CLIENT_H diff --git a/NetworkProtocol/config.h b/NetworkProtocol/config.h deleted file mode 100644 index acb6f18..0000000 --- a/NetworkProtocol/config.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H - -#define LOCAL_SNAKE_SERVER "127.0.0.1" - -#define DEFAULT_PORT 3090 - - -#define DEFAULT_DB_NAME "QtNetworkDB" -#define DEFAULT_DB_PATH QDir::homePath() + "/QtNetwork/" + DEFAULT_DB_NAME -#define DEFAULT_DB_INIT_FILE_PATH ":/sql/default" -#define DEFAULT_UPDATE_INTERVAL 3600000 // 1 hour - -#endif // CONFIG_H diff --git a/NetworkProtocol/databaseaddress.cpp b/NetworkProtocol/databaseaddress.cpp deleted file mode 100644 index 3a20f51..0000000 --- a/NetworkProtocol/databaseaddress.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "databaseaddress.h" -#include <QHash> - -namespace NP { - -uint qHash(const DataBaseAddress &item){ - return qHash(item.table + QString::number(item.id)); -} - -} diff --git a/NetworkProtocol/databaseaddress.h b/NetworkProtocol/databaseaddress.h deleted file mode 100644 index a9d2a80..0000000 --- a/NetworkProtocol/databaseaddress.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef DATABASEADDRESS_H -#define DATABASEADDRESS_H -#include "networkprotocol_global.h" -#include <QString> - -namespace NP { - -struct NETWORKPROTOCOLSHARED_EXPORT DataBaseAddress -{ - QString table; - int id; -}; - -uint qHash(const DataBaseAddress& item); - -} -#endif // DATABASEADDRESS_H diff --git a/NetworkProtocol/dbaddress.cpp b/NetworkProtocol/dbaddress.cpp deleted file mode 100644 index c6d3f0d..0000000 --- a/NetworkProtocol/dbaddress.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "dbaddress.h" -#include <QDataStream> -#include <QHash> - - -namespace NP { - -qint64 qHash(const DbAddress &address) { - qint64 res = address.id; - res <<= 32; - return res + qHash(address.table); -} - -DbAddress::DbAddress(const QString &address, int id) { - this->table = address; - this->id = id; -} - -bool operator==(const DbAddress & left, const DbAddress &other) { - return left.table == other.table && left.id == other.id; -} - -QDataStream &DbAddress::fromStream(QDataStream &stream) { - stream >> id; - stream >> table; - return stream; -} - -QDataStream &DbAddress::toStream(QDataStream &stream) const { - stream << id; - stream << table; - return stream; -} -} diff --git a/NetworkProtocol/dbaddress.h b/NetworkProtocol/dbaddress.h deleted file mode 100644 index 8d16d3a..0000000 --- a/NetworkProtocol/dbaddress.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef DBADDRESS_H -#define DBADDRESS_H - -#include "streambase.h" - - -namespace NP { - -class NETWORKPROTOCOLSHARED_EXPORT DbAddress : public StreamBase { - -public: - - DbAddress() = default; - DbAddress(const QString& address, int id); - - - QString table; - int id; - - QDataStream &fromStream(QDataStream &stream); - QDataStream &toStream(QDataStream &stream) const; - - friend bool operator== (const DbAddress& left, const DbAddress& other); -}; - -qint64 qHash(const DbAddress& address); - -} - - -#endif // DBADDRESS_H diff --git a/NetworkProtocol/dbobjectsfactory.cpp b/NetworkProtocol/dbobjectsfactory.cpp deleted file mode 100644 index 310a5a5..0000000 --- a/NetworkProtocol/dbobjectsfactory.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "dbobjectsfactory.h" - -#include <dbobject.h> - -namespace NP { - -DbObjectsFactory::DbObjectsFactory() { - -} - -SP<DBObject> DbObjectsFactory::factory(const QString & table) { - return instance()->_data.value(table)->factory(); -} - -DbObjectsFactory *DbObjectsFactory::instance() { - DbObjectsFactory * i = new DbObjectsFactory(); - return i; -} - -bool DbObjectsFactory::registerObject(const QString & key, SP<DBObject> obj) { - if (obj.isNull()) - return false; - - _data[key] = obj; - return true; -} - -} diff --git a/NetworkProtocol/dbobjectsfactory.h b/NetworkProtocol/dbobjectsfactory.h deleted file mode 100644 index cbea6f1..0000000 --- a/NetworkProtocol/dbobjectsfactory.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef DBOBJECTSFACTORY_H -#define DBOBJECTSFACTORY_H -#include "networkprotocol_global.h" - -#include <QSharedPointer> - -namespace NP { - -class DBObject; - -class NETWORKPROTOCOLSHARED_EXPORT DbObjectsFactory -{ -public: - static SP<DBObject> factory(const QString&); - static DbObjectsFactory* instance(); - bool registerObject(const QString&key, SP<DBObject> obj); - -private: - DbObjectsFactory(); - - QHash<QString, SP<DBObject>> _data; - -}; -} - -#endif // DBOBJECTSFACTORY_H diff --git a/NetworkProtocol/dbtablebase.cpp b/NetworkProtocol/dbtablebase.cpp deleted file mode 100644 index a7c9b67..0000000 --- a/NetworkProtocol/dbtablebase.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "dbtablebase.h" - -#include <QSet> - -namespace NP { - - -QString DbTableBase::lastIdQuery() const { - return QString("SELECT MAX(id) FROM " + name); -} - -bool DbTableBase::isInited() const { - return keys.size(); -} - -bool DbTableBase::isValid() const { - return name.size(); -} - -} diff --git a/NetworkProtocol/dbtablebase.h b/NetworkProtocol/dbtablebase.h deleted file mode 100644 index 8111797..0000000 --- a/NetworkProtocol/dbtablebase.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef DBTABLEBASE_H -#define DBTABLEBASE_H - -#include <QSet> -#include <QString> -#include <QVariantMap> - -#include "networkprotocol_global.h" - -namespace NP { - -class DBObject; - -/** - * @brief The DbTableBase class - */ -struct NETWORKPROTOCOLSHARED_EXPORT DbTableBase -{ - QString name; - QHash<QString, QVariant::Type> keys; - - /** - * @brief lastIdQuery - * @return - */ - QString lastIdQuery() const; - - /** - * @brief isInited - * @return - */ - bool isInited() const; - - /** - * @brief isValid - * @return - */ - bool isValid() const; - -}; -} - - - -#endif // DBTABLEBASE_H diff --git a/NetworkProtocol/defines.h b/NetworkProtocol/defines.h deleted file mode 100644 index f4bbaeb..0000000 --- a/NetworkProtocol/defines.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef DEFINES_H -#define DEFINES_H - -#define SP QSharedPointer -#define WP QWeakPointer - -#endif // DEFINES_H diff --git a/NetworkProtocol/header.cpp b/NetworkProtocol/header.cpp deleted file mode 100644 index 507aba9..0000000 --- a/NetworkProtocol/header.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "header.h" - -namespace NP { -Header::Header() { - reset(); -} - -bool Header::isValid() const { - - if (sizeof (*this) != 6) { - return false; - } - - return command && size; -} - -void Header::reset() { - size = 0; - command = 0; - triggerCommnad = 0; -} -} diff --git a/NetworkProtocol/header.h b/NetworkProtocol/header.h deleted file mode 100644 index 2a84b74..0000000 --- a/NetworkProtocol/header.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ABSTRACTHEADER_H -#define ABSTRACTHEADER_H -#include "networkprotocol_global.h" - -namespace NP { -/** - * @brief The Header struct 6 byte - */ -#pragma pack(push, 1) -struct NETWORKPROTOCOLSHARED_EXPORT Header { - /** - * @brief size - size of package data (not header) - */ - unsigned short size; - - /** - * @brief command of pacage - */ - unsigned short command; - - /** - * @brief command of pacage see Command (rquest from client) - * the server should write to which command it responds - */ - unsigned short triggerCommnad; - - /** - * @brief Header default constructor - */ - Header(); - ~Header() = default; - - /** - * @brief isValid - * @return true if header is valid - */ - bool isValid() const; - - - /** - * @brief reset - reset all data and set for header invalid status - */ - void reset(); -}; -#pragma pack(pop) - -} - - - -#endif // ABSTRACTHEADER_H diff --git a/NetworkProtocol/iobjectprovider.cpp b/NetworkProtocol/iobjectprovider.cpp deleted file mode 100644 index dac0bba..0000000 --- a/NetworkProtocol/iobjectprovider.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "iobjectprovider.h" -namespace NP { -iObjectProvider::iObjectProvider() = default; - -iObjectProvider::~iObjectProvider() = default; - -} diff --git a/NetworkProtocol/iobjectprovider.h b/NetworkProtocol/iobjectprovider.h deleted file mode 100644 index a7a59e9..0000000 --- a/NetworkProtocol/iobjectprovider.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef IOBJECTPROVIDER_H -#define IOBJECTPROVIDER_H -#include "networkprotocol_global.h" - -#include <QSharedPointer> -#include "defines.h" - -namespace NP { - -class DBObject; -class AbstractData; - -class NETWORKPROTOCOLSHARED_EXPORT iObjectProvider -{ -public: - iObjectProvider(); - virtual ~iObjectProvider(); - - /** - * @brief getObject - * obj - dbobject with own query of select. - * After the invoke this object well contain current data. - * @return - */ - virtual bool getObject(SP<DBObject>& obj) = 0; - - /** - * @brief saveObject - * @return - */ - virtual bool saveObject(const WP<AbstractData>& saveObject) = 0; - - /** - * @brief deleteObject - * @return - */ - virtual bool deleteObject(const WP<AbstractData>& saveObject) = 0; - -}; - -} -#endif // IOBJECTPROVIDER_H diff --git a/NetworkProtocol/networkprotocol.cpp b/NetworkProtocol/networkprotocol.cpp deleted file mode 100644 index 5a02626..0000000 --- a/NetworkProtocol/networkprotocol.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "networkprotocol.h" - -#include <QDataStream> -#include <QVariantMap> - -namespace NP { - -} diff --git a/NetworkProtocol/networkprotocol.h b/NetworkProtocol/networkprotocol.h deleted file mode 100644 index 5603fa8..0000000 --- a/NetworkProtocol/networkprotocol.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CLIENTPROTOCOL_H -#define CLIENTPROTOCOL_H - -#include "package.h" -#include "config.h" -#include "ratingtable.h" - -/** - * NP - Network protocol - * defirent values: - * SP - shared pointer - * WP - weak pointer - */ -namespace NP { -} - -#endif // CLIENTPROTOCOL_H diff --git a/NetworkProtocol/networkprotocol_global.h b/NetworkProtocol/networkprotocol_global.h deleted file mode 100644 index f596295..0000000 --- a/NetworkProtocol/networkprotocol_global.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CLIENTPROTOCOL_GLOBAL_H -#define CLIENTPROTOCOL_GLOBAL_H - -#include <QtCore/qglobal.h> -#include "defines.h" - -#if defined(NETWORKPROTOCOL_LIBRARY) -# define NETWORKPROTOCOLSHARED_EXPORT Q_DECL_EXPORT -#else -# define NETWORKPROTOCOLSHARED_EXPORT Q_DECL_IMPORT -#endif - -#endif // CLIENTPROTOCOL_GLOBAL_H diff --git a/NetworkProtocol/package.cpp b/NetworkProtocol/package.cpp deleted file mode 100644 index 21abb74..0000000 --- a/NetworkProtocol/package.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "abstractdata.h" -#include "package.h" - -namespace NP { - -Package::Package() { - reset(); -} - -bool Package::isValid() const { - if (!hdr.isValid()) { - return false; - } - - auto rawint = data.mid(0, sizeof (decltype (hdr.command))); - decltype (hdr.command) cmd; - memcpy(&cmd, rawint.data(), sizeof (cmd)); - - if (data.size() && hdr.command != cmd) { - std::reverse(rawint.begin(), rawint.end()); - memcpy(&cmd, rawint.data(), sizeof (cmd)); - - if (hdr.command != cmd) - return false; - } - - return hdr.size == data.size(); -} - -QByteArray Package::toBytes() const { - QByteArray res; - res.append(reinterpret_cast<char*>(const_cast<Header*>(&hdr)), - sizeof (hdr)); - - res.append(data); - return res; -} - -void Package::fromBytes(const QByteArray& array) { - reset(); - memcpy(&hdr, - array.data(), sizeof(Header)); - - data.append(array.mid(sizeof(Header))); -} - -void Package::reset() { - hdr.reset(); - data.clear(); -} - -} diff --git a/NetworkProtocol/ratingusernode.cpp b/NetworkProtocol/ratingusernode.cpp deleted file mode 100644 index 526101c..0000000 --- a/NetworkProtocol/ratingusernode.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include "basenodeinfo.h" -#include "ratingusernode.h" -#include "sqldbcache.h" - -#include <badrequest.h> -#include <userdatarequest.h> -#include <quasarapp.h> -#include <ratingtable.h> - -namespace NP { - -RatingUserNode::RatingUserNode() { - -} - -ParserResult RatingUserNode::parsePackage(const Package &pkg, - const WP<AbstractNodeInfo> &sender) { - - auto parentResult = BaseNode::parsePackage(pkg, sender); - if (parentResult != ParserResult::NotProcessed) { - return parentResult; - } - - auto strongSender = sender.toStrongRef(); - - if (UserDataRequest().cmd() == pkg.hdr.command) { - auto cmd = SP<UserDataRequest>::create(pkg); - - if (!cmd->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - if (!workWithUserRequest(cmd, strongSender->id(), &pkg.hdr)) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - return ParserResult::Processed; - - - } else if (UserData().cmd() == pkg.hdr.command) { - auto obj = SP<UserData>::create(pkg); - if (!obj->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - emit incomingData(obj, strongSender->id()); - return ParserResult::Processed; - - } else if (RatingTable().cmd() == pkg.hdr.command) { - - auto obj = SP<RatingTable>::create(pkg); - if (!obj->isValid()) { - badRequest(strongSender->id(), pkg.hdr); - return ParserResult::Error; - } - - emit incomingData(obj, strongSender->id()); - return ParserResult::Processed; - } - - return ParserResult::NotProcessed; - -} - -QVariantMap RatingUserNode::defaultDbParams() const { - return BaseNode::defaultDbParams(); -} - -// bug : user register with id -1 it is all permision to write into all users table. -bool RatingUserNode::registerNewUser(const WP<AbstractData>& user, - const QHostAddress& address) { - auto strongUser = user.toStrongRef().dynamicCast<UserData>(); - - if (strongUser.isNull()) { - return false; - } - - auto node = getInfoPtr(address).toStrongRef().dynamicCast<BaseNodeInfo>(); - if (node.isNull()) { - return false; - } - - AccessToken token = AccessToken(AccessToken::Day); - - strongUser->setToken(token); - node->setToken(token); - node->setPermision(strongUser->tableName(), strongUser->getId(), - Permission::Read | Permission::Write); - - auto _db = db().toStrongRef(); - - if (!_db->saveObject(user)) { - return false; - } - - return true; -} - -bool RatingUserNode::loginUser(const WP<AbstractData>& user, - const WP<AbstractData>& userdb, - const QHostAddress& address) { - auto strongUser = user.toStrongRef().dynamicCast<UserData>(); - - if (strongUser.isNull()) { - return false; - } - - auto node = getInfoPtr(address).toStrongRef().dynamicCast<BaseNodeInfo>(); - if (node.isNull()) { - return false; - } - - if (node->token().isValid()) { - - if (node->token() == strongUser->token()) { - node->setPermision(strongUser->tableName(), strongUser->getId(), - Permission::Read | Permission::Write); - return true; - } - } - - auto strongUserDB = userdb.toStrongRef().dynamicCast<UserData>(); - - if (!strongUserDB.isNull() && strongUserDB->isValid() ) { - if (strongUserDB->passSHA256() == strongUser->passSHA256()) { - node->setPermision(strongUser->tableName(), strongUser->getId(), - Permission::Read | Permission::Write); - return true; - } - } - - return false; -} - -bool RatingUserNode::workWithUserRequest(const WP<AbstractData> &rec, - const QHostAddress &addere, - const Header *rHeader) { - - auto request = rec.toStrongRef().dynamicCast<UserDataRequest>(); - - if (request.isNull()) - return false; - - if (!isListening()) { - return false; - } - - auto _db = db().toStrongRef(); - - if (_db.isNull()) { - QuasarAppUtils::Params::log("Server not inited (db is null)", - QuasarAppUtils::Error); - return false; - } - - switch (static_cast<UserDataRequestCmd>(request->getRequestCmd())) { - case UserDataRequestCmd::Get: { - - auto node = getInfoPtr(addere).toStrongRef().dynamicCast<BaseNodeInfo>(); - if (node.isNull()) { - return false; - } - - if (node->permision(request->tableName(), request->getId()) < Permission::Read) { - return false; - } - - auto res = SP<UserData>::create().dynamicCast<DBObject>(); - if (!_db->getObject(res)) { - return false; - } - - if (!sendData(res, addere, rHeader)) { - QuasarAppUtils::Params::log("responce not sendet to" + addere.toString(), - QuasarAppUtils::Warning); - return false; - } - break; - - } - - case UserDataRequestCmd::Save: { - - auto node = getInfoPtr(addere).toStrongRef().dynamicCast<BaseNodeInfo>(); - if (node.isNull()) { - return false; - } - - if (node->permision(request->tableName(), request->getId()) < Permission::Write) { - return false; - } - - if(!_db->saveObject(rec)) { - QuasarAppUtils::Params::log("do not saved object in database!" + addere.toString(), - QuasarAppUtils::Error); - return false; - } - - if (!sendData(rec, addere, rHeader)) { - QuasarAppUtils::Params::log("responce not sendet to" + addere.toString(), - QuasarAppUtils::Warning); - return false; - } - - break; - } - - // TODO - - case UserDataRequestCmd::Login: { - - auto res = SP<UserData>::create().dynamicCast<DBObject>(); - res->copyFrom(request.data()); - - if (_db->getObject(res)) { - // login oldUser - if (!loginUser(rec, res, addere)) { - return false; - } - } else { - // register a new user; - if (!registerNewUser(res, addere)) { - return false; - } - _db->getObject(res); - } - - if (!sendData(res, addere, rHeader)) { - QuasarAppUtils::Params::log("responce not sendet to" + addere.toString(), - QuasarAppUtils::Warning); - return false; - } - - break; - } - - case UserDataRequestCmd::Delete: { - - if(!_db->deleteObject(rec)) { - QuasarAppUtils::Params::log("do not deleted object from database!" + addere.toString(), - QuasarAppUtils::Error); - return false; - } - - - if (!sendData(rec, addere, rHeader)) { - QuasarAppUtils::Params::log("responce not sendet to" + addere.toString(), - QuasarAppUtils::Warning); - return false; - } - - break; - } - default: return false; - - } - - - return true; - -} - -} diff --git a/NetworkProtocol/ratingusernode.h b/NetworkProtocol/ratingusernode.h deleted file mode 100644 index d3d97a3..0000000 --- a/NetworkProtocol/ratingusernode.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef RATINGUSERSERVER_H -#define RATINGUSERSERVER_H - -#include "basenode.h" - - -namespace NP { - - -class RatingUserNode: public BaseNode -{ - Q_OBJECT -public: - RatingUserNode(); - - // AbstractNode interface -protected: - ParserResult parsePackage(const Package &pkg, const WP<AbstractNodeInfo> &sender) override; - QVariantMap defaultDbParams() const override; - bool workWithUserRequest(const WP<AbstractData> &, - const QHostAddress &addere, - const Header *rHeader); - -private: - - /** - * @brief registerNewUser - * @param user - * @param address - * @return - */ - bool registerNewUser(const WP<AbstractData> &user, - const QHostAddress &address); - - /** - * @brief loginUser - * @param user - * @param address - * @return - */ - bool loginUser(const WP<AbstractData> &user, - const WP<AbstractData> &userdb, - const QHostAddress &address); -}; - -} -#endif // RATINGUSERSERVER_H diff --git a/NetworkProtocol/sqldbcache.cpp b/NetworkProtocol/sqldbcache.cpp deleted file mode 100644 index e8c7f06..0000000 --- a/NetworkProtocol/sqldbcache.cpp +++ /dev/null @@ -1,225 +0,0 @@ -#include "sqldbcache.h" -#include "quasarapp.h" -#include "sqldbwriter.h" - -#include <networkprotocol.h> -#include <dbobject.h> - -#include <QDateTime> -#include <QtConcurrent/QtConcurrent> - - -namespace NP { - -void SqlDBCache::globalUpdateDataBasePrivate(qint64 currentTime) { - - QMutexLocker lock(&_saveLaterMutex); - - for (auto listIt = _needToSaveCache.begin(); listIt != _needToSaveCache.end(); ++listIt ) { - - auto list = listIt.value(); - for (int id: list) { - - auto saveObject = _cache.value(listIt.key()).value(id); - - if (!saveObject.isNull() && !_writer.isNull() && _writer->isValid()) { - - if (!saveObject->isValid()) { - deleteFromCache(listIt.key(), id); - - QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" - " db object is not valid! id=" + QString::number(id), - QuasarAppUtils::VerboseLvl::Error); - continue; - } - - if (!_writer->saveObject(saveObject)) { - QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" - " work globalUpdateDataRelease!!! id=" + - QString::number(id), - QuasarAppUtils::VerboseLvl::Error); - } - - QuasarAppUtils::Params::log("writeUpdateItemIntoDB failed when" - " db writer is npt inited! ", - QuasarAppUtils::VerboseLvl::Error); - } - } - } - - lastUpdateTime = currentTime; -} - -void SqlDBCache::globalUpdateDataBase(SqlDBCasheWriteMode mode) { - qint64 currentTime = QDateTime::currentMSecsSinceEpoch(); - - if (currentTime - lastUpdateTime > updateInterval || - static_cast<bool>(mode & SqlDBCasheWriteMode::Force)) { - - if (static_cast<bool>(mode & SqlDBCasheWriteMode::On_New_Thread)) { - - QtConcurrent::run([currentTime, this](){ - globalUpdateDataBasePrivate(currentTime); - }); - - } else { - globalUpdateDataBasePrivate(currentTime); - } - } -} - -SqlDBCache::SqlDBCache(qint64 updateInterval) { - lastUpdateTime = QDateTime::currentMSecsSinceEpoch(); - this->updateInterval = updateInterval; -} - -SqlDBCache::~SqlDBCache() { - globalUpdateDataBase(SqlDBCasheWriteMode::Force); -} - -WP<SqlDBWriter> SqlDBCache::writer() const { - return _writer; -} - -void SqlDBCache::setWriter(const WP<SqlDBWriter> &writer) { - _writer = writer; -} - -bool SqlDBCache::getObject(SP<DBObject> &obj) { - if (obj.isNull()) - return false; - - int id = obj->getId(); - auto table = obj->tableName(); - - auto& tableObj = _cache[table]; - - if (!tableObj.contains(id) && !_writer.isNull() && _writer->isValid()) { - if (!_writer->getObject(obj)) { - return false; - } - - saveToCache(obj); - return true; - } - - auto &sptr = tableObj[id]; - - if (!sptr->isCached() && _writer->getObject(sptr)) { - saveToCache(sptr); - } - - if (!sptr->isValid()) { - deleteFromCache(table, id); - return false; - } - - obj = sptr; - return true; -} - -SP<DBObject> &SqlDBCache::getObjectFromCache(const QString &table, int id) { - auto& tableObj = _cache[table]; - return tableObj[id]; -} - -bool SqlDBCache::saveObject(const WP<AbstractData>& saveObject) { - - auto ptr = saveObject.toStrongRef().dynamicCast<DBObject>(); - - if (ptr.isNull() || !ptr->isValid()) { - return false; - } - - saveToCache(ptr); - - if (getMode() == SqlDBCasheWriteMode::Force) { - if (!_writer.isNull() && _writer->isValid()) { - if (!_writer->saveObject(saveObject)) { - return false; - } - - return true; - } - } else { - _needToSaveCache[ptr->tableName()].push_back(ptr->getId()); - globalUpdateDataBase(_mode); - } - - return true; - -} - -bool SqlDBCache::deleteObject(const WP<AbstractData> &delObj) { - auto ref = delObj.toStrongRef().dynamicCast<DBObject>(); - - if (ref.isNull()) - return false; - - deleteFromCache(ref->tableName(), ref->getId()); - - if (_writer && _writer->isValid()) { - return _writer->deleteObject(delObj); - } - - return false; - -} - -bool SqlDBCache::init(const QString &initDbParams) { - - if (_writer.isNull()) { - return false; - } - - return _writer->initDb(initDbParams); -} - -bool SqlDBCache::init(const QVariantMap ¶ms) { - - if (_writer.isNull()) { - return false; - } - - return _writer->initDb(params); -} - -void SqlDBCache::deleteFromCache(const QString &table, int id) { - auto& tableObj = _cache[table]; - tableObj.remove(id); - - if (tableObj.isEmpty()) { - _cache.remove(table); - } -} - -void SqlDBCache::saveToCache(const WP<AbstractData> &obj) { - - auto ref = obj.toStrongRef().dynamicCast<DBObject>(); - - if (ref.isNull()) - return; - - // bug : pointer is rewrited!!!! - _cache[ref->tableName()][ref->getId()] = ref; - emit sigItemChanged(obj); - -} - -SqlDBCasheWriteMode SqlDBCache::getMode() const { - return _mode; -} - -void SqlDBCache::setMode(const SqlDBCasheWriteMode &mode) { - _mode = mode; -} - -qint64 SqlDBCache::getUpdateInterval() const { - return updateInterval; -} - -void SqlDBCache::setUpdateInterval(const qint64 &value) { - updateInterval = value; -} - -} diff --git a/NetworkProtocol/websocketcontroller.cpp b/NetworkProtocol/websocketcontroller.cpp deleted file mode 100644 index a7c8a62..0000000 --- a/NetworkProtocol/websocketcontroller.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "abstractnode.h" -#include "abstractnodeinfo.h" -#include "websocketcontroller.h" -#include <quasarapp.h> - -namespace NP { - - -WebSocketController::WebSocketController(AbstractNode *node) { - _node = node; - assert(_node); -} - -bool WebSocketController::subscribe(SP<AbstractNodeInfo> subscriber, - const DbAddress &item) { - - _subscribs[item].insert(subscriber); - _items[subscriber].insert(item); - - return true; -} - -void WebSocketController::unsubscribe(SP<AbstractNodeInfo> subscriber, - const DbAddress& item) { - _subscribs[item].remove(subscriber); - _items[subscriber].remove(item); - -} - -const QSet<DbAddress> &WebSocketController::list( - SP<AbstractNodeInfo> node) { - return _items[node]; -} - -void WebSocketController::handleItemChanged(const WP<AbstractData> &item) { - auto obj = item.toStrongRef().dynamicCast<DBObject>(); - if (obj.isNull() || !obj->isValid()) - return; - - foreachSubscribers(item, _subscribs.value(obj->dbAddress())); -} - -void WebSocketController::foreachSubscribers(const WP<AbstractData> &item, - const QSet<SP<AbstractNodeInfo>> &subscribersList) { - - auto ref = item.toStrongRef().dynamicCast<DBObject>(); - - if (ref.isNull()) - return; - - for (auto &&subscriber : subscribersList) { - - if (!subscriber.isNull() && subscriber->isValid()) { - if (!_node->sendData(item, subscriber->id())) { - QuasarAppUtils::Params::log("Send update failed for " + subscriber->id().toString(), - QuasarAppUtils::Warning); - } - } else { - unsubscribe(subscriber, ref->dbAddress()); - } - } -} -} diff --git a/NetworkProtocol/websocketcontroller.h b/NetworkProtocol/websocketcontroller.h deleted file mode 100644 index 0e276cb..0000000 --- a/NetworkProtocol/websocketcontroller.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef WEBSOCKETCONTROLLER_H -#define WEBSOCKETCONTROLLER_H - -#include <QHash> -#include <QSharedPointer> -#include <dbobject.h> - - -namespace NP { - -class AbstractNodeInfo; -class AbstractNode; - -/** - * @brief The WebSocketController class - manage subscribe - */ -class NETWORKPROTOCOLSHARED_EXPORT WebSocketController : public QObject -{ - Q_OBJECT - -public: - WebSocketController(AbstractNode *node); - bool subscribe(SP<AbstractNodeInfo> subscriber, - const DbAddress &item); - - void unsubscribe(SP<AbstractNodeInfo> subscriber, - const DbAddress &item); - - const QSet<DbAddress> &list(SP<AbstractNodeInfo> node); - -public slots: - void handleItemChanged(const WP<AbstractData> &item); - -private: - void foreachSubscribers(const WP<AbstractData> &item, - const QSet<SP<AbstractNodeInfo>> &subscribersList); - - QHash<DbAddress, QSet<SP<AbstractNodeInfo>>> _subscribs; - QHash<SP<AbstractNodeInfo>, QSet<DbAddress>> _items; - - AbstractNode *_node = nullptr; - -}; - -} -#endif // WEBSOCKETCONTROLLER_H diff --git a/ProtocolTests/CMakeLists.txt b/ProtocolTests/CMakeLists.txt deleted file mode 100644 index ec6dc7b..0000000 --- a/ProtocolTests/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (C) 2018-2020 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. -# - -cmake_minimum_required(VERSION 3.1) - -project(NetworkProtocolTest LANGUAGES CXX) - -include(../QuasarAppLib/CMake/ProjectOut.cmake) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -find_package(Qt5 COMPONENTS Core Test REQUIRED) - -file(GLOB SOURCE_CPP - "*.cpp" "DataPacakages/*.cpp" -) - -add_executable(${PROJECT_NAME} ${SOURCE_CPP}) -target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Test NetworkProtocol) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/DataPacakages) - -include(../QuasarAppLib/CMake/QuasarAppCITargets.cmake) -initTests(${PROJECT_NAME}) diff --git a/ProtocolTests/testutils.cpp b/ProtocolTests/testutils.cpp deleted file mode 100644 index ab21747..0000000 --- a/ProtocolTests/testutils.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "testutils.h" - -#include <QCoreApplication> -#include <QDateTime> -#include <QVariantMap> -#include <basenode.h> -#include <client.h> - -bool funcPrivate(std::function<bool()> requestFunc, - NP::BaseNode* node, - SP<NP::AbstractData>* responce = nullptr, - QHostAddress *responceSender = nullptr) { - - bool received = false; - QMetaObject::Connection m_connection; - m_connection = QObject::connect(node, &NP::BaseNode::incomingData, - [ &received, responce, responceSender] - (SP<NP::AbstractData> pkg, - const QHostAddress& sender) { - - received = true; - - if (responce) { - *responce = pkg; - } - - if (responceSender) { - *responceSender = sender; - } - - }); - - if (!requestFunc()) { - return false; - } - - if (!TestUtils::wait(received, 10000)) - return false; - - QObject::disconnect(m_connection); - - - return true; -} - - -bool funcPrivateConnect(std::function<bool()> requestFunc, - NP::Client* node) { - - bool connected = false; - QMetaObject::Connection m_connection; - m_connection = QObject::connect(node, &NP::Client::statusChanged, - [ &connected](int new_status) { - - connected = NP::Client::Status::Online == static_cast<NP::Client::Status>(new_status); - - }); - - if (!requestFunc()) { - return false; - } - - TestUtils::wait(connected, 10900); - QObject::disconnect(m_connection); - - return connected; -} - -TestUtils::TestUtils() -{ - -} - -bool TestUtils::wait(const bool &forWait, int msec) { - auto curmsec = QDateTime::currentMSecsSinceEpoch() + msec; - while (curmsec > QDateTime::currentMSecsSinceEpoch() && !forWait) { - QCoreApplication::processEvents(); - } - QCoreApplication::processEvents(); - return forWait; -} - -bool TestUtils::loginFunc( - NP::Client *cli, - const QString& login, - const QByteArray& pass, - bool sendResult, - bool loginResult) { - - auto wraper = [cli, login, pass](){return cli->login(login, pass);}; - bool result = funcPrivate(wraper, cli); - - if (!result) { - return !sendResult; - } - - return loginResult == (cli->status() == NP::Client::Logined); -} - -bool TestUtils::connectFunc( - NP::Client *cli, - const QString& address, - unsigned short port) { - - auto wraper = [&cli, address, port](){ - cli->setHost(QHostAddress(address), port); - return cli->connectClient(); - }; - - return funcPrivateConnect(wraper, cli); -} - -//bool TestUtils::getState( ServerProtocol::Client& cli, QVariantMap &state) { -// auto wraper = [&cli](){return cli.getState();}; -// return terminalFuncPrivate(wraper, cli, &state); -//} - -//bool TestUtils::unBanFunc( ServerProtocol::Client& cli, const QHostAddress& address) { -// auto wraper = [&cli, address](){return cli.unBan(address);}; -// return terminalFuncPrivate(wraper, cli); -//} - - -//bool TestUtils::banFunc( ServerProtocol::Client& cli, const QHostAddress& address) { -// auto wraper = [&cli, address](){return cli.ban(address);}; -// return terminalFuncPrivate(wraper, cli); -//} - -//bool TestUtils::reconnectFunc(ClientProtocol::Client &cli) { -// cli.reconnectToHost(); -// return wait(cli.isOnline(), 1000); -//} diff --git a/ProtocolTests/testutils.h b/ProtocolTests/testutils.h deleted file mode 100644 index c8deaf8..0000000 --- a/ProtocolTests/testutils.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TESTUTILS_H -#define TESTUTILS_H - -#include <networkprotocol.h> - -namespace NP { - class Client; -} -class TestUtils -{ -public: - TestUtils(); - static bool wait(const bool &forWait, int msec); - static bool loginFunc(NP::Client *cli, - const QString &login, - const QByteArray &pass, - bool sendResult, - bool loginResult); - - static bool connectFunc(NP::Client *cli, - const QString &address, - unsigned short port); -// static bool getState(ServerProtocol::Client &cli, QVariantMap &state); -// static bool unBanFunc(ServerProtocol::Client &cli, const QHostAddress &address); -// static bool banFunc(ServerProtocol::Client &cli, const QHostAddress &address); -// static bool reconnectFunc(ClientProtocol::Client &cli); -// static bool registerFunc(ClientProtocol::Client &cli, const QString &login, - // const QByteArray &pass, bool sendResult, bool loginResult); - -}; - -#endif // TESTUTILS_H diff --git a/ProtocolTests/tst_testsnakeserver.cpp b/ProtocolTests/tst_testsnakeserver.cpp deleted file mode 100644 index 0b3743a..0000000 --- a/ProtocolTests/tst_testsnakeserver.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include <QtTest> - -#include <thread> -#include <quasarapp.h> -#include <QCoreApplication> -#include <QCryptographicHash> -#include <networkprotocol.h> -#include <abstractdata.h> -#include <badrequest.h> -#include <package.h> -#include <basenode.h> -#include <client.h> - -#include "testutils.h" - -#define TEST_LOCAL_HOST "127.0.0.1" -#define TEST_PORT 27777 - -class testProtockol : public QObject -{ - Q_OBJECT - -private: - - -public: - testProtockol(); - - void connectTest(NP::Client *cli, NP::BaseNode *serv); - void testLogin(NP::Client *cli); - - ~testProtockol(); - -private slots: - void initTestCase(); - void testPakageData(); - void testBaseNode(); - void testUser(); - - -}; - -testProtockol::testProtockol() { - QuasarAppUtils::Params::setArg("verbose", 3); - -} - -void testProtockol::connectTest(NP::Client *cli, NP::BaseNode *serv) { - QVERIFY(serv->run(TEST_LOCAL_HOST, TEST_PORT)); - QVERIFY(TestUtils::connectFunc(cli, TEST_LOCAL_HOST, TEST_PORT)); -} - -void testProtockol::testLogin(NP::Client* cli) { - QVERIFY(TestUtils::loginFunc(cli, "user", "123", true, true)); - QVERIFY(cli->logout()); - QVERIFY(TestUtils::loginFunc(cli, "user", "124", true, false)); - QVERIFY(TestUtils::loginFunc(cli, "user", "124", true, false)); - QVERIFY(TestUtils::loginFunc(cli, "user", "123", true, true)); - QVERIFY(cli->logout()); - -} - -testProtockol::~testProtockol() { - -} - -void testProtockol::initTestCase() { -} - -void testProtockol::testPakageData() { - NP::BadRequest bad("Test"); - NP::BadRequest bad1; - NP::BadRequest bad2; - - QVERIFY(bad.cmd() == bad1.cmd() && bad.cmd() == bad2.cmd()); - - NP::Package pkg; - - QVERIFY(bad.toPackage(pkg)); - - NP::BadRequest res(pkg); - - QVERIFY(bad.cmd() == res.cmd()); - QVERIFY(bad.err() == res.err()); - -} - -void testProtockol::testBaseNode() { - NP::BaseNode node, node2; - - const int port1 = TEST_PORT + 1; - const int port2 = TEST_PORT + 2; - - QVERIFY(node.run(TEST_LOCAL_HOST, port1)); - QVERIFY(node2.run(TEST_LOCAL_HOST, port2)); - - node.connectToHost(QHostAddress(TEST_LOCAL_HOST), port2); - QVERIFY(node2.waitForNewConnection(1000)); - - QVERIFY(node.getWorkState().getConnectionCount() == 1); - - node2.stop(); - -} - -void testProtockol::testUser() { - int argc =0; - char * argv[] = {nullptr}; - - QCoreApplication app(argc, argv); - - QTimer::singleShot(0, [&app, this]() { - - NP::RatingUserNode *server = new NP::RatingUserNode(); - NP::Client * client = new NP::Client(QHostAddress(TEST_LOCAL_HOST), TEST_PORT); - - connectTest(client, server); - testLogin(client); - - delete server; - delete client; - - app.exit(0); - }); - - app.exec(); - - -} - - -QTEST_APPLESS_MAIN(testProtockol) - -#include "tst_testsnakeserver.moc" diff --git a/QuasarAppLib b/QuasarAppLib index c5c74c3..df33334 160000 --- a/QuasarAppLib +++ b/QuasarAppLib @@ -1 +1 @@ -Subproject commit c5c74c393f880c64d552fe4660bee4cdeb28fb16 +Subproject commit df333341ce44ba09819726ff204a09c965af88ae diff --git a/README.md b/README.md index 8e5f52f..9a3577e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,71 @@ -# QtNetworkProtocol -Network protockol for qt +# QuasarApp Heart +QuasarApp Heart - it is base back for C++/Qt projects. + +- [X] Support ssl sockets +- [X] Support initialize database +- [X] Support work in database +- [ ] Sopport decentralized network mode + +## Futures +This library consists of two levels (AbstractNode level and DataBaseNode level). + +### AbstractNode level (1) +#### Description +The AbstractNode level implement only base functons of create new work threads and parsing packages. +Example of use AbstractNode level + +```cpp +EXAMPLE +``` + +For more information see QuasarApp Heart documentation. + +### DataBaseNode level (2) +#### 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). + +Example of use DataBaseNode level + +```cpp +EXAMPLE +``` +### NetworkNode level (3) +#### Description +This level is still in develop. + +## Build and Include + +### For cmake projects + + * cd yourRepo + * 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 + add_subdirectory(Heart) + ``` + * select requiriment build level for you project + ``` + set(HEART_BUILD_LVL 2) + ``` + where 1 - is code of build level + + 1 - AbstractNode + + 2 - DataBaseNode + + 3 - NetworkNode + * link the Heart library to your target + ```cmake + target_link_libraries(yourLib PUBLIC Heart) + ``` + * rebuild yuor project + + + +## Usage + +To-do + -- [ ] support ssl sockets -- [ ] support initialize database -- [ ] support work in database -- [X] support registration users -- [ ] support client of daemon diff --git a/doxygen.conf b/doxygen.conf new file mode 100644 index 0000000..1377851 --- /dev/null +++ b/doxygen.conf @@ -0,0 +1,2496 @@ +# Doxyfile 1.8.13 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = NetworkProtocol + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = docs + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = NetworkProtocol/Qt-Secret/res/DoxyStyle/DoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ./NetworkProtocol \ + ./Doc + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = ./NetworkProtocol/Qt-Secret \ + ./NetworkProtocol/CMakeFiles + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = ./README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse-libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = NetworkProtocol/Qt-Secret/res/DoxyStyle/doxygenStyles.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = QuasarApp.NetworkProtocol + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer (doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO, the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES, the include files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: YES. + +HAVE_DOT = YES + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = YES + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = YES + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, +# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, +# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = YES + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/openssl-cmake b/openssl-cmake deleted file mode 160000 index 93d54fe..0000000 --- a/openssl-cmake +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 93d54fee2ae4864b3269b460872fe669a103ccab