├── modeling ├── .gitignore ├── server_db.dia ├── localstore_db.dia ├── modeling.pri └── exchange.txt ├── src ├── 3rdparty │ ├── cryptopp │ │ ├── .gitignore │ │ ├── cryptopp.pri │ │ ├── travis.sh │ │ └── appveyor.bat │ └── 3rdparty.pro ├── plugins │ ├── keystores │ │ ├── plain │ │ │ ├── plain.json │ │ │ ├── plain.pro │ │ │ ├── plainkeystoreplugin.h │ │ │ ├── plainkeystoreplugin.cpp │ │ │ ├── plainkeystore.h │ │ │ └── plainkeystore.cpp │ │ ├── android │ │ │ ├── android.json │ │ │ ├── android.pro │ │ │ ├── androidkeystoreplugin.h │ │ │ ├── androidkeystoreplugin.cpp │ │ │ └── androidkeystore.h │ │ ├── kwallet │ │ │ ├── kwallet.json │ │ │ ├── kwallet.pro │ │ │ ├── kwalletkeystoreplugin.h │ │ │ ├── kwalletkeystoreplugin.cpp │ │ │ └── kwalletkeystore.h │ │ ├── keychain │ │ │ ├── keychain.json │ │ │ ├── keychain.pro │ │ │ ├── keychainkeystoreplugin.h │ │ │ ├── keychainkeystoreplugin.cpp │ │ │ └── keychainkeystore.h │ │ ├── wincred │ │ │ ├── wincred.json │ │ │ ├── wincred.pro │ │ │ ├── wincredkeystoreplugin.h │ │ │ ├── wincredkeystoreplugin.cpp │ │ │ └── wincredkeystore.h │ │ ├── secretservice │ │ │ ├── secretservice.json │ │ │ ├── secretservice.pro │ │ │ ├── secretservicekeystoreplugin.h │ │ │ ├── secretservicekeystoreplugin.cpp │ │ │ ├── secretservicekeystore.h │ │ │ ├── libsecretwrapper.h │ │ │ └── secretservicekeystore.cpp │ │ └── keystores.pro │ └── plugins.pro ├── imports │ ├── imports.pro │ └── datasync │ │ ├── qmldir │ │ ├── qqmliossyncsingleton.cpp │ │ ├── qtdatasync_plugin.h │ │ ├── qqmliossyncsingleton.h │ │ ├── datasync.pro │ │ ├── qqmleventcursor.h │ │ ├── qqmleventcursor.cpp │ │ └── qqmldatastoremodel.cpp ├── messages │ ├── messages.pri │ ├── syncmessage.cpp │ ├── accountmessage.cpp │ ├── keychangemessage.cpp │ ├── devicesmessage.cpp │ ├── loginmessage.cpp │ ├── grantmessage.cpp │ ├── syncmessage_p.h │ ├── macupdatemessage.cpp │ ├── removemessage.cpp │ ├── devicekeysmessage.cpp │ ├── changemessage.cpp │ ├── welcomemessage.cpp │ ├── keychangemessage_p.h │ ├── devicechangemessage.cpp │ ├── accountmessage_p.h │ ├── newkeymessage.cpp │ ├── loginmessage_p.h │ ├── changedmessage.cpp │ ├── grantmessage_p.h │ ├── accessmessage.cpp │ ├── macupdatemessage_p.h │ ├── removemessage_p.h │ ├── welcomemessage_p.h │ ├── devicesmessage_p.h │ ├── devicekeysmessage_p.h │ ├── errormessage.cpp │ ├── devicechangemessage_p.h │ ├── changemessage_p.h │ ├── proofmessage.cpp │ ├── errormessage_p.h │ ├── accessmessage_p.h │ ├── newkeymessage_p.h │ ├── registermessage.cpp │ ├── messages.pro │ ├── changedmessage_p.h │ ├── identifymessage_p.h │ ├── registermessage_p.h │ └── identifymessage.cpp ├── datasyncios │ ├── QIOSApplicationDelegate+QtDatasyncAppDelegate_p.h │ ├── qtdatasyncappdelegate_capi_p.h │ ├── qtdatasyncios_global.h │ ├── datasyncios.pro │ ├── iossyncdelegate_p.h │ └── QIOSApplicationDelegate+QtDatasyncAppDelegate.mm ├── datasync │ ├── datatypestore.cpp │ ├── rothreadedbackend │ │ ├── rothreadedbackend.pri │ │ ├── exchangerotransport_p.h │ │ ├── exchangerotransport.cpp │ │ ├── exchangebufferserver_p.h │ │ └── exchangebuffer_p.h │ ├── conflictresolver_p.h │ ├── logger_p.h │ ├── changeemitter_p.rep │ ├── syncmanager_p.rep │ ├── signal_private_connect_p.h │ ├── remoteconfig_p.h │ ├── datastore_p.h │ ├── qtdatasync_global.h │ ├── synchelper_p.h │ ├── synccontroller_p.h │ ├── qtdatasync_global.cpp │ ├── syncmanager_p.h │ ├── qtdatasync_helpertypes.h │ ├── conflictresolver.cpp │ ├── eventcursor_p.h │ ├── datastoremodel_p.h │ ├── migrationhelper_p.h │ ├── userexchangemanager_p.h │ ├── logger.cpp │ ├── accountmanager_p.rep │ ├── controller_p.h │ ├── changeemitter_p.h │ ├── objectkey.h │ ├── objectkey.cpp │ ├── setup_p.h │ ├── keystore.cpp │ ├── emitteradapter_p.h │ ├── accountmanager_p.h │ ├── exception.cpp │ ├── changeemitter.cpp │ └── controller.cpp ├── datasyncandroid │ ├── datasyncandroid.pro │ ├── qtdatasyncandroid_global.h │ ├── androidbackgroundservice_p.h │ └── androidsynccontrol_p.h ├── java │ └── java.pro ├── src.pro └── translations │ └── translations.pro ├── examples ├── examples.pro └── datasync │ ├── IosSync │ ├── qml.qrc │ ├── IosSync.pro │ ├── syncdelegate.cpp │ ├── syncdelegate.h │ ├── main.qml │ ├── main.cpp │ └── Info.plist │ ├── AndroidSync │ ├── qml.qrc │ ├── android │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ └── icon.png │ │ │ ├── drawable-ldpi │ │ │ │ └── icon.png │ │ │ ├── drawable-mdpi │ │ │ │ └── icon.png │ │ │ └── values │ │ │ │ └── libs.xml │ │ ├── build.gradle │ │ └── src │ │ │ └── de │ │ │ └── skycoder42 │ │ │ └── qtdatasync │ │ │ └── sample │ │ │ └── androidsync │ │ │ └── SvcHelper.java │ ├── AndroidSync.pro │ ├── syncservice.h │ ├── main.qml │ ├── syncservice.cpp │ └── main.cpp │ ├── datasync.pro │ └── Sample │ ├── sampledata.cpp │ ├── sampledata.h │ ├── docker-compose.yaml │ ├── widget.h │ ├── Sample.pro │ ├── exchangedialog.h │ └── accountdialog.h ├── doc ├── images │ ├── demo.gif │ └── GitHub_Logo.png ├── doc.pro ├── qtdatasync.dox ├── doxme.py ├── rothreaded.dox ├── migrationhelper.dox ├── makedoc.sh └── logger.dox ├── tools ├── tools.pro └── appserver │ ├── docker_setup.conf │ ├── qdsapp-install.bat.in │ ├── qdsapp.socket.in │ ├── dockerbuild │ ├── env_start.sh │ └── install.sh │ ├── qdsapp.conf │ ├── qdsapp.service.in │ ├── de.skycoder42.qtdatasync.qdsapp.plist.in │ ├── docker-compose.yaml │ ├── clientconnector.h │ ├── datasyncservice.h │ └── singletaskqueue.h ├── tests ├── global │ └── global.cfg ├── auto │ ├── datasync │ │ ├── TestSetup │ │ │ └── TestSetup.pro │ │ ├── TestMessages │ │ │ └── TestMessages.pro │ │ ├── TestDataStore │ │ │ └── TestDataStore.pro │ │ ├── TestEventCursor │ │ │ └── TestEventCursor.pro │ │ ├── TestDataTypeStore │ │ │ └── TestDataTypeStore.pro │ │ ├── TestChangeController │ │ │ └── TestChangeController.pro │ │ ├── TestMigrationHelper │ │ │ └── TestMigrationHelper.pro │ │ ├── TestRemoteConnector │ │ │ └── TestRemoteConnector.pro │ │ ├── TestRoThreadedBackend │ │ │ ├── testclass.rep │ │ │ └── TestRoThreadedBackend.pro │ │ ├── TestLocalStore │ │ │ └── TestLocalStore.pro │ │ ├── IntegrationTest │ │ │ ├── qdsapp.conf │ │ │ └── IntegrationTest.pro │ │ ├── TestKeystorePlugins │ │ │ └── TestKeystorePlugins.pro │ │ ├── TestSyncController │ │ │ ├── TestSyncController.pro │ │ │ ├── testresolver.h │ │ │ └── testresolver.cpp │ │ ├── TestCryptoController │ │ │ └── TestCryptoController.pro │ │ ├── TestAppServer │ │ │ ├── qdsapp.conf │ │ │ └── TestAppServer.pro │ │ ├── TestLib │ │ │ ├── testdata.cpp │ │ │ ├── testobject.cpp │ │ │ ├── mockclient.h │ │ │ ├── testdata.h │ │ │ ├── testobject.h │ │ │ ├── mockserver.h │ │ │ ├── mockclient.cpp │ │ │ ├── TestLib.pro │ │ │ ├── mockserver.cpp │ │ │ ├── testlib.h │ │ │ └── testlib.cpp │ │ ├── datasync.pro │ │ └── tests.pri │ ├── cmake │ │ ├── cmake.pro │ │ └── CMakeLists.txt │ ├── qml │ │ ├── qml.pro │ │ └── TestQmlDataSync │ │ │ ├── TestQmlDataSync.pro │ │ │ ├── tst_qmldatasync.cpp │ │ │ └── tst_qmldatasync.qml │ └── auto.pro ├── tests.pro └── ci │ ├── qdsapp.conf │ └── setup.sh ├── .gitmodules ├── Dockerfile ├── .qmake.conf ├── deploy.json ├── qtdatasync.pro ├── sync.profile ├── .gitignore ├── mkspecs └── features │ └── masm.prf ├── appveyor.yml └── LICENSE /modeling/.gitignore: -------------------------------------------------------------------------------- 1 | *.dia~ 2 | -------------------------------------------------------------------------------- /src/3rdparty/cryptopp/.gitignore: -------------------------------------------------------------------------------- 1 | include 2 | lib 3 | -------------------------------------------------------------------------------- /examples/examples.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = datasync 4 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plain.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "plain" ] 3 | } 4 | -------------------------------------------------------------------------------- /src/imports/imports.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | datasync 5 | -------------------------------------------------------------------------------- /src/plugins/keystores/android/android.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "android" ] 3 | } 4 | -------------------------------------------------------------------------------- /src/plugins/keystores/kwallet/kwallet.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "kwallet" ] 3 | } 4 | -------------------------------------------------------------------------------- /src/plugins/keystores/keychain/keychain.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "keychain" ] 3 | } 4 | -------------------------------------------------------------------------------- /src/plugins/keystores/wincred/wincred.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "wincred" ] 3 | } 4 | -------------------------------------------------------------------------------- /doc/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/doc/images/demo.gif -------------------------------------------------------------------------------- /modeling/server_db.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/modeling/server_db.dia -------------------------------------------------------------------------------- /src/plugins/plugins.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | QT_FOR_CONFIG += core 4 | SUBDIRS += keystores 5 | -------------------------------------------------------------------------------- /doc/images/GitHub_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/doc/images/GitHub_Logo.png -------------------------------------------------------------------------------- /modeling/localstore_db.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/modeling/localstore_db.dia -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservice.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "secretservice", "gnome-keyring" ] 3 | } 4 | -------------------------------------------------------------------------------- /src/messages/messages.pri: -------------------------------------------------------------------------------- 1 | QMAKE_USE_PRIVATE += datasync_messages 2 | include($$PWD/../3rdparty/cryptopp/cryptopp.pri) 3 | -------------------------------------------------------------------------------- /tools/tools.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | !cross_compile: SUBDIRS += appserver 4 | 5 | QMAKE_EXTRA_TARGETS += run-tests 6 | -------------------------------------------------------------------------------- /tests/global/global.cfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /modeling/modeling.pri: -------------------------------------------------------------------------------- 1 | OTHER_FILES += $$PWD/*.qmodel \ 2 | $$PWD/*.dia \ 3 | $$PWD/*.txt \ 4 | $$PWD/../src/datasync/connectormodel.scxml 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/3rdparty/cryptopp/src"] 2 | path = src/3rdparty/cryptopp/src 3 | url = https://github.com/weidai11/cryptopp.git 4 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | main.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestSetup/TestSetup.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_setup 4 | 5 | SOURCES += \ 6 | tst_setup.cpp 7 | 8 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestMessages/TestMessages.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_messages 4 | 5 | SOURCES += \ 6 | tst_messages.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestDataStore/TestDataStore.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_datastore 4 | 5 | SOURCES += \ 6 | tst_datastore.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/cmake/cmake.pro: -------------------------------------------------------------------------------- 1 | 2 | # Cause make to do nothing. 3 | TEMPLATE = subdirs 4 | 5 | CMAKE_QT_MODULES_UNDER_TEST = datasync 6 | 7 | CONFIG += ctest_testcase 8 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestEventCursor/TestEventCursor.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_eventcursor 4 | 5 | SOURCES += \ 6 | tst_eventcursor.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/qml/qml.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | TestQmlDataSync 5 | 6 | prepareRecursiveTarget(run-tests) 7 | QMAKE_EXTRA_TARGETS += run-tests 8 | -------------------------------------------------------------------------------- /src/3rdparty/3rdparty.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | system_cryptopp:unix: message("Not building cryptopp, using system provided version") 4 | else: SUBDIRS += cryptopp 5 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestDataTypeStore/TestDataTypeStore.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_datatypestore 4 | 5 | SOURCES += \ 6 | tst_datatypestore.cpp 7 | -------------------------------------------------------------------------------- /src/3rdparty/cryptopp/cryptopp.pri: -------------------------------------------------------------------------------- 1 | system_cryptopp:unix { 2 | CONFIG += link_pkgconfig 3 | PKGCONFIG += libcrypto++ 4 | } else { 5 | QMAKE_USE_PRIVATE += cryptopp 6 | } 7 | -------------------------------------------------------------------------------- /tests/tests.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | CONFIG += no_docs_target 4 | 5 | SUBDIRS += auto 6 | 7 | prepareRecursiveTarget(run-tests) 8 | QMAKE_EXTRA_TARGETS += run-tests 9 | -------------------------------------------------------------------------------- /examples/datasync/datasync.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | QT_FOR_CONFIG += core 3 | 4 | SUBDIRS += \ 5 | Sample 6 | 7 | android: SUBDIRS += AndroidSync 8 | ios: SUBDIRS += IosSync 9 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestChangeController/TestChangeController.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_changecontroller 4 | 5 | SOURCES += \ 6 | tst_changecontroller.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestMigrationHelper/TestMigrationHelper.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_migrationhelper 4 | 5 | SOURCES += \ 6 | tst_migrationhelper.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestRemoteConnector/TestRemoteConnector.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_remoteconnector 4 | 5 | SOURCES += \ 6 | tst_remoteconnector.cpp 7 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestRoThreadedBackend/testclass.rep: -------------------------------------------------------------------------------- 1 | class TestClass 2 | { 3 | PROP(bool currState=false); 4 | SLOT(serverDo(int id)); 5 | SIGNAL(serverDone(int id)); 6 | }; 7 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/examples/datasync/AndroidSync/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/examples/datasync/AndroidSync/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skycoder42/QtDataSync/master/examples/datasync/AndroidSync/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /tests/auto/datasync/TestLocalStore/TestLocalStore.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | QT += concurrent 4 | 5 | TARGET = tst_localstore 6 | 7 | SOURCES += \ 8 | tst_localstore.cpp 9 | -------------------------------------------------------------------------------- /tests/ci/qdsapp.conf: -------------------------------------------------------------------------------- 1 | [server] 2 | host=localhost 3 | port=14242 4 | 5 | [database] 6 | name=postgres 7 | host=localhost 8 | port=5432 9 | username=postgres 10 | password=baum42 11 | -------------------------------------------------------------------------------- /src/imports/datasync/qmldir: -------------------------------------------------------------------------------- 1 | module de.skycoder42.QtDataSync 2 | plugin declarative_datasync 3 | classname QtDataSyncDeclarativeModule 4 | typeinfo plugins.qmltypes 5 | depends QtQml 2.2 6 | depends QtQml.Models 2.2 7 | -------------------------------------------------------------------------------- /tests/auto/datasync/IntegrationTest/qdsapp.conf: -------------------------------------------------------------------------------- 1 | [server] 2 | host=localhost 3 | port=14242 4 | 5 | [database] 6 | name=QtDataSync 7 | host=localhost 8 | port=15432 9 | username=qtdatasync 10 | password=baum42 11 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestKeystorePlugins/TestKeystorePlugins.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | QT += gui widgets #required for kde 4 | 5 | TARGET = tst_keystoreplugins 6 | 7 | SOURCES += \ 8 | tst_keystoreplugins.cpp 9 | -------------------------------------------------------------------------------- /tools/appserver/docker_setup.conf: -------------------------------------------------------------------------------- 1 | [server] 2 | host=localhost 3 | port=4242 4 | loglevel=4 5 | 6 | [database] 7 | name=QtDataSync 8 | host=localhost 9 | port=15432 10 | username=qtdatasync 11 | password=baum42 12 | -------------------------------------------------------------------------------- /src/messages/syncmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "syncmessage_p.h" 2 | 3 | #include 4 | 5 | using namespace QtDataSync; 6 | 7 | const QMetaObject *SyncMessage::getMetaObject() const 8 | { 9 | return &staticMetaObject; 10 | } 11 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestSyncController/TestSyncController.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_synccontroller 4 | 5 | SOURCES += \ 6 | tst_synccontroller.cpp \ 7 | testresolver.cpp 8 | 9 | HEADERS += \ 10 | testresolver.h 11 | -------------------------------------------------------------------------------- /src/datasyncios/QIOSApplicationDelegate+QtDatasyncAppDelegate_p.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface QIOSApplicationDelegate : UIResponder 4 | @end 5 | 6 | @interface QIOSApplicationDelegate (QtDatasyncAppDelegate) 7 | @end 8 | -------------------------------------------------------------------------------- /tests/auto/auto.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += cmake \ 4 | datasync \ 5 | qml 6 | 7 | qml.depends += datasync 8 | 9 | cmake.CONFIG += no_run-tests_target 10 | prepareRecursiveTarget(run-tests) 11 | QMAKE_EXTRA_TARGETS += run-tests 12 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestCryptoController/TestCryptoController.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_cryptocontroller 4 | 5 | SOURCES += \ 6 | tst_cryptocontroller.cpp 7 | 8 | DEFINES += PLUGIN_DIR=\\\"$$OUT_PWD/../../../../plugins/keystores/\\\" 9 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestAppServer/qdsapp.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | logIpAddress=true 3 | 4 | [server] 5 | host=localhost 6 | port=14242 7 | 8 | [database] 9 | name=QtDataSync 10 | host=localhost 11 | port=15432 12 | username=qtdatasync 13 | password=baum42 14 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestRoThreadedBackend/TestRoThreadedBackend.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | TARGET = tst_rothreadedbackend 4 | 5 | SOURCES += \ 6 | tst_rothreadedbackend.cpp 7 | 8 | REPC_SOURCE += testclass.rep 9 | REPC_REPLICA += $$REPC_SOURCE 10 | -------------------------------------------------------------------------------- /src/datasync/datatypestore.cpp: -------------------------------------------------------------------------------- 1 | #include "datatypestore.h" 2 | using namespace QtDataSync; 3 | 4 | DataTypeStoreBase::DataTypeStoreBase(QObject *parent) : 5 | QObject{parent} 6 | {} 7 | 8 | QString DataTypeStoreBase::setupName() const 9 | { 10 | return store()->setupName(); 11 | } 12 | -------------------------------------------------------------------------------- /tests/auto/cmake/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 2.8) 3 | 4 | project(qmake_cmake_files) 5 | 6 | enable_testing() 7 | 8 | find_package(Qt5Core REQUIRED) 9 | 10 | include("${_Qt5CTestMacros}") 11 | 12 | test_module_includes( 13 | DataSync QDataSync 14 | ) 15 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testdata.cpp: -------------------------------------------------------------------------------- 1 | #include "testdata.h" 2 | 3 | TestData::TestData(int id, QString text) : 4 | id(id), 5 | text(text) 6 | {} 7 | 8 | bool TestData::operator ==(const TestData &other) const 9 | { 10 | return id == other.id && 11 | text == other.text; 12 | } 13 | -------------------------------------------------------------------------------- /tools/appserver/qdsapp-install.bat.in: -------------------------------------------------------------------------------- 1 | @echo off 2 | sc create qdsapp binPath= \\"$$system_path($$[QT_INSTALL_BINS]\\\\$${TARGET}) --backend windows\\" start= auto displayname= \\"$${QMAKE_TARGET_PRODUCT}\\" || exit /B 1 3 | sc description qdsapp \\"$${QMAKE_TARGET_PRODUCT} Service\\" || exit /B 1 4 | -------------------------------------------------------------------------------- /tools/appserver/qdsapp.socket.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=QtDataSync AppServer Socket 3 | Documentation=https://github.com/Skycoder42/QtDataSync 4 | After=network.target 5 | PartOf=$${APPNAME}.service 6 | 7 | [Socket] 8 | ListenStream=4242 9 | 10 | [Install] 11 | WantedBy=sockets.target 12 | -------------------------------------------------------------------------------- /src/messages/accountmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "accountmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | AccountMessage::AccountMessage(QUuid deviceId) : 5 | deviceId{deviceId} 6 | {} 7 | 8 | const QMetaObject *AccountMessage::getMetaObject() const 9 | { 10 | return &staticMetaObject; 11 | } 12 | -------------------------------------------------------------------------------- /src/messages/keychangemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "keychangemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | KeyChangeMessage::KeyChangeMessage(quint32 nextIndex) : 5 | nextIndex{nextIndex} 6 | {} 7 | 8 | const QMetaObject *KeyChangeMessage::getMetaObject() const 9 | { 10 | return &staticMetaObject; 11 | } 12 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testobject.cpp: -------------------------------------------------------------------------------- 1 | #include "testobject.h" 2 | 3 | TestObject::TestObject(QObject *parent) : 4 | QObject(parent), 5 | id(0), 6 | text() 7 | {} 8 | 9 | bool TestObject::equals(const TestObject *other) const 10 | { 11 | return id == other->id && 12 | text == other->text; 13 | } 14 | -------------------------------------------------------------------------------- /src/messages/devicesmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "devicesmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | const QMetaObject *ListDevicesMessage::getMetaObject() const 5 | { 6 | return &staticMetaObject; 7 | } 8 | 9 | 10 | 11 | const QMetaObject *DevicesMessage::getMetaObject() const 12 | { 13 | return &staticMetaObject; 14 | } 15 | -------------------------------------------------------------------------------- /src/imports/datasync/qqmliossyncsingleton.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmliossyncsingleton.h" 2 | using namespace QtDataSync; 3 | 4 | QQmlIosSyncSingleton::QQmlIosSyncSingleton(QObject *parent) : 5 | QObject{parent} 6 | {} 7 | 8 | IosSyncDelegate *QQmlIosSyncSingleton::delegate() const 9 | { 10 | return IosSyncDelegate::currentDelegate(); 11 | } 12 | -------------------------------------------------------------------------------- /src/plugins/keystores/keystores.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += plain 4 | qtHaveModule(KWallet): SUBDIRS += kwallet 5 | unix:!android:!ios:packagesExist(libsecret-1): SUBDIRS += secretservice 6 | win32:!cross_compile: SUBDIRS += wincred 7 | mac|ios: SUBDIRS += keychain 8 | android:qtHaveModule(androidextras): SUBDIRS += android 9 | -------------------------------------------------------------------------------- /src/datasync/rothreadedbackend/rothreadedbackend.pri: -------------------------------------------------------------------------------- 1 | HEADERS += \ 2 | $$PWD/exchangebuffer_p.h \ 3 | $$PWD/exchangebufferserver_p.h \ 4 | $$PWD/exchangerotransport_p.h 5 | 6 | SOURCES += \ 7 | $$PWD/exchangebuffer.cpp \ 8 | $$PWD/exchangebufferserver.cpp \ 9 | $$PWD/exchangerotransport.cpp 10 | 11 | INCLUDEPATH += $$PWD 12 | -------------------------------------------------------------------------------- /src/datasyncios/qtdatasyncappdelegate_capi_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNCAPPDELEGATE_CAPI_P_H 2 | #define QTDATASYNCAPPDELEGATE_CAPI_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include "iossyncdelegate.h" 8 | 9 | // c -> mm 10 | void QtDatasyncAppDelegateInitialize(); 11 | void setSyncInterval(double intervalSeconds); 12 | 13 | #endif // DATASYNCAPPDELEGATE_CAPI_P_H 14 | -------------------------------------------------------------------------------- /src/messages/loginmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "loginmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | LoginMessage::LoginMessage(QUuid deviceId, QString deviceName, QByteArray nonce) : 5 | InitMessage{std::move(nonce)}, 6 | deviceId{deviceId}, 7 | deviceName{std::move(deviceName)} 8 | {} 9 | 10 | const QMetaObject *LoginMessage::getMetaObject() const 11 | { 12 | return &staticMetaObject; 13 | } 14 | -------------------------------------------------------------------------------- /examples/datasync/Sample/sampledata.cpp: -------------------------------------------------------------------------------- 1 | #include "sampledata.h" 2 | 3 | QDebug operator<<(QDebug debug, const SampleData &data) 4 | { 5 | QDebugStateSaver saver(debug); 6 | debug.nospace().noquote() << "SampleData{" 7 | << "id: " << data.id << ", " 8 | << "title: " << data.title << ", " 9 | << "description: " << data.description 10 | << '}'; 11 | return debug; 12 | } 13 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | #LABEL maintainer="skycoder42.de@gmx.de" 2 | FROM alpine:latest 3 | 4 | COPY . /tmp/src 5 | RUN /tmp/src/tools/appserver/dockerbuild/install.sh 6 | 7 | ENV QDSAPP_CONFIG_FILE=/etc/qdsapp.conf \ 8 | QDSAPP_DATABASE_HOST= \ 9 | QDSAPP_DATABASE_PORT=5432 \ 10 | QDSAPP_DATABASE_USER=postgres \ 11 | QDSAPP_DATABASE_PASSWORD= \ 12 | QDSAPP_DATABASE_NAME=postgres 13 | CMD ["/usr/bin/env_start.sh"] 14 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plain.pro: -------------------------------------------------------------------------------- 1 | TARGET = qplain 2 | 3 | QT += datasync 4 | QT -= gui 5 | 6 | HEADERS += \ 7 | plainkeystoreplugin.h \ 8 | plainkeystore.h 9 | 10 | SOURCES += \ 11 | plainkeystoreplugin.cpp \ 12 | plainkeystore.cpp 13 | 14 | DISTFILES += plain.json 15 | 16 | PLUGIN_TYPE = keystores 17 | PLUGIN_EXTENDS = datasync 18 | PLUGIN_CLASS_NAME = PlainKeyStorePlugin 19 | load(qt_plugin) 20 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/IosSync.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += quick datasync datasyncios 4 | CONFIG += c++14 5 | 6 | TARGET = IosSync 7 | 8 | HEADERS += \ 9 | syncdelegate.h 10 | 11 | SOURCES += \ 12 | main.cpp \ 13 | syncdelegate.cpp 14 | 15 | RESOURCES += qml.qrc 16 | 17 | QMAKE_INFO_PLIST = Info.plist 18 | 19 | target.path = $$[QT_INSTALL_EXAMPLES]/datasync/$$TARGET 20 | !install_ok: INSTALLS += target 21 | -------------------------------------------------------------------------------- /src/plugins/keystores/kwallet/kwallet.pro: -------------------------------------------------------------------------------- 1 | TARGET = qkwallet 2 | 3 | QT += datasync KWallet 4 | QT -= gui 5 | 6 | HEADERS += \ 7 | kwalletkeystoreplugin.h \ 8 | kwalletkeystore.h 9 | 10 | SOURCES += \ 11 | kwalletkeystoreplugin.cpp \ 12 | kwalletkeystore.cpp 13 | 14 | DISTFILES += kwallet.json 15 | 16 | PLUGIN_TYPE = keystores 17 | PLUGIN_EXTENDS = datasync 18 | PLUGIN_CLASS_NAME = KWalletKeyStorePlugin 19 | load(qt_plugin) 20 | -------------------------------------------------------------------------------- /src/datasyncios/qtdatasyncios_global.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNCIOS_GLOBAL_H 2 | #define QTDATASYNCIOS_GLOBAL_H 3 | 4 | #include 5 | 6 | #ifndef QT_STATIC 7 | # if defined(QT_BUILD_DATASYNCIOS_LIB) 8 | # define Q_DATASYNCIOS_EXPORT Q_DECL_EXPORT 9 | # else 10 | # define Q_DATASYNCIOS_EXPORT Q_DECL_IMPORT 11 | # endif 12 | #else 13 | # define Q_DATASYNCIOS_EXPORT 14 | #endif 15 | 16 | #endif // QTDATASYNCIOS_GLOBAL_H 17 | -------------------------------------------------------------------------------- /src/plugins/keystores/android/android.pro: -------------------------------------------------------------------------------- 1 | TARGET = qandroid 2 | 3 | QT += datasync androidextras 4 | QT -= gui 5 | 6 | HEADERS += \ 7 | androidkeystoreplugin.h \ 8 | androidkeystore.h 9 | 10 | SOURCES += \ 11 | androidkeystoreplugin.cpp \ 12 | androidkeystore.cpp 13 | 14 | DISTFILES += android.json 15 | 16 | PLUGIN_TYPE = keystores 17 | PLUGIN_EXTENDS = datasync 18 | PLUGIN_CLASS_NAME = AndroidKeyStorePlugin 19 | load(qt_plugin) 20 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/mockclient.h: -------------------------------------------------------------------------------- 1 | #ifndef MOCKCLIENT_H 2 | #define MOCKCLIENT_H 3 | 4 | #include 5 | 6 | #include "mockconnection.h" 7 | 8 | class MockClient : public MockConnection 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit MockClient(QObject *parent = nullptr); 14 | 15 | bool waitForConnected(quint16 port = 14242); 16 | 17 | private: 18 | QSignalSpy _connectSpy; 19 | }; 20 | 21 | #endif // MOCKCLIENT_H 22 | -------------------------------------------------------------------------------- /src/datasyncandroid/datasyncandroid.pro: -------------------------------------------------------------------------------- 1 | TARGET = QtDataSyncAndroid 2 | 3 | QT = core service androidextras datasync datasync-private 4 | 5 | HEADERS += \ 6 | androidbackgroundservice.h \ 7 | qtdatasyncandroid_global.h \ 8 | androidbackgroundservice_p.h \ 9 | androidsynccontrol.h \ 10 | androidsynccontrol_p.h 11 | 12 | SOURCES += \ 13 | androidbackgroundservice.cpp \ 14 | androidsynccontrol.cpp 15 | 16 | load(qt_module) 17 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestAppServer/TestAppServer.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | QT += service 4 | 5 | TARGET = tst_appserver 6 | 7 | SOURCES += \ 8 | tst_appserver.cpp 9 | 10 | BUILD_BIN_DIR = $$shadowed($$dirname(_QMAKE_CONF_))/bin 11 | DEFINES += BUILD_BIN_DIR=\\\"$$BUILD_BIN_DIR/\\\" 12 | 13 | !include(./setup.pri): SETUP_FILE = $$PWD/qdsapp.conf 14 | 15 | DISTFILES += $$SETUP_FILE 16 | DEFINES += SETUP_FILE=\\\"$$SETUP_FILE\\\" 17 | -------------------------------------------------------------------------------- /src/messages/grantmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "grantmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | GrantMessage::GrantMessage() = default; 5 | 6 | GrantMessage::GrantMessage(const AcceptMessage &message) : 7 | AccountMessage{message.deviceId}, 8 | index{message.index}, 9 | scheme{message.scheme}, 10 | secret{message.secret} 11 | {} 12 | 13 | const QMetaObject *GrantMessage::getMetaObject() const 14 | { 15 | return &staticMetaObject; 16 | } 17 | -------------------------------------------------------------------------------- /src/messages/syncmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SYNCMESSAGE_P_H 2 | #define QTDATASYNC_SYNCMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | 6 | namespace QtDataSync { 7 | 8 | class Q_DATASYNC_EXPORT SyncMessage : public Message 9 | { 10 | Q_GADGET 11 | 12 | protected: 13 | const QMetaObject *getMetaObject() const override; 14 | }; 15 | 16 | } 17 | 18 | Q_DECLARE_METATYPE(QtDataSync::SyncMessage) 19 | 20 | #endif // QTDATASYNC_SYNCMESSAGE_P_H 21 | -------------------------------------------------------------------------------- /tests/auto/datasync/IntegrationTest/IntegrationTest.pro: -------------------------------------------------------------------------------- 1 | include(../tests.pri) 2 | 3 | QT += service 4 | 5 | TARGET = tst_integration 6 | 7 | SOURCES += \ 8 | tst_integration.cpp 9 | 10 | BUILD_BIN_DIR = $$shadowed($$dirname(_QMAKE_CONF_))/bin 11 | DEFINES += BUILD_BIN_DIR=\\\"$$BUILD_BIN_DIR/\\\" 12 | 13 | !include(./setup.pri): SETUP_FILE = $$PWD/qdsapp.conf 14 | 15 | DISTFILES += $$SETUP_FILE 16 | DEFINES += SETUP_FILE=\\\"$$SETUP_FILE\\\" 17 | -------------------------------------------------------------------------------- /src/3rdparty/cryptopp/travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | version=7_0_0 5 | 6 | case "$PLATFORM" in 7 | gcc_64) 8 | pkgName=linux 9 | ;; 10 | clang_64) 11 | pkgName=macos 12 | ;; 13 | *) 14 | pkgName=$PLATFORM 15 | ;; 16 | esac 17 | 18 | curl -Lo /tmp/cryptopp.tar.xz https://github.com/Skycoder42/ci-builds/releases/download/cryptopp_${version}/cryptopp_${version}_${pkgName}.tar.xz 19 | tar -xf /tmp/cryptopp.tar.xz -C ./src/3rdparty/ 20 | -------------------------------------------------------------------------------- /.qmake.conf: -------------------------------------------------------------------------------- 1 | load(qt_build_config) 2 | 3 | CONFIG += warning_clean exceptions c++17 4 | #QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.12 5 | 6 | DEFINES += QT_DEPRECATED_WARNINGS QT_ASCII_CAST_WARNINGS 7 | 8 | MODULE_VERSION_MAJOR = 4 9 | MODULE_VERSION_MINOR = 3 10 | MODULE_VERSION_PATCH = 0 11 | MODULE_VERSION_IMPORT = $${MODULE_VERSION_MAJOR}.$${MODULE_VERSION_MINOR} 12 | MODULE_VERSION = $${MODULE_VERSION_MAJOR}.$${MODULE_VERSION_MINOR}.$${MODULE_VERSION_PATCH} 13 | 14 | -------------------------------------------------------------------------------- /deploy.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "QtDataSync", 3 | "description": "A simple offline-first synchronisation framework, to synchronize data of Qt applications between devices.", 4 | "modules": [ "QtDataSync", "QtDataSyncAndroid", "QtDataSyncIos" ], 5 | "dependencies": [ 6 | ".skycoder42.jsonserializer", 7 | ".skycoder42.service" 8 | ], 9 | "excludes": [ "wasm", "msvc2015" ], 10 | "license": { 11 | "name": "BSD-3-Clause", 12 | "path": "LICENSE" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/imports/datasync/qtdatasync_plugin.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_PLUGIN_H 2 | #define QTDATASYNC_PLUGIN_H 3 | 4 | #include 5 | 6 | class QtDataSyncDeclarativeModule : public QQmlExtensionPlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) 10 | 11 | public: 12 | QtDataSyncDeclarativeModule(QObject *parent = nullptr); 13 | void registerTypes(const char *uri) override; 14 | }; 15 | 16 | #endif // QTDATASYNC_PLUGIN_H 17 | -------------------------------------------------------------------------------- /src/datasync/conflictresolver_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_CONFLICTRESOLVER_P_H 2 | #define QTDATASYNC_CONFLICTRESOLVER_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "conflictresolver.h" 6 | 7 | namespace QtDataSync { 8 | 9 | //no export needed 10 | class ConflictResolverPrivate 11 | { 12 | public: 13 | QString defaultsName; 14 | Logger *logger = nullptr; 15 | QSettings *settings = nullptr; 16 | }; 17 | 18 | } 19 | 20 | #endif // QTDATASYNC_CONFLICTRESOLVER_P_H 21 | -------------------------------------------------------------------------------- /src/datasync/logger_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_LOGGER_P_H 2 | #define QTDATASYNC_LOGGER_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "logger.h" 6 | 7 | namespace QtDataSync { 8 | 9 | //no export needed 10 | class LoggerPrivate 11 | { 12 | public: 13 | LoggerPrivate(QString setupName, const QByteArray &subCategory); 14 | 15 | QString setupName; 16 | QByteArray catName; 17 | QLoggingCategory logCat; 18 | }; 19 | 20 | } 21 | 22 | #endif // QTDATASYNC_LOGGER_P_H 23 | -------------------------------------------------------------------------------- /src/plugins/keystores/wincred/wincred.pro: -------------------------------------------------------------------------------- 1 | TARGET = qwincred 2 | 3 | QT += datasync 4 | QT -= gui 5 | 6 | HEADERS += \ 7 | wincredkeystoreplugin.h \ 8 | wincredkeystore.h 9 | 10 | SOURCES += \ 11 | wincredkeystoreplugin.cpp \ 12 | wincredkeystore.cpp 13 | 14 | DISTFILES += wincred.json 15 | 16 | LIBS += -ladvapi32 17 | 18 | PLUGIN_TYPE = keystores 19 | PLUGIN_EXTENDS = datasync 20 | PLUGIN_CLASS_NAME = WinCredKeyStorePlugin 21 | load(qt_plugin) 22 | -------------------------------------------------------------------------------- /src/datasyncandroid/qtdatasyncandroid_global.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNCANDROID_GLOBAL_H 2 | #define QTDATASYNCANDROID_GLOBAL_H 3 | 4 | #include 5 | 6 | #ifndef QT_STATIC 7 | # if defined(QT_BUILD_DATASYNCANDROID_LIB) 8 | # define Q_DATASYNCANDROID_EXPORT Q_DECL_EXPORT 9 | # else 10 | # define Q_DATASYNCANDROID_EXPORT Q_DECL_IMPORT 11 | # endif 12 | #else 13 | # define Q_DATASYNCANDROID_EXPORT 14 | #endif 15 | 16 | #endif // QTDATASYNCANDROID_GLOBAL_H 17 | -------------------------------------------------------------------------------- /src/messages/macupdatemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "macupdatemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | MacUpdateMessage::MacUpdateMessage(quint32 keyIndex, QByteArray cmac) : 5 | keyIndex{keyIndex}, 6 | cmac{std::move(cmac)} 7 | {} 8 | 9 | const QMetaObject *MacUpdateMessage::getMetaObject() const 10 | { 11 | return &staticMetaObject; 12 | } 13 | 14 | 15 | 16 | const QMetaObject *MacUpdateAckMessage::getMetaObject() const 17 | { 18 | return &staticMetaObject; 19 | } 20 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/syncdelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "syncdelegate.h" 2 | #include 3 | 4 | SyncDelegate::SyncDelegate(QObject *parent) : 5 | IosSyncDelegate{parent} 6 | {} 7 | 8 | //! [delegate_src] 9 | QtDataSync::IosSyncDelegate::SyncResult SyncDelegate::onSyncCompleted(QtDataSync::SyncManager::SyncState state) 10 | { 11 | qInfo() << "Finished synchronization in state:" << state; 12 | return IosSyncDelegate::onSyncCompleted(state); 13 | } 14 | //! [delegate_src] 15 | -------------------------------------------------------------------------------- /tests/auto/qml/TestQmlDataSync/TestQmlDataSync.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | TARGET = tst_qmldatasync 3 | CONFIG += qmltestcase 4 | CONFIG += console 5 | SOURCES += tst_qmldatasync.cpp 6 | 7 | QT += datasync 8 | 9 | importFiles.path = . 10 | DEPLOYMENT += importFiles 11 | 12 | DISTFILES += \ 13 | tst_qmldatasync.qml 14 | 15 | DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_/\\\" 16 | 17 | win32:msvc:CONFIG(debug, debug|release): CONFIG += disable_testrun 18 | include($$PWD/../../testrun.pri) 19 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testdata.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTDATA_H 2 | #define TESTDATA_H 3 | 4 | #include 5 | 6 | class TestData 7 | { 8 | Q_GADGET 9 | 10 | Q_PROPERTY(int id MEMBER id USER true) 11 | Q_PROPERTY(QString text MEMBER text) 12 | 13 | public: 14 | TestData(int id = -1, QString text = {}); 15 | 16 | bool operator ==(const TestData &other) const; 17 | 18 | int id; 19 | QString text; 20 | }; 21 | 22 | Q_DECLARE_METATYPE(TestData) 23 | 24 | #endif // TESTDATA_H 25 | -------------------------------------------------------------------------------- /src/datasync/changeemitter_p.rep: -------------------------------------------------------------------------------- 1 | #include "qtdatasync_global.h" 2 | #include "objectkey.h" 3 | 4 | class ChangeEmitter { 5 | SLOT(void triggerRemoteChange(const QtDataSync::ObjectKey &key, bool deleted, bool changed)); 6 | SLOT(void triggerRemoteClear(const QByteArray &typeName, const QStringList &ids)); 7 | SLOT(void triggerRemoteReset()); 8 | SLOT(void triggerUpload()); 9 | 10 | SIGNAL(remoteDataChanged(const QtDataSync::ObjectKey &key, bool deleted)); 11 | SIGNAL(remoteDataResetted()); 12 | }; 13 | -------------------------------------------------------------------------------- /src/datasyncios/datasyncios.pro: -------------------------------------------------------------------------------- 1 | TARGET = QtDataSyncIos 2 | 3 | QT = core datasync datasync-private 4 | CONFIG += no_app_extension_api_only 5 | 6 | HEADERS += \ 7 | qtdatasyncios_global.h \ 8 | qtdatasyncappdelegate_capi_p.h \ 9 | QIOSApplicationDelegate+QtDatasyncAppDelegate_p.h \ 10 | iossyncdelegate.h \ 11 | iossyncdelegate_p.h 12 | 13 | SOURCES += \ 14 | iossyncdelegate.cpp 15 | 16 | OBJECTIVE_SOURCES += \ 17 | QIOSApplicationDelegate+QtDatasyncAppDelegate.mm 18 | 19 | load(qt_module) 20 | -------------------------------------------------------------------------------- /src/messages/removemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "removemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | RemoveMessage::RemoveMessage(QUuid deviceId) : 5 | deviceId{deviceId} 6 | {} 7 | 8 | const QMetaObject *RemoveMessage::getMetaObject() const 9 | { 10 | return &staticMetaObject; 11 | } 12 | 13 | 14 | 15 | RemoveAckMessage::RemoveAckMessage(QUuid deviceId) : 16 | deviceId{deviceId} 17 | {} 18 | 19 | const QMetaObject *RemoveAckMessage::getMetaObject() const 20 | { 21 | return &staticMetaObject; 22 | } 23 | -------------------------------------------------------------------------------- /qtdatasync.pro: -------------------------------------------------------------------------------- 1 | load(qt_parts) 2 | 3 | SUBDIRS += doc 4 | 5 | doxygen.target = doxygen 6 | doxygen.CONFIG = recursive 7 | doxygen.recurse_target = doxygen 8 | doxygen.recurse += doc 9 | QMAKE_EXTRA_TARGETS += doxygen 10 | 11 | runtests.target = run-tests 12 | runtests.CONFIG = recursive 13 | runtests.recurse_target = run-tests 14 | runtests.recurse += sub_tests sub_src sub_tools 15 | QMAKE_EXTRA_TARGETS += runtests 16 | 17 | include(modeling/modeling.pri) 18 | 19 | DISTFILES += .qmake.conf \ 20 | sync.profile 21 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/syncdelegate.h: -------------------------------------------------------------------------------- 1 | #ifndef SYNCDELEGATE_H 2 | #define SYNCDELEGATE_H 3 | 4 | #include 5 | #include 6 | 7 | //! [delegate_hdr] 8 | class SyncDelegate : public QtDataSync::IosSyncDelegate 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit SyncDelegate(QObject *parent = nullptr); 14 | 15 | protected: 16 | SyncResult onSyncCompleted(QtDataSync::SyncManager::SyncState state) override; 17 | }; 18 | //! [delegate_hdr] 19 | 20 | #endif // SYNCDELEGATE_H 21 | -------------------------------------------------------------------------------- /src/datasyncandroid/androidbackgroundservice_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ANDROIDBACKGROUNDSERVICE_P_H 2 | #define QTDATASYNC_ANDROIDBACKGROUNDSERVICE_P_H 3 | 4 | #include "androidbackgroundservice.h" 5 | 6 | #include 7 | 8 | namespace QtDataSync { 9 | 10 | class AndroidBackgroundServicePrivate 11 | { 12 | public: 13 | SyncManager *manager = nullptr; 14 | int startId = -1; 15 | 16 | bool waitFullSync = true; 17 | }; 18 | 19 | } 20 | 21 | #endif // QTDATASYNC_ANDROIDBACKGROUNDSERVICE_P_H 22 | -------------------------------------------------------------------------------- /src/messages/devicekeysmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "devicekeysmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | DeviceKeysMessage::DeviceKeysMessage(quint32 keyIndex) : 5 | keyIndex{keyIndex}, 6 | duplicated{true} 7 | {} 8 | 9 | DeviceKeysMessage::DeviceKeysMessage(quint32 keyIndex, QList devices) : 10 | keyIndex{keyIndex}, 11 | duplicated{false}, 12 | devices{std::move(devices)} 13 | {} 14 | 15 | const QMetaObject *DeviceKeysMessage::getMetaObject() const 16 | { 17 | return &staticMetaObject; 18 | } 19 | -------------------------------------------------------------------------------- /src/plugins/keystores/keychain/keychain.pro: -------------------------------------------------------------------------------- 1 | TARGET = qkeychain 2 | 3 | QT += datasync 4 | QT -= gui 5 | 6 | HEADERS += \ 7 | keychainkeystoreplugin.h \ 8 | keychainkeystore.h 9 | 10 | SOURCES += \ 11 | keychainkeystoreplugin.cpp 12 | 13 | OBJECTIVE_SOURCES += \ 14 | keychainkeystore.mm 15 | 16 | DISTFILES += keychain.json 17 | 18 | LIBS += -framework Foundation -framework Security 19 | 20 | PLUGIN_TYPE = keystores 21 | PLUGIN_EXTENDS = datasync 22 | PLUGIN_CLASS_NAME = KeychainKeyStorePlugin 23 | load(qt_plugin) 24 | -------------------------------------------------------------------------------- /tools/appserver/dockerbuild/env_start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "[server]" > $QDSAPP_CONFIG_FILE 4 | echo "port=4242" >> $QDSAPP_CONFIG_FILE 5 | echo "[database]" >> $QDSAPP_CONFIG_FILE 6 | echo "host=$QDSAPP_DATABASE_HOST" >> $QDSAPP_CONFIG_FILE 7 | echo "port=$QDSAPP_DATABASE_PORT" >> $QDSAPP_CONFIG_FILE 8 | echo "username=$QDSAPP_DATABASE_USER" >> $QDSAPP_CONFIG_FILE 9 | echo "password=$QDSAPP_DATABASE_PASSWORD" >> $QDSAPP_CONFIG_FILE 10 | echo "name=$QDSAPP_DATABASE_NAME" >> $QDSAPP_CONFIG_FILE 11 | 12 | exec /usr/bin/qdsappd 13 | -------------------------------------------------------------------------------- /src/messages/changemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "changemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | ChangeMessage::ChangeMessage(QByteArray dataId) : 5 | dataId{std::move(dataId)} 6 | {} 7 | 8 | const QMetaObject *ChangeMessage::getMetaObject() const 9 | { 10 | return &staticMetaObject; 11 | } 12 | 13 | 14 | 15 | ChangeAckMessage::ChangeAckMessage(const ChangeMessage &message) : 16 | dataId{message.dataId} 17 | {} 18 | 19 | const QMetaObject *ChangeAckMessage::getMetaObject() const 20 | { 21 | return &staticMetaObject; 22 | } 23 | -------------------------------------------------------------------------------- /sync.profile: -------------------------------------------------------------------------------- 1 | %modules = ( 2 | "QtDataSync" => "$basedir/src/datasync;$basedir/src/messages", 3 | "QtDataSyncAndroid" => "$basedir/src/datasyncandroid", 4 | "QtDataSyncIos" => "$basedir/src/datasyncios", 5 | ); 6 | 7 | # Force generation of camel case headers for classes inside QtDataSync namespaces 8 | # Exception must be excluded, because it generates conflicts with the std::exception class (case-insensitive) 9 | $publicclassregexp = "QtDataSync::(?!__helpertypes|JsonObject|Exception|QtRoTransportRegistry|QtRoTransportRegistry::__private).+"; 10 | -------------------------------------------------------------------------------- /tools/appserver/qdsapp.conf: -------------------------------------------------------------------------------- 1 | [general] 2 | #threads/count= 3 | #threads/expire= 4 | #livesync= 5 | #cleanup/interval= 6 | #cleanup/auto= 7 | #quota/limit= 8 | #quota/force= 9 | #loglevel= 10 | #logIpAddress= 11 | 12 | [server] 13 | #name= 14 | #host= 15 | #port= 16 | #secret= 17 | #idleTimeout= 18 | #uploads/limit= 19 | #downloads/limit= 20 | #downloads/threshold= 21 | #wss= 22 | #wss/pfx= 23 | #wss/pass= 24 | 25 | [database] 26 | #driver= 27 | #name= 28 | #host= 29 | #port= 30 | #username= 31 | #password= 32 | #options= 33 | #keepaliveInterval= 34 | -------------------------------------------------------------------------------- /examples/datasync/Sample/sampledata.h: -------------------------------------------------------------------------------- 1 | #ifndef SAMPLEDATA_H 2 | #define SAMPLEDATA_H 3 | 4 | #include 5 | #include 6 | 7 | class SampleData 8 | { 9 | Q_GADGET 10 | 11 | Q_PROPERTY(int id MEMBER id USER true) 12 | Q_PROPERTY(QString title MEMBER title) 13 | Q_PROPERTY(QString description MEMBER description) 14 | 15 | public: 16 | int id; 17 | QString title; 18 | QString description; 19 | }; 20 | 21 | QDebug operator<<(QDebug debug, const SampleData &data); 22 | 23 | Q_DECLARE_METATYPE(SampleData) 24 | 25 | #endif // SAMPLEDATA_H 26 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestSyncController/testresolver.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTRESOLVER_H 2 | #define TESTRESOLVER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "testdata.h" 8 | 9 | class TestResolver : public QtDataSync::GenericConflictResolver 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit TestResolver(QObject *parent = nullptr); 15 | 16 | TestData resolveConflict(TestData data1, TestData data2, QObject *parent) const override; 17 | 18 | bool shouldThrow = false; 19 | }; 20 | 21 | #endif // TESTRESOLVER_H 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | /.qmake.cache 16 | /.qmake.stash 17 | *.pro.user 18 | *.pro.user.* 19 | *.qbs.user 20 | *.qbs.user.* 21 | *.moc 22 | moc_*.cpp 23 | qrc_*.cpp 24 | ui_*.h 25 | Makefile* 26 | *build-* 27 | *.qmlc 28 | 29 | # QtCreator 30 | 31 | *.autosave 32 | 33 | # QtCtreator Qml 34 | *.qmlproject.user 35 | *.qmlproject.user.* 36 | 37 | # QtCtreator CMake 38 | CMakeLists.txt.user 39 | 40 | *.json.user 41 | .qpmx-dev-cache 42 | 43 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservice.pro: -------------------------------------------------------------------------------- 1 | TARGET = qsecretservice 2 | 3 | QT += datasync 4 | QT -= gui 5 | 6 | CONFIG += link_pkgconfig 7 | PKGCONFIG += libsecret-1 8 | 9 | HEADERS += \ 10 | libsecretwrapper.h \ 11 | secretservicekeystore.h \ 12 | secretservicekeystoreplugin.h 13 | 14 | SOURCES += \ 15 | libsecretwrapper.cpp \ 16 | secretservicekeystore.cpp \ 17 | secretservicekeystoreplugin.cpp 18 | 19 | DISTFILES += \ 20 | secretservice.json 21 | 22 | PLUGIN_TYPE = keystores 23 | PLUGIN_EXTENDS = datasync 24 | PLUGIN_CLASS_NAME = GSecretKeyStorePlugin 25 | load(qt_plugin) 26 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testobject.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTOBJECT_H 2 | #define TESTOBJECT_H 3 | 4 | #include 5 | 6 | class TestObject : public QObject 7 | { 8 | Q_OBJECT 9 | 10 | Q_PROPERTY(int id MEMBER id NOTIFY idChanged USER true) 11 | Q_PROPERTY(QString text MEMBER text NOTIFY textChanged) 12 | 13 | public: 14 | Q_INVOKABLE TestObject(QObject *parent = nullptr); 15 | 16 | int id; 17 | QString text; 18 | 19 | bool equals(const TestObject *other) const; 20 | 21 | signals: 22 | void idChanged(int id); 23 | void textChanged(QString text); 24 | }; 25 | 26 | #endif // TESTOBJECT_H 27 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/AndroidSync.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += quick datasync datasyncandroid 4 | CONFIG += c++14 5 | 6 | TARGET = AndroidSync 7 | 8 | HEADERS += \ 9 | syncservice.h 10 | 11 | SOURCES += \ 12 | main.cpp \ 13 | syncservice.cpp 14 | 15 | RESOURCES += qml.qrc 16 | 17 | target.path = $$[QT_INSTALL_EXAMPLES]/datasync/$$TARGET 18 | !install_ok: INSTALLS += target 19 | 20 | DISTFILES += \ 21 | android/AndroidManifest.xml \ 22 | $$files(android/src/*, true) \ 23 | $$files(android/res/*, true) \ 24 | android/build.gradle 25 | 26 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 27 | -------------------------------------------------------------------------------- /src/datasync/syncmanager_p.rep: -------------------------------------------------------------------------------- 1 | #include "qtdatasync_global.h" 2 | #include "syncmanager.h" 3 | 4 | class SyncManagerPrivate { 5 | PROP(QString setupName READONLY) 6 | PROP(bool syncEnabled=true); 7 | PROP(QtDataSync::SyncManager::SyncState syncState=QtDataSync::SyncManager::Initializing READONLY); 8 | PROP(qreal syncProgress=-1.0 READONLY); 9 | PROP(QString lastError READONLY); 10 | 11 | SLOT(void synchronize()); 12 | SLOT(void reconnect()); 13 | 14 | SLOT(void runOnState(QUuid id, bool downloadOnly, bool triggerSync)); 15 | SIGNAL(stateReached(QUuid id, QtDataSync::SyncManager::SyncState syncState)); 16 | }; 17 | -------------------------------------------------------------------------------- /src/messages/welcomemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "welcomemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | WelcomeMessage::WelcomeMessage(bool hasChanges) : 5 | hasChanges{hasChanges} 6 | {} 7 | 8 | bool WelcomeMessage::hasKeyUpdate() const 9 | { 10 | return !key.isEmpty(); 11 | } 12 | 13 | QByteArray WelcomeMessage::signatureData(QUuid deviceId) const 14 | { 15 | // keyIndex, scheme, deviceId, key 16 | return QByteArray::number(keyIndex) + 17 | scheme + 18 | deviceId.toRfc4122() + 19 | key; 20 | } 21 | 22 | const QMetaObject *WelcomeMessage::getMetaObject() const 23 | { 24 | return &staticMetaObject; 25 | } 26 | -------------------------------------------------------------------------------- /src/java/java.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = aux 2 | 3 | CONFIG -= qt android_install 4 | 5 | javaresources.files = \ 6 | $$PWD/res \ 7 | $$PWD/src 8 | 9 | javaresources.path = $$[QT_INSTALL_PREFIX]/src/android/java 10 | 11 | INSTALLS += javaresources 12 | 13 | !prefix_build:!equals(OUT_PWD, $$PWD) { 14 | RETURN = $$escape_expand(\\n\\t) 15 | equals(QMAKE_HOST.os, Windows) { 16 | RETURN = $$escape_expand(\\r\\n\\t) 17 | } 18 | OUT_PATH = $$shell_path($$OUT_PWD) 19 | 20 | QMAKE_POST_LINK += \ 21 | $${QMAKE_COPY_DIR} $$shell_path($$PWD/res) $$OUT_PATH $$RETURN \ 22 | $${QMAKE_COPY_DIR} $$shell_path($$PWD/src) $$OUT_PATH 23 | } 24 | -------------------------------------------------------------------------------- /src/messages/keychangemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_KEYCHANGEMESSAGE_P_H 2 | #define QTDATASYNC_KEYCHANGEMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | 6 | namespace QtDataSync { 7 | 8 | class Q_DATASYNC_EXPORT KeyChangeMessage : public Message 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(quint32 nextIndex MEMBER nextIndex) 13 | 14 | public: 15 | KeyChangeMessage(quint32 nextIndex = 0); 16 | 17 | quint32 nextIndex; 18 | 19 | protected: 20 | const QMetaObject *getMetaObject() const override; 21 | }; 22 | 23 | } 24 | 25 | Q_DECLARE_METATYPE(QtDataSync::KeyChangeMessage) 26 | 27 | #endif // QTDATASYNC_KEYCHANGEMESSAGE_P_H 28 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/mockserver.h: -------------------------------------------------------------------------------- 1 | #ifndef MOCKSERVER_H 2 | #define MOCKSERVER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "mockconnection.h" 9 | 10 | class MockServer : public QObject 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit MockServer(QObject *parent = nullptr); 16 | 17 | void init(); 18 | QUrl url() const; 19 | 20 | void clear(); 21 | bool waitForConnected(MockConnection **connection, int timeout = 5000); 22 | 23 | private: 24 | QWebSocketServer *_server; 25 | 26 | QSignalSpy _connectedSpy; 27 | }; 28 | 29 | 30 | #endif // MOCKSERVER_H 31 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/syncservice.h: -------------------------------------------------------------------------------- 1 | #ifndef SYNCSERVICE_H 2 | #define SYNCSERVICE_H 3 | 4 | #include 5 | 6 | //! [droid_service_hdr] 7 | class SyncService : public QtDataSync::AndroidBackgroundService 8 | { 9 | Q_OBJECT 10 | 11 | public: 12 | explicit SyncService(int &argc, char **argv); 13 | 14 | protected: 15 | void prepareSetup(QtDataSync::Setup &setup) override; 16 | void onSyncCompleted(QtDataSync::SyncManager::SyncState state) override; 17 | QAndroidJniObject createForegroundNotification() override; 18 | }; 19 | //! [droid_service_hdr] 20 | 21 | #endif // SYNCSERVICE_H 22 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.10 2 | import QtQuick.Controls 2.4 3 | import QtQuick.Layouts 1.3 4 | import QtQuick.Window 2.10 5 | import de.skycoder42.QtDataSync 4.2 6 | 7 | Window { 8 | visible: true 9 | width: 640 10 | height: 480 11 | title: qsTr("Hello World") 12 | 13 | property IosSyncDelegate syncDelegate: IosSyncSingleton.delegate 14 | 15 | ColumnLayout { 16 | anchors.centerIn: parent 17 | 18 | CheckBox { 19 | id: cBox 20 | checked: syncDelegate.enabled 21 | onCheckedChanged: syncDelegate.enabled = cBox.checked 22 | 23 | text: qsTr("Background sync active") 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/datasync/rothreadedbackend/exchangerotransport_p.h: -------------------------------------------------------------------------------- 1 | #ifndef THREADEDCLIENT_P_H 2 | #define THREADEDCLIENT_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "qtrotransportregistry.h" 6 | 7 | namespace QtDataSync { 8 | 9 | class ThreadedQtRoServer : public QtRoTransportRegistry::Server 10 | { 11 | public: 12 | bool prepareHostNode(const QUrl &url, QRemoteObjectHostBase *host) override; 13 | }; 14 | 15 | class ThreadedQtRoClient : public QtRoTransportRegistry::Client 16 | { 17 | public: 18 | bool prepareClientNode(const QUrl &url, QRemoteObjectNode *node) override; 19 | }; 20 | 21 | } 22 | 23 | #endif // THREADEDCLIENT_P_H 24 | -------------------------------------------------------------------------------- /tests/ci/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | scriptdir=$(dirname $0) 5 | 6 | # get postgres running for ws test 7 | if [[ $PLATFORM == "gcc_64" ]]; then 8 | sudo docker run -d --rm --name datasync_postgres -e "POSTGRES_PASSWORD=baum42" postgres:latest 9 | 10 | postgresIp=$(sudo docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' datasync_postgres) 11 | echo host=$postgresIp >> ./tests/ci/qdsapp.conf 12 | echo 'SETUP_FILE=$$PWD/../../../ci/qdsapp.conf' > ./tests/auto/datasync/TestAppServer/setup.pri 13 | echo 'SETUP_FILE=$$PWD/../../../ci/qdsapp.conf' > ./tests/auto/datasync/IntegrationTest/setup.pri 14 | fi 15 | -------------------------------------------------------------------------------- /src/3rdparty/cryptopp/appveyor.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set version=7_0_0 4 | 5 | echo %PLATFORM% | findstr /C:"winrt_x64" > nul && ( 6 | set pkgName=%PLATFORM:~10%_64 7 | ) 8 | echo %PLATFORM% | findstr /C:"winrt_x86" > nul && ( 9 | set pkgName=%PLATFORM:~10% 10 | ) 11 | if "%PLATFORM%" == "mingw53_32" ( 12 | set pkgName=mingw 13 | ) 14 | if "%pkgName%" == "" ( 15 | set pkgName=%PLATFORM% 16 | ) 17 | 18 | powershell -Command "Invoke-WebRequest https://github.com/Skycoder42/ci-builds/releases/download/cryptopp_%version%/cryptopp_%version%_%pkgName%.zip -OutFile %temp%\cryptopp.zip" || exit /B 1 19 | 7z x %temp%\cryptopp.zip -o.\src\3rdparty || exit /B 1 20 | -------------------------------------------------------------------------------- /src/src.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | datasync \ 5 | plugins \ 6 | imports \ 7 | messages \ 8 | 3rdparty \ 9 | translations 10 | 11 | messages.depends += 3rdparty 12 | datasync.depends += messages 3rdparty 13 | plugins.depends += datasync 14 | imports.depends += datasync 15 | 16 | android { 17 | SUBDIRS += datasyncandroid 18 | !android-embedded: SUBDIRS += java 19 | 20 | datasyncandroid.depends += datasync java 21 | imports.depends += datasyncandroid 22 | } 23 | 24 | ios { 25 | SUBDIRS += datasyncios 26 | 27 | datasyncios.depends += datasync 28 | imports.depends += datasyncios 29 | } 30 | 31 | QMAKE_EXTRA_TARGETS += run-tests 32 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "syncdelegate.h" 4 | 5 | //! [delegate_main] 6 | int main(int argc, char *argv[]) 7 | { 8 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 9 | QGuiApplication app(argc, argv); 10 | 11 | QtDataSync::IosSyncDelegate::init(new SyncDelegate{&app}); 12 | QtDataSync::IosSyncDelegate::currentDelegate()->setEnabled(true); 13 | 14 | // ... 15 | //! [delegate_main] 16 | QQmlApplicationEngine engine; 17 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 18 | if (engine.rootObjects().isEmpty()) 19 | return -1; 20 | 21 | return app.exec(); 22 | } 23 | -------------------------------------------------------------------------------- /src/messages/devicechangemessage.cpp: -------------------------------------------------------------------------------- 1 | #include "devicechangemessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | DeviceChangeMessage::DeviceChangeMessage(QByteArray dataId, QUuid deviceId) : 5 | ChangeMessage{std::move(dataId)}, 6 | deviceId{deviceId} 7 | {} 8 | 9 | const QMetaObject *DeviceChangeMessage::getMetaObject() const 10 | { 11 | return &staticMetaObject; 12 | } 13 | 14 | 15 | 16 | DeviceChangeAckMessage::DeviceChangeAckMessage(const DeviceChangeMessage &message) : 17 | ChangeAckMessage{message}, 18 | deviceId{message.deviceId} 19 | {} 20 | 21 | const QMetaObject *DeviceChangeAckMessage::getMetaObject() const 22 | { 23 | return &staticMetaObject; 24 | } 25 | -------------------------------------------------------------------------------- /src/datasync/signal_private_connect_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SIGNAL_PRIVATE_CONNECT_P_H 2 | #define QTDATASYNC_SIGNAL_PRIVATE_CONNECT_P_H 3 | 4 | #include 5 | 6 | #define EXTEND(a, x, ...) [a](auto... args) { \ 7 | (a->*(x))(args..., __VA_ARGS__); \ 8 | } 9 | 10 | #define EXTEND_NULL(a, x, ...) [a]() { \ 11 | (a->*(x))(__VA_ARGS__); \ 12 | } 13 | 14 | #define PSIG(x) EXTEND(this, x, QPrivateSignal{}) 15 | 16 | #define PSIG_NULL(x) EXTEND_NULL(this, x, QPrivateSignal{}) 17 | 18 | #if __cplusplus >= 201402L 19 | #define LAMBDA_MV(x) x = std::move(x) 20 | #else 21 | #define LAMBDA_MV(x) x 22 | #endif 23 | 24 | #endif // QTDATASYNC_SIGNAL_PRIVATE_CONNECT_P_H 25 | -------------------------------------------------------------------------------- /src/datasyncandroid/androidsynccontrol_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ANDROIDSYNCCONTROL_P_H 2 | #define QTDATASYNC_ANDROIDSYNCCONTROL_P_H 3 | 4 | #include "androidsynccontrol.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace QtDataSync { 10 | 11 | class AndroidSyncControlPrivate 12 | { 13 | public: 14 | QString serviceId {QStringLiteral("de.skycoder42.qtservice.AndroidService")}; 15 | std::chrono::minutes interval{60}; 16 | 17 | QAndroidIntent createIntent() const; 18 | QAndroidJniObject createPendingIntent(bool allowCreate) const; 19 | }; 20 | 21 | } 22 | 23 | #endif // QTDATASYNC_ANDROIDSYNCCONTROL_P_H 24 | -------------------------------------------------------------------------------- /src/messages/accountmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ACCOUNTMESSAGE_P_H 2 | #define QTDATASYNC_ACCOUNTMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "message_p.h" 9 | 10 | namespace QtDataSync { 11 | 12 | class Q_DATASYNC_EXPORT AccountMessage : public Message 13 | { 14 | Q_GADGET 15 | 16 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 17 | 18 | public: 19 | AccountMessage(QUuid deviceId = {}); 20 | 21 | QUuid deviceId; 22 | 23 | protected: 24 | const QMetaObject *getMetaObject() const override; 25 | }; 26 | 27 | } 28 | 29 | Q_DECLARE_METATYPE(QtDataSync::AccountMessage) 30 | 31 | #endif // QTDATASYNC_ACCOUNTMESSAGE_P_H 32 | -------------------------------------------------------------------------------- /src/datasync/remoteconfig_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_REMOTECONFIG_P_H 2 | #define QTDATASYNC_REMOTECONFIG_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "remoteconfig.h" 6 | 7 | namespace QtDataSync { 8 | 9 | //no export needed 10 | class RemoteConfigPrivate : public QSharedData 11 | { 12 | public: 13 | RemoteConfigPrivate(QUrl url, 14 | QString accessKey, 15 | RemoteConfig::HeaderHash headers, 16 | int keepaliveTimeout); 17 | RemoteConfigPrivate(const RemoteConfigPrivate &other); 18 | 19 | QUrl url; 20 | QString accessKey; 21 | RemoteConfig::HeaderHash headers; 22 | int keepaliveTimeout; 23 | }; 24 | 25 | } 26 | 27 | #endif // QTDATASYNC_REMOTECONFIG_P_H 28 | -------------------------------------------------------------------------------- /doc/doc.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = aux 2 | 3 | OTHER_FILES += Doxyfile \ 4 | makedoc.sh \ 5 | doxme.py \ 6 | ../README.md \ 7 | *.dox \ 8 | snippets/*.cpp \ 9 | images/* 10 | 11 | system($$QMAKE_MKDIR $$shell_quote($$shell_path($$OUT_PWD/qtdatasync))) 12 | 13 | docTarget.target = doxygen 14 | docTarget.commands = $$PWD/makedoc.sh "$$PWD" "$$MODULE_VERSION" "$$[QT_INSTALL_BINS]" "$$[QT_INSTALL_HEADERS]" "$$[QT_INSTALL_DOCS]" 15 | QMAKE_EXTRA_TARGETS += docTarget 16 | 17 | docInst1.path = $$[QT_INSTALL_DOCS] 18 | docInst1.files = $$OUT_PWD/qtdatasync.qch 19 | docInst1.CONFIG += no_check_exist 20 | docInst2.path = $$[QT_INSTALL_DOCS] 21 | docInst2.files = $$OUT_PWD/qtdatasync 22 | INSTALLS += docInst1 docInst2 23 | -------------------------------------------------------------------------------- /src/datasync/datastore_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_DATASTORE_P_H 2 | #define QTDATASYNC_DATASTORE_P_H 3 | 4 | #include 5 | 6 | #include "qtdatasync_global.h" 7 | #include "datastore.h" 8 | #include "defaults.h" 9 | #include "logger.h" 10 | #include "localstore_p.h" 11 | 12 | namespace QtDataSync { 13 | 14 | //no export needed 15 | class DataStorePrivate 16 | { 17 | public: 18 | DataStorePrivate(DataStore *q, const QString &setupName); 19 | 20 | QByteArray typeName(int metaTypeId) const; 21 | 22 | Defaults defaults; 23 | Logger *logger; 24 | QPointer serializer; 25 | 26 | LocalStore *store; 27 | }; 28 | 29 | } 30 | 31 | #endif // QTDATASYNC_DATASTORE_P_H 32 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plainkeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAINKEYSTOREPLUGIN_H 2 | #define PLAINKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class PlainKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "plain.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | PlainKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // PLAINKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /examples/datasync/Sample/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | services: 3 | datasync_postgres: 4 | container_name: datasync_postgres 5 | image: postgres:latest 6 | environment: 7 | POSTGRES_PASSWORD: baum42 8 | PGDATA: /var/lib/postgresql/data/pgdata 9 | volumes: 10 | - datasync_postgres_data:/var/lib/postgresql/data/pgdata 11 | datasync_qdsapp: 12 | container_name: datasync_qdsapp 13 | image: skycoder42/qdsapp:latest 14 | depends_on: 15 | - datasync_postgres 16 | ports: 17 | - "4242:4242/tcp" 18 | environment: 19 | QDSAPP_DATABASE_HOST: datasync_postgres 20 | QDSAPP_DATABASE_PASSWORD: baum42 21 | volumes: 22 | datasync_postgres_data: 23 | -------------------------------------------------------------------------------- /tools/appserver/qdsapp.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=QtDataSync AppServer Service 3 | Documentation=https://github.com/Skycoder42/QtDataSync 4 | After=network-online.target $${APPNAME}.socket 5 | 6 | [Service] 7 | Type=notify 8 | NotifyAccess=exec 9 | ExecStart=$$[QT_INSTALL_BINS]/$${TARGET} --backend systemd 10 | ExecReload=$$[QT_INSTALL_BINS]/$${TARGET} --backend systemd reload $MAINPID 11 | ExecStop=$$[QT_INSTALL_BINS]/$${TARGET} --backend systemd stop $MAINPID 12 | WatchdogSec=10 13 | Restart=on-abnormal 14 | RuntimeDirectory=$${APPNAME} 15 | 16 | [Install] 17 | # Use the following for a system service 18 | #WantedBy=multi-user.target 19 | # Use the following for a user service 20 | #WantedBy=default.target 21 | -------------------------------------------------------------------------------- /src/plugins/keystores/android/androidkeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef ANDROIDKEYSTOREPLUGIN_H 2 | #define ANDROIDKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class AndroidKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "android.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | AndroidKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // ANDROIDKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /src/plugins/keystores/kwallet/kwalletkeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef KWALLETKEYSTOREPLUGIN_H 2 | #define KWALLETKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class KWalletKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "kwallet.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | KWalletKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // KWALLETKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/main.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.10 2 | import QtQuick.Window 2.10 3 | import QtQuick.Controls 2.4 4 | import QtQuick.Layouts 1.3 5 | import de.skycoder42.QtDataSync 4.2 6 | 7 | Window { 8 | visible: true 9 | width: 640 10 | height: 480 11 | title: qsTr("Hello World") 12 | 13 | AndroidSyncControl { 14 | id: syncControl 15 | } 16 | 17 | ColumnLayout { 18 | anchors.centerIn: parent 19 | 20 | CheckBox { 21 | id: cBox 22 | checked: syncControl.enabled 23 | onCheckedChanged: syncControl.enabled = cBox.checked 24 | 25 | text: qsTr("Background sync active") 26 | } 27 | 28 | Button { 29 | text: qsTr("Sync now") 30 | onClicked: syncControl.triggerSyncNow() 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/plugins/keystores/keychain/keychainkeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYCHAINKEYSTOREPLUGIN_H 2 | #define KEYCHAINKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class KeychainKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "keychain.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | KeychainKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // KEYCHAINKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /src/plugins/keystores/wincred/wincredkeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef WINCREDKEYSTOREPLUGIN_H 2 | #define WINCREDKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class WinCredKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "wincred.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | WinCredKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // WINCREDKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plainkeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "plainkeystoreplugin.h" 2 | #include "plainkeystore.h" 3 | 4 | #include 5 | 6 | PlainKeyStorePlugin::PlainKeyStorePlugin(QObject *parent) : 7 | QObject(parent), 8 | KeyStorePlugin() 9 | {} 10 | 11 | bool PlainKeyStorePlugin::keystoreAvailable(const QString &provider) const 12 | { 13 | if(provider == QStringLiteral("plain")) 14 | return true; 15 | else 16 | return false; 17 | } 18 | 19 | QtDataSync::KeyStore *PlainKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 20 | { 21 | if(provider == QStringLiteral("plain")) 22 | return new PlainKeyStore(defaults, parent); 23 | else 24 | return nullptr; 25 | } 26 | -------------------------------------------------------------------------------- /src/plugins/keystores/kwallet/kwalletkeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "kwalletkeystoreplugin.h" 2 | #include "kwalletkeystore.h" 3 | 4 | KWalletKeyStorePlugin::KWalletKeyStorePlugin(QObject *parent) : 5 | QObject(parent), 6 | KeyStorePlugin() 7 | {} 8 | 9 | QtDataSync::KeyStore *KWalletKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 10 | { 11 | if(provider == QStringLiteral("kwallet")) 12 | return new KWalletKeyStore(defaults, parent); 13 | else 14 | return nullptr; 15 | } 16 | 17 | bool KWalletKeyStorePlugin::keystoreAvailable(const QString &provider) const 18 | { 19 | if(provider == QStringLiteral("kwallet")) 20 | return KWallet::Wallet::isEnabled(); 21 | else 22 | return false; 23 | } 24 | -------------------------------------------------------------------------------- /src/datasync/qtdatasync_global.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_GLOBAL_H 2 | #define QTDATASYNC_GLOBAL_H 3 | 4 | #include 5 | #include 6 | 7 | #ifndef QT_STATIC 8 | # if defined(QT_BUILD_DATASYNC_LIB) 9 | # define Q_DATASYNC_EXPORT Q_DECL_EXPORT 10 | # else 11 | # define Q_DATASYNC_EXPORT Q_DECL_IMPORT 12 | # endif 13 | #else 14 | # define Q_DATASYNC_EXPORT 15 | #endif 16 | 17 | #ifdef DOXYGEN_RUN 18 | #define QT_DATASYNC_REVISION_2 19 | #else 20 | #define QT_DATASYNC_REVISION_2 Q_REVISION(2) 21 | #endif 22 | 23 | //! The primary namespace of the QtDataSync library 24 | namespace QtDataSync { 25 | //! The default setup name 26 | extern Q_DATASYNC_EXPORT const QString DefaultSetup; 27 | } 28 | 29 | #endif // QTDATASYNC_GLOBAL_H 30 | -------------------------------------------------------------------------------- /tools/appserver/de.skycoder42.qtdatasync.qdsapp.plist.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | de.skycoder42.qtdatasync.qdsapp 7 | ProgramArguments 8 | 9 | $$[QT_INSTALL_BINS]/$${TARGET} 10 | --backend 11 | launchd 12 | 13 | RunAtLoad 14 | false 15 | Sockets 16 | 17 | Listeners 18 | 19 | SockServiceName 20 | 4242 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/messages/newkeymessage.cpp: -------------------------------------------------------------------------------- 1 | #include "newkeymessage_p.h" 2 | using namespace QtDataSync; 3 | using std::get; 4 | 5 | QByteArray NewKeyMessage::signatureData(const NewKeyMessage::KeyUpdate &deviceInfo) const 6 | { 7 | // keyIndex, scheme, deviceId, key 8 | return QByteArray::number(keyIndex) + 9 | scheme + 10 | get<0>(deviceInfo).toRfc4122() + 11 | get<1>(deviceInfo); 12 | } 13 | 14 | const QMetaObject *NewKeyMessage::getMetaObject() const 15 | { 16 | return &staticMetaObject; 17 | } 18 | 19 | 20 | 21 | NewKeyAckMessage::NewKeyAckMessage(const NewKeyMessage &message) : 22 | MacUpdateAckMessage{}, 23 | keyIndex{message.keyIndex} 24 | {} 25 | 26 | const QMetaObject *NewKeyAckMessage::getMetaObject() const 27 | { 28 | return &staticMetaObject; 29 | } 30 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservicekeystoreplugin.h: -------------------------------------------------------------------------------- 1 | #ifndef SECRETSERVICEKEYSTOREPLUGIN_H 2 | #define SECRETSERVICEKEYSTOREPLUGIN_H 3 | 4 | #include 5 | 6 | class SecretServiceKeyStorePlugin : public QObject, public QtDataSync::KeyStorePlugin 7 | { 8 | Q_OBJECT 9 | Q_PLUGIN_METADATA(IID QtDataSync_KeyStorePlugin_Iid FILE "secretservice.json") 10 | Q_INTERFACES(QtDataSync::KeyStorePlugin) 11 | 12 | public: 13 | SecretServiceKeyStorePlugin(QObject *parent = nullptr); 14 | 15 | bool keystoreAvailable(const QString &provider) const override; 16 | QtDataSync::KeyStore *createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) override; 17 | }; 18 | 19 | #endif // SECRETSERVICEKEYSTOREPLUGIN_H 20 | -------------------------------------------------------------------------------- /src/plugins/keystores/android/androidkeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "androidkeystoreplugin.h" 2 | #include "androidkeystore.h" 3 | 4 | #include 5 | 6 | AndroidKeyStorePlugin::AndroidKeyStorePlugin(QObject *parent) : 7 | QObject(parent), 8 | KeyStorePlugin() 9 | {} 10 | 11 | bool AndroidKeyStorePlugin::keystoreAvailable(const QString &provider) const 12 | { 13 | if(provider == QStringLiteral("android")) 14 | return true; 15 | else 16 | return false; 17 | } 18 | 19 | QtDataSync::KeyStore *AndroidKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 20 | { 21 | if(provider == QStringLiteral("android")) 22 | return new AndroidKeyStore(defaults, parent); 23 | else 24 | return nullptr; 25 | } 26 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/mockclient.cpp: -------------------------------------------------------------------------------- 1 | #include "mockclient.h" 2 | 3 | #ifdef Q_OS_WIN 4 | #define WAIT_TIMEOUT 15000 5 | #else 6 | #define WAIT_TIMEOUT 10000 7 | #endif 8 | 9 | MockClient::MockClient(QObject *parent) : 10 | MockConnection(new QWebSocket(), parent), 11 | _connectSpy(_socket, &QWebSocket::connected) 12 | {} 13 | 14 | bool MockClient::waitForConnected(quint16 port) 15 | { 16 | QUrl url; 17 | url.setScheme(QStringLiteral("ws")); 18 | url.setHost(QHostAddress(QHostAddress::LocalHost).toString()); 19 | url.setPort(port); 20 | _socket->open(url); 21 | 22 | auto ok = false; 23 | [&]() { 24 | if(_connectSpy.isEmpty()) 25 | QVERIFY(_connectSpy.wait(WAIT_TIMEOUT)); 26 | QVERIFY(!_connectSpy.isEmpty()); 27 | ok = true; 28 | }(); 29 | return ok; 30 | } 31 | -------------------------------------------------------------------------------- /src/plugins/keystores/keychain/keychainkeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "keychainkeystoreplugin.h" 2 | #include "keychainkeystore.h" 3 | 4 | #include 5 | 6 | KeychainKeyStorePlugin::KeychainKeyStorePlugin(QObject *parent) : 7 | QObject(parent), 8 | KeyStorePlugin() 9 | {} 10 | 11 | bool KeychainKeyStorePlugin::keystoreAvailable(const QString &provider) const 12 | { 13 | if(provider == QStringLiteral("keychain")) 14 | return true; 15 | else 16 | return false; 17 | } 18 | 19 | QtDataSync::KeyStore *KeychainKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 20 | { 21 | if(provider == QStringLiteral("keychain")) 22 | return new KeychainKeyStore(defaults, parent); 23 | else 24 | return nullptr; 25 | } 26 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestSyncController/testresolver.cpp: -------------------------------------------------------------------------------- 1 | #include "testresolver.h" 2 | 3 | TestResolver::TestResolver(QObject *parent) : 4 | GenericConflictResolver(parent) 5 | {} 6 | 7 | TestData TestResolver::resolveConflict(TestData data1, TestData data2, QObject *parent) const 8 | { 9 | Q_ASSERT(parent); 10 | Q_ASSERT_X(data1.id == data2.id, Q_FUNC_INFO, "resolveConflict called on different datasets"); 11 | 12 | TestData resData(data1.id); 13 | if(shouldThrow) 14 | throw NoConflictResultException{}; 15 | if(data1.text < data2.text) 16 | resData.text = data1.text + QStringLiteral("+conflict"); 17 | else if(data2.text < data1.text) 18 | resData.text = data2.text + QStringLiteral("+conflict"); 19 | else 20 | throw NoConflictResultException{}; 21 | return resData; 22 | } 23 | -------------------------------------------------------------------------------- /doc/qtdatasync.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @namespace de::skycoder42::QtDataSync 3 | @brief The QML import for the QtDataSync QML module 4 | 5 | Current Version
6 |         4.2 7 | 8 | Available Types 9 | - @ref QtDataSync::DeviceInfo "DeviceInfo" (uncreatable) 10 | - @ref QtDataSync::LoginRequest "LoginRequest" (uncreatable) 11 | - @ref QtDataSync::UserInfo "UserInfo" (uncreatable) 12 | - @ref QtDataSync::EventCursor "EventCursor" (uncreatable) 13 | - DataStore 14 | - DataStoreModel 15 | - SyncManager 16 | - AccountManager 17 | - UserExchangeManager 18 | - EventLog (singleton) 19 | - @ref QtDataSync::AndroidSyncControl "AndroidSyncControl" 20 | - @ref QtDataSync::IosSyncDelegate "IosSyncDelegate" (uncreatable) 21 | - IosSyncSingleton (singleton) 22 | */ 23 | -------------------------------------------------------------------------------- /src/datasync/synchelper_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SYNCHELPER_P_H 2 | #define QTDATASYNC_SYNCHELPER_P_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "qtdatasync_global.h" 9 | #include "objectkey.h" 10 | 11 | namespace QtDataSync { 12 | 13 | namespace SyncHelper { 14 | 15 | //exports are needed for tests 16 | Q_DATASYNC_EXPORT QByteArray jsonHash(const QJsonObject &object); 17 | 18 | Q_DATASYNC_EXPORT QByteArray combine(const ObjectKey &key, quint64 version, const QJsonObject &data); 19 | Q_DATASYNC_EXPORT QByteArray combine(const ObjectKey &key, quint64 version); 20 | Q_DATASYNC_EXPORT std::tuple extract(const QByteArray &data); // (deleted, key, version, data) 21 | 22 | } 23 | 24 | } 25 | 26 | #endif // QTDATASYNC_SYNCHELPER_P_H 27 | -------------------------------------------------------------------------------- /src/plugins/keystores/wincred/wincredkeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "wincredkeystoreplugin.h" 2 | #include "wincredkeystore.h" 3 | 4 | #include 5 | 6 | WinCredKeyStorePlugin::WinCredKeyStorePlugin(QObject *parent) : 7 | QObject(parent), 8 | KeyStorePlugin() 9 | {} 10 | 11 | bool WinCredKeyStorePlugin::keystoreAvailable(const QString &provider) const 12 | { 13 | if(provider == QStringLiteral("wincred")) 14 | return true; 15 | else 16 | return false; 17 | } 18 | 19 | QtDataSync::KeyStore *WinCredKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 20 | { 21 | if(provider == QStringLiteral("wincred")) 22 | return new WinCredKeyStore(defaults, parent); 23 | else 24 | return nullptr; 25 | } 26 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | https://download.qt.io/ministro/android/qt5/qt-5.9 5 | 6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/messages/loginmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_LOGINMESSAGE_P_H 2 | #define QTDATASYNC_LOGINMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | #include "identifymessage_p.h" 8 | 9 | namespace QtDataSync { 10 | 11 | class Q_DATASYNC_EXPORT LoginMessage : public InitMessage 12 | { 13 | Q_GADGET 14 | 15 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 16 | Q_PROPERTY(QtDataSync::Utf8String deviceName MEMBER deviceName) 17 | 18 | public: 19 | LoginMessage(QUuid deviceId = {}, QString deviceName = {}, QByteArray nonce = {}); 20 | 21 | QUuid deviceId; 22 | Utf8String deviceName; 23 | 24 | protected: 25 | const QMetaObject *getMetaObject() const override; 26 | }; 27 | 28 | } 29 | 30 | Q_DECLARE_METATYPE(QtDataSync::LoginMessage) 31 | 32 | #endif // QTDATASYNC_LOGINMESSAGE_P_H 33 | -------------------------------------------------------------------------------- /src/messages/changedmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "changedmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | const QMetaObject *ChangedMessage::getMetaObject() const 5 | { 6 | return &staticMetaObject; 7 | } 8 | 9 | 10 | 11 | ChangedInfoMessage::ChangedInfoMessage(quint32 changeEstimate) : 12 | ChangedMessage{}, 13 | changeEstimate{changeEstimate} 14 | {} 15 | 16 | const QMetaObject *ChangedInfoMessage::getMetaObject() const 17 | { 18 | return &staticMetaObject; 19 | } 20 | 21 | 22 | 23 | const QMetaObject *LastChangedMessage::getMetaObject() const 24 | { 25 | return &staticMetaObject; 26 | } 27 | 28 | 29 | 30 | ChangedAckMessage::ChangedAckMessage(quint64 dataIndex) : 31 | dataIndex{dataIndex} 32 | {} 33 | 34 | const QMetaObject *ChangedAckMessage::getMetaObject() const 35 | { 36 | return &staticMetaObject; 37 | } 38 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plainkeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef PLAINKEYSTORE_H 2 | #define PLAINKEYSTORE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | class PlainKeyStore : public QtDataSync::KeyStore 9 | { 10 | Q_OBJECT 11 | 12 | public: 13 | explicit PlainKeyStore(const QtDataSync::Defaults &defaults, QObject *parent = nullptr); 14 | 15 | QString providerName() const override; 16 | bool isOpen() const override; 17 | void openStore() override; 18 | void closeStore() override; 19 | bool contains(const QString &key) const override; 20 | void save(const QString &key, const QByteArray &pKey) override; 21 | QByteArray load(const QString &key) override; 22 | void remove(const QString &key) override; 23 | 24 | private: 25 | QSettings *_settings; 26 | }; 27 | 28 | #endif // PLAINKEYSTORE_H 29 | -------------------------------------------------------------------------------- /src/datasync/synccontroller_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SYNCCONTROLLER_P_H 2 | #define QTDATASYNC_SYNCCONTROLLER_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "controller_p.h" 6 | #include "localstore_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT SyncController : public Controller 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit SyncController(const Defaults &defaults, QObject *parent = nullptr); 16 | 17 | void initialize(const QVariantHash ¶ms) override; 18 | 19 | public Q_SLOTS: 20 | void setSyncEnabled(bool enabled); 21 | void syncChange(quint64 key, const QByteArray &changeData); 22 | 23 | Q_SIGNALS: 24 | void syncDone(quint64 key); 25 | 26 | private: 27 | LocalStore *_store = nullptr; 28 | bool _enabled = false; 29 | }; 30 | 31 | } 32 | 33 | #endif // QTDATASYNC_SYNCCONTROLLER_P_H 34 | -------------------------------------------------------------------------------- /src/messages/grantmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_GRANTMESSAGE_P_H 2 | #define QTDATASYNC_GRANTMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | #include "accountmessage_p.h" 6 | #include "proofmessage_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT GrantMessage : public AccountMessage 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(quint32 index MEMBER index) 15 | Q_PROPERTY(QByteArray scheme MEMBER scheme) 16 | Q_PROPERTY(QByteArray secret MEMBER secret) 17 | 18 | public: 19 | GrantMessage(); 20 | GrantMessage(const AcceptMessage &message); 21 | 22 | quint32 index = 0; 23 | QByteArray scheme; 24 | QByteArray secret; 25 | 26 | protected: 27 | const QMetaObject *getMetaObject() const override; 28 | }; 29 | 30 | } 31 | 32 | Q_DECLARE_METATYPE(QtDataSync::GrantMessage) 33 | 34 | #endif // QTDATASYNC_GRANTMESSAGE_P_H 35 | -------------------------------------------------------------------------------- /tools/appserver/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '2.2' 2 | services: 3 | datasync_postgres: 4 | container_name: datasync_example_postgres 5 | image: postgres:latest 6 | ports: 7 | - "15432:5432/tcp" 8 | environment: 9 | POSTGRES_USER: qtdatasync 10 | POSTGRES_PASSWORD: baum42 11 | POSTGRES_DB: QtDataSync 12 | PGDATA: /var/lib/postgresql/data/pgdata 13 | volumes: 14 | - datasync_example_postgres_data:/var/lib/postgresql/data/pgdata 15 | datasync_pgAdmin: 16 | container_name: datasync_example_pgAdmin 17 | image: thajeztah/pgadmin4:latest 18 | depends_on: 19 | - datasync_postgres 20 | ports: 21 | - "5050:5050/tcp" 22 | volumes: 23 | - datasync_example_pgAdmin_data:/pgadmin 24 | volumes: 25 | datasync_example_postgres_data: 26 | datasync_example_pgAdmin_data: 27 | -------------------------------------------------------------------------------- /src/messages/accessmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "accessmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | AccessMessage::AccessMessage() = default; 5 | 6 | AccessMessage::AccessMessage(QString deviceName, QByteArray nonce, const QSharedPointer &signKey, const QSharedPointer &cryptKey, AsymmetricCrypto *crypto, QByteArray pNonce, QUuid partnerId, QByteArray macscheme, QByteArray cmac, QByteArray trustmac) : 7 | RegisterBaseMessage{std::move(deviceName), 8 | std::move(nonce), 9 | signKey, 10 | cryptKey, 11 | crypto}, 12 | pNonce{std::move(pNonce)}, 13 | partnerId{partnerId}, 14 | macscheme{std::move(macscheme)}, 15 | cmac{std::move(cmac)}, 16 | trustmac{std::move(trustmac)} 17 | {} 18 | 19 | const QMetaObject *AccessMessage::getMetaObject() const 20 | { 21 | return &staticMetaObject; 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/keystores/kwallet/kwalletkeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef KWALLETKEYSTORE_H 2 | #define KWALLETKEYSTORE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include 9 | 10 | class KWalletKeyStore : public QtDataSync::KeyStore 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit KWalletKeyStore(const QtDataSync::Defaults &defaults, QObject *parent = nullptr); 16 | 17 | QString providerName() const override; 18 | bool isOpen() const override; 19 | void openStore() override; 20 | void closeStore() override; 21 | bool contains(const QString &key) const override; 22 | void save(const QString &key, const QByteArray &pKey) override; 23 | QByteArray load(const QString &key) override; 24 | void remove(const QString &key) override; 25 | 26 | private: 27 | QPointer _wallet; 28 | }; 29 | 30 | #endif // KWALLETKEYSTORE_H 31 | -------------------------------------------------------------------------------- /examples/datasync/Sample/widget.h: -------------------------------------------------------------------------------- 1 | #ifndef WIDGET_H 2 | #define WIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace Ui { 9 | class Widget; 10 | } 11 | 12 | class Widget : public QWidget 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | explicit Widget(const QString &setup, QWidget *parent = nullptr); 18 | ~Widget(); 19 | 20 | private slots: 21 | void selectionChange(const QModelIndex &index); 22 | void updateState(QtDataSync::SyncManager::SyncState state); 23 | 24 | void on_addButton_clicked(); 25 | void on_deleteButton_clicked(); 26 | void on_clearButton_clicked(); 27 | 28 | void on_accountButton_clicked(); 29 | 30 | private: 31 | const QString _setup; 32 | Ui::Widget *ui; 33 | QtDataSync::SyncManager *_manager; 34 | QtDataSync::DataStoreModel *_model; 35 | }; 36 | 37 | #endif // WIDGET_H 38 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/TestLib.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | QT += datasync-private testlib 4 | # TODO why tho 5 | !linux: CONFIG += static 6 | linux: DESTDIR = $$shadowed($$dirname(_QMAKE_CONF_))/lib 7 | 8 | HEADERS += \ 9 | testlib.h \ 10 | testdata.h \ 11 | testobject.h \ 12 | mockserver.h \ 13 | mockconnection.h \ 14 | mockclient.h 15 | 16 | SOURCES += \ 17 | testlib.cpp \ 18 | testdata.cpp \ 19 | testobject.cpp \ 20 | mockserver.cpp \ 21 | mockconnection.cpp \ 22 | mockclient.cpp 23 | 24 | INCLUDEPATH += ../../../../src/messages 25 | 26 | verbose_tests: DEFINES += VERBOSE_TESTS 27 | 28 | include(../../../../src/3rdparty/cryptopp/cryptopp.pri) 29 | 30 | runtarget.target = run-tests 31 | win32: runtarget.depends += $(DESTDIR_TARGET) 32 | else:linux: runtarget.depends += $(DESTDIR)$(TARGET) 33 | else: runtarget.depends += $(TARGET) 34 | QMAKE_EXTRA_TARGETS += runtarget 35 | -------------------------------------------------------------------------------- /tests/auto/qml/TestQmlDataSync/tst_qmldatasync.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace QtDataSync; 6 | 7 | static QTemporaryDir tDir; 8 | 9 | static void initImportPath() 10 | { 11 | #ifdef VERBOSE_TESTS 12 | QLoggingCategory::setFilterRules(QStringLiteral("qtdatasync.*.debug=true")); 13 | #endif 14 | 15 | tDir.setAutoRemove(false); 16 | qInfo() << "storage path:" << tDir.path(); 17 | Setup().setLocalDir(tDir.path()) 18 | .setKeyStoreProvider(QStringLiteral("plain")) 19 | .setSignatureScheme(Setup::RSA_PSS_SHA3_512) 20 | .setSignatureKeyParam(2048) 21 | .setEncryptionScheme(Setup::RSA_OAEP_SHA3_512) 22 | .setEncryptionKeyParam(2048) 23 | .setEventLoggingMode(Setup::EventMode::Enabled) 24 | .create(); 25 | } 26 | Q_COREAPP_STARTUP_FUNCTION(initImportPath) 27 | 28 | QUICK_TEST_MAIN(qmldatasync) 29 | -------------------------------------------------------------------------------- /src/imports/datasync/qqmliossyncsingleton.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLIOSSYNCSINGLETON_H 2 | #define QQMLIOSSYNCSINGLETON_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #ifdef DOXYGEN_RUN 9 | namespace de::skycoder42::QtDataSync { 10 | 11 | /*! @brief The QML bindings for the static methods of of QtDataSync::EventCursor 12 | * 13 | * @extends QtQml.QtObject 14 | * @since 4.2 15 | * 16 | * @sa QtDataSync::IosSyncDelegate 17 | */ 18 | class IosSyncSingleton 19 | #else 20 | namespace QtDataSync { 21 | 22 | class QQmlIosSyncSingleton : public QObject 23 | #endif 24 | { 25 | Q_OBJECT 26 | 27 | public: 28 | //! @private 29 | explicit QQmlIosSyncSingleton(QObject *parent = nullptr); 30 | 31 | //! Returns the currently registered sync delegate 32 | Q_INVOKABLE QtDataSync::IosSyncDelegate *delegate() const; 33 | }; 34 | 35 | } 36 | 37 | #endif // QQMLIOSSYNCSINGLETON_H 38 | -------------------------------------------------------------------------------- /doc/doxme.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # $1 The readme to be transformed 3 | # $pwd: dest dir 4 | 5 | import sys 6 | 7 | def readFirst(line, out): 8 | if line[0:2] != "# ": 9 | raise ValueError("Expected first line to start with '# '") 10 | # skip the first line 11 | out.write("[TOC]\n\n") 12 | 13 | readCounter = 0 14 | def readMore(line, out): 15 | global readCounter 16 | if line[0:2] == "##": 17 | out.write(line[1:] + " {{#qtdatasync_readme_label_{}}}\n".format(readCounter)) 18 | readCounter += 1 19 | else: 20 | out.write(line + "\n") 21 | 22 | #read args 23 | readme = sys.argv[1] 24 | doxme = "./README.md" 25 | 26 | inFile = open(readme, "r") 27 | outFile = open(doxme, "w") 28 | 29 | isFirst = True 30 | for line in inFile: 31 | if isFirst: 32 | readFirst(line[:-1], outFile) 33 | isFirst = False 34 | else: 35 | readMore(line[:-1], outFile) 36 | 37 | inFile.close(); 38 | outFile.close(); 39 | -------------------------------------------------------------------------------- /src/translations/translations.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = aux 2 | 3 | QDEP_LUPDATE_INPUTS += $$PWD/../datasync 4 | QDEP_LUPDATE_INPUTS += $$PWD/../datasyncandroid 5 | QDEP_LUPDATE_INPUTS += $$PWD/../datasyncios 6 | QDEP_LUPDATE_INPUTS += $$PWD/../imports 7 | QDEP_LUPDATE_INPUTS += $$PWD/../java 8 | QDEP_LUPDATE_INPUTS += $$PWD/../messages 9 | QDEP_LUPDATE_INPUTS += $$PWD/../plugins 10 | 11 | TRANSLATIONS += \ 12 | qtdatasync_de.ts \ 13 | qtdatasync_template.ts 14 | 15 | CONFIG += lrelease 16 | QM_FILES_INSTALL_PATH = $$[QT_INSTALL_TRANSLATIONS] 17 | 18 | QDEP_DEPENDS += 19 | 20 | !load(qdep):error("Failed to load qdep feature! Run 'qdep prfgen --qmake $$QMAKE_QMAKE' to create it.") 21 | 22 | #replace template qm by ts 23 | QM_FILES -= $$__qdep_lrelease_real_dir/qtdatasync_template.qm 24 | QM_FILES += qtdatasync_template.ts 25 | 26 | HEADERS = 27 | SOURCES = 28 | GENERATED_SOURCES = 29 | OBJECTIVE_SOURCES = 30 | RESOURCES = 31 | -------------------------------------------------------------------------------- /src/datasync/rothreadedbackend/exchangerotransport.cpp: -------------------------------------------------------------------------------- 1 | #include "exchangerotransport_p.h" 2 | #include "exchangebuffer_p.h" 3 | #include "exchangebufferserver_p.h" 4 | using namespace QtDataSync; 5 | 6 | bool ThreadedQtRoServer::prepareHostNode(const QUrl &url, QRemoteObjectHostBase *host) 7 | { 8 | auto server = new ExchangeBufferServer{host}; 9 | if(server->registerInstance(url)) 10 | return true; 11 | else { 12 | delete server; 13 | return false; 14 | } 15 | } 16 | 17 | bool ThreadedQtRoClient::prepareClientNode(const QUrl &url, QRemoteObjectNode *node) 18 | { 19 | auto buffer = new ExchangeBuffer{node}; 20 | QObject::connect(buffer, &ExchangeBuffer::partnerConnected, 21 | node, [buffer, node]() { 22 | node->addClientSideConnection(buffer); 23 | }); 24 | 25 | if(ExchangeBufferServer::connectTo(url, buffer)) 26 | return true; 27 | else { 28 | delete buffer; 29 | return false; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/plugins/keystores/wincred/wincredkeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef WINCREDKEYSTORE_H 2 | #define WINCREDKEYSTORE_H 3 | 4 | #include 5 | 6 | class WinCredKeyStore : public QtDataSync::KeyStore 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | explicit WinCredKeyStore(const QtDataSync::Defaults &defaults, QObject *parent = nullptr); 12 | 13 | QString providerName() const override; 14 | bool isOpen() const override; 15 | void openStore() override; 16 | void closeStore() override; 17 | bool contains(const QString &key) const override; 18 | void save(const QString &key, const QByteArray &pKey) override; 19 | QByteArray load(const QString &key) override; 20 | void remove(const QString &key) override; 21 | 22 | private: 23 | bool _open; 24 | 25 | static QString fullKey(const QString &key); 26 | QByteArray tryLoad(const QString &key) const; 27 | }; 28 | 29 | #endif // WINCREDKEYSTORE_H 30 | -------------------------------------------------------------------------------- /src/datasync/qtdatasync_global.cpp: -------------------------------------------------------------------------------- 1 | #include "qtdatasync_global.h" 2 | #include "objectkey.h" 3 | #include "changecontroller_p.h" 4 | 5 | #include "exchangerotransport_p.h" 6 | #include "exchangebufferserver_p.h" 7 | 8 | #include 9 | #include "message_p.h" 10 | 11 | const QString QtDataSync::DefaultSetup(QStringLiteral("default")); 12 | 13 | namespace { 14 | 15 | void setupQtDataSync() 16 | { 17 | qRegisterMetaType(); 18 | qRegisterMetaType(); 19 | qRegisterMetaTypeStreamOperators(); 20 | 21 | QtDataSync::QtRoTransportRegistry::registerTransport(QtDataSync::ExchangeBufferServer::UrlScheme(), 22 | new QtDataSync::ThreadedQtRoServer{}, 23 | new QtDataSync::ThreadedQtRoClient{}); 24 | 25 | QtDataSync::Message::registerTypes(); 26 | } 27 | 28 | } 29 | Q_COREAPP_STARTUP_FUNCTION(setupQtDataSync) 30 | -------------------------------------------------------------------------------- /src/messages/macupdatemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_MACUPDATEMESSAGE_P_H 2 | #define QTDATASYNC_MACUPDATEMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | 6 | namespace QtDataSync { 7 | 8 | class Q_DATASYNC_EXPORT MacUpdateMessage : public Message 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 13 | Q_PROPERTY(QByteArray cmac MEMBER cmac) 14 | 15 | public: 16 | MacUpdateMessage(quint32 keyIndex = 0, QByteArray cmac = {}); 17 | 18 | quint32 keyIndex; 19 | QByteArray cmac; 20 | 21 | protected: 22 | const QMetaObject *getMetaObject() const override; 23 | }; 24 | 25 | class Q_DATASYNC_EXPORT MacUpdateAckMessage : public Message 26 | { 27 | Q_GADGET 28 | 29 | protected: 30 | const QMetaObject *getMetaObject() const override; 31 | }; 32 | 33 | } 34 | 35 | Q_DECLARE_METATYPE(QtDataSync::MacUpdateMessage) 36 | Q_DECLARE_METATYPE(QtDataSync::MacUpdateAckMessage) 37 | 38 | #endif // QTDATASYNC_MACUPDATEMESSAGE_P_H 39 | -------------------------------------------------------------------------------- /tests/auto/datasync/datasync.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | TestLib \ 5 | TestSetup \ 6 | TestLocalStore \ 7 | TestDataStore \ 8 | TestDataTypeStore \ 9 | TestChangeController \ 10 | TestCryptoController \ 11 | TestSyncController \ 12 | TestRoThreadedBackend \ 13 | TestMessages \ 14 | TestKeystorePlugins \ 15 | TestRemoteConnector \ 16 | TestMigrationHelper \ 17 | TestEventCursor 18 | 19 | include_server_tests { 20 | SUBDIRS += \ 21 | TestAppServer \ 22 | IntegrationTest 23 | 24 | IntegrationTest.depends += TestAppServer #ensure those two don't run in parallel 25 | } 26 | 27 | include_server_tests: message("Please run 'sudo docker-compose -f $$absolute_path(../../../tools/appserver/docker-compose.yaml) up -d' to start the services needed for server tests") 28 | 29 | for(subdir, SUBDIRS):!equals(subdir, "TestLib"): $${subdir}.depends += TestLib 30 | 31 | prepareRecursiveTarget(run-tests) 32 | QMAKE_EXTRA_TARGETS += run-tests 33 | -------------------------------------------------------------------------------- /examples/datasync/Sample/Sample.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT += core gui widgets datasync 4 | QT += testlib 5 | 6 | TARGET = Sample 7 | 8 | HEADERS += \ 9 | widget.h \ 10 | sampledata.h \ 11 | accountdialog.h \ 12 | exchangedialog.h 13 | 14 | SOURCES += \ 15 | main.cpp \ 16 | widget.cpp \ 17 | sampledata.cpp \ 18 | accountdialog.cpp \ 19 | exchangedialog.cpp 20 | 21 | FORMS += \ 22 | widget.ui \ 23 | accountdialog.ui \ 24 | exchangedialog.ui 25 | 26 | DISTFILES += docker-compose.yaml 27 | 28 | target.path = $$[QT_INSTALL_EXAMPLES]/datasync/$$TARGET 29 | !install_ok: INSTALLS += target 30 | 31 | #not found by linker? 32 | unix:!mac { 33 | LIBS += -L$$OUT_PWD/../../../lib #required to make this the first place to search 34 | LIBS += -L$$[QT_INSTALL_LIBS] -licudata 35 | LIBS += -L$$[QT_INSTALL_LIBS] -licui18n 36 | LIBS += -L$$[QT_INSTALL_LIBS] -licuuc 37 | } 38 | 39 | #add lib dir to rpath 40 | mac: QMAKE_LFLAGS += '-Wl,-rpath,\'$$OUT_PWD/../../../lib\'' 41 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservicekeystoreplugin.cpp: -------------------------------------------------------------------------------- 1 | #include "secretservicekeystoreplugin.h" 2 | #include "secretservicekeystore.h" 3 | 4 | #include "libsecretwrapper.h" 5 | 6 | SecretServiceKeyStorePlugin::SecretServiceKeyStorePlugin(QObject *parent) : 7 | QObject(parent), 8 | KeyStorePlugin() 9 | {} 10 | 11 | bool SecretServiceKeyStorePlugin::keystoreAvailable(const QString &provider) const 12 | { 13 | if(provider == QStringLiteral("secretservice") || 14 | provider == QStringLiteral("gnome-keyring")) 15 | return LibSecretWrapper::testAvailable(); 16 | else 17 | return false; 18 | } 19 | 20 | QtDataSync::KeyStore *SecretServiceKeyStorePlugin::createInstance(const QString &provider, const QtDataSync::Defaults &defaults, QObject *parent) 21 | { 22 | if(provider == QStringLiteral("secretservice") || 23 | provider == QStringLiteral("gnome-keyring")) 24 | return new SecretServiceKeyStore(defaults, provider, parent); 25 | else 26 | return nullptr; 27 | } 28 | -------------------------------------------------------------------------------- /src/messages/removemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_REMOVEMESSAGE_P_H 2 | #define QTDATASYNC_REMOVEMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT RemoveMessage : public Message 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 15 | 16 | public: 17 | RemoveMessage(QUuid deviceId = {}); 18 | 19 | QUuid deviceId; 20 | 21 | protected: 22 | const QMetaObject *getMetaObject() const override; 23 | }; 24 | 25 | class Q_DATASYNC_EXPORT RemoveAckMessage : public Message 26 | { 27 | Q_GADGET 28 | 29 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 30 | 31 | public: 32 | RemoveAckMessage(QUuid deviceId = {}); 33 | 34 | QUuid deviceId; 35 | 36 | protected: 37 | const QMetaObject *getMetaObject() const override; 38 | }; 39 | 40 | } 41 | 42 | Q_DECLARE_METATYPE(QtDataSync::RemoveMessage) 43 | Q_DECLARE_METATYPE(QtDataSync::RemoveAckMessage) 44 | 45 | #endif // QTDATASYNC_REMOVEMESSAGE_P_H 46 | -------------------------------------------------------------------------------- /mkspecs/features/masm.prf: -------------------------------------------------------------------------------- 1 | isEmpty(QMAKE_MASM_COMPILER) { 2 | contains(QT_ARCH, x86_64): QMAKE_MASM_COMPILER = ml64.exe 3 | else: QMAKE_MASM_COMPILER = ml.exe 4 | } 5 | 6 | contains(QT_ARCH, x86_64): QMAKE_MASM_FLAGS = /D_M_X64 7 | else: QMAKE_MASM_FLAGS = /D_M_X86 /safeseh 8 | QMAKE_MASM_FLAGS += /c /nologo /W3 /Cx /Zi 9 | 10 | isEmpty(MASM_DIR): MASM_DIR = . 11 | debug_and_release { 12 | CONFIG(debug, debug|release): MASM_DIR = $$MASM_DIR/debug 13 | CONFIG(release, debug|release): MASM_DIR = $$MASM_DIR/release 14 | } 15 | 16 | masm_c.name = QMAKE_MASM_COMPILER ${QMAKE_FILE_IN} 17 | masm_c.input = MASM_SOURCES 18 | masm_c.variable_out = OBJECTS 19 | masm_c.commands = $$QMAKE_MASM_COMPILER $$QMAKE_MASM_FLAGS /Fo${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} 20 | masm_c.output = $$MASM_DIR/${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} 21 | #masm_c.depends += $$QMAKE_MASM_COMPILER 22 | masm_c.dependency_type = TYPE_C 23 | QMAKE_EXTRA_COMPILERS += masm_c 24 | 25 | QMAKE_DIR_REPLACE += MASM_DIR 26 | QMAKE_DIR_REPLACE_SANE += MASM_DIR 27 | -------------------------------------------------------------------------------- /src/messages/welcomemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_WELCOMEMESSAGE_P_H 2 | #define QTDATASYNC_WELCOMEMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT WelcomeMessage : public Message 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(bool hasChanges MEMBER hasChanges) 15 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 16 | Q_PROPERTY(QByteArray scheme MEMBER scheme) 17 | Q_PROPERTY(QByteArray key MEMBER key) 18 | Q_PROPERTY(QByteArray cmac MEMBER cmac) 19 | 20 | public: 21 | WelcomeMessage(bool hasChanges = false); 22 | 23 | bool hasChanges; 24 | quint32 keyIndex = 0; 25 | QByteArray scheme; 26 | QByteArray key; 27 | QByteArray cmac; 28 | 29 | bool hasKeyUpdate() const; 30 | QByteArray signatureData(QUuid deviceId) const; 31 | 32 | protected: 33 | const QMetaObject *getMetaObject() const override; 34 | }; 35 | 36 | } 37 | 38 | Q_DECLARE_METATYPE(QtDataSync::WelcomeMessage) 39 | 40 | #endif // QTDATASYNC_WELCOMEMESSAGE_P_H 41 | -------------------------------------------------------------------------------- /src/plugins/keystores/keychain/keychainkeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYCHAINKEYSTORE_H 2 | #define KEYCHAINKEYSTORE_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | class KeychainKeyStore : public QtDataSync::KeyStore 12 | { 13 | Q_OBJECT 14 | 15 | public: 16 | explicit KeychainKeyStore(const QtDataSync::Defaults &defaults, QObject *parent = nullptr); 17 | 18 | QString providerName() const override; 19 | bool isOpen() const override; 20 | void openStore() override; 21 | void closeStore() override; 22 | bool contains(const QString &key) const override; 23 | void save(const QString &key, const QByteArray &pKey) override; 24 | QByteArray load(const QString &key) override; 25 | void remove(const QString &key) override; 26 | 27 | private: 28 | bool _open; 29 | QtDataSync::Logger *_logger; 30 | 31 | static QString serviceName(); 32 | static QString errorMsg(OSStatus status); 33 | }; 34 | 35 | #endif // KEYCHAINKEYSTORE_H 36 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservicekeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef SECRETSERVICEKEYSTORE_H 2 | #define SECRETSERVICEKEYSTORE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "libsecretwrapper.h" 9 | 10 | class SecretServiceKeyStore : public QtDataSync::KeyStore 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit SecretServiceKeyStore(const QtDataSync::Defaults &defaults, 16 | const QString &providerName, 17 | QObject *parent = nullptr); 18 | 19 | QString providerName() const override; 20 | bool isOpen() const override; 21 | void openStore() override; 22 | void closeStore() override; 23 | bool contains(const QString &key) const override; 24 | void save(const QString &key, const QByteArray &pKey) override; 25 | QByteArray load(const QString &key) override; 26 | void remove(const QString &key) override; 27 | 28 | private: 29 | const QString _providerName; 30 | QScopedPointer _libSecret; 31 | }; 32 | 33 | #endif // SECRETSERVICEKEYSTORE_H 34 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/syncservice.cpp: -------------------------------------------------------------------------------- 1 | #include "syncservice.h" 2 | #include 3 | 4 | //! [droid_service_impl] 5 | SyncService::SyncService(int &argc, char **argv) : 6 | AndroidBackgroundService{argc, argv} 7 | {} 8 | 9 | void SyncService::prepareSetup(QtDataSync::Setup &setup) 10 | { 11 | // prepare the setup here, i.e. 12 | // setup.setRemoteConfiguration(QtDataSync::RemoteConfig{ ... ]); 13 | } 14 | 15 | void SyncService::onSyncCompleted(QtDataSync::SyncManager::SyncState state) 16 | { 17 | qDebug() << "[[SYNCSERVICE]]" << "Sync completed in state:" << state; 18 | exitAfterSync(); 19 | } 20 | //! [droid_service_impl] 21 | 22 | //! [jni_create_notification] 23 | QAndroidJniObject SyncService::createForegroundNotification() 24 | { 25 | return QAndroidJniObject::callStaticObjectMethod("de/skycoder42/qtdatasync/sample/androidsync/SvcHelper", 26 | "createFgNotification", 27 | "(Landroid/content/Context;)Landroid/app/Notification;", 28 | QtAndroid::androidService().object()); 29 | } 30 | //! [jni_create_notification] 31 | -------------------------------------------------------------------------------- /src/datasync/syncmanager_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SYNCMANAGER_P_H 2 | #define QTDATASYNC_SYNCMANAGER_P_H 3 | 4 | #include 5 | 6 | #include "qtdatasync_global.h" 7 | #include "exchangeengine_p.h" 8 | 9 | #include "rep_syncmanager_p_source.h" 10 | 11 | namespace QtDataSync { 12 | 13 | //not exported because base it not, too 14 | class SyncManagerPrivate : public SyncManagerPrivateSource 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | SyncManagerPrivate(ExchangeEngine *engineParent); 20 | 21 | QString setupName() const override; 22 | bool syncEnabled() const override; 23 | SyncManager::SyncState syncState() const override; 24 | qreal syncProgress() const override; 25 | QString lastError() const override; 26 | 27 | void setSyncEnabled(bool syncEnabled) override; 28 | 29 | public Q_SLOTS: 30 | void synchronize() override; 31 | void reconnect() override; 32 | void runOnState(QUuid id, bool downloadOnly, bool triggerSync) override; 33 | 34 | private: 35 | QPointer _engine; 36 | }; 37 | 38 | } 39 | 40 | #endif // QTDATASYNC_SYNCMANAGER_P_H 41 | -------------------------------------------------------------------------------- /src/datasync/qtdatasync_helpertypes.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_HELPERTYPES_H 2 | #define QTDATASYNC_HELPERTYPES_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "QtDataSync/qtdatasync_global.h" 9 | 10 | namespace QtDataSync { 11 | namespace __helpertypes { 12 | 13 | template 14 | struct is_gadget : public std::false_type {}; 15 | 16 | template 17 | struct is_gadget : public std::true_type {}; 18 | 19 | template 20 | struct is_object : public std::false_type {}; 21 | 22 | template 23 | struct is_object : public std::is_base_of {}; 24 | 25 | template 26 | struct is_storable : public is_gadget {}; 27 | 28 | template 29 | struct is_storable : public std::is_base_of {}; 30 | 31 | } 32 | } 33 | 34 | #define QTDATASYNC_STORE_ASSERT(T) static_assert(__helpertypes::is_storable::value, "Only Q_GADGETS or pointers to QObject extending classes can be stored") 35 | 36 | #endif // QTDATASYNC_HELPERTYPES_H 37 | -------------------------------------------------------------------------------- /examples/datasync/Sample/exchangedialog.h: -------------------------------------------------------------------------------- 1 | #ifndef EXCHANGEDIALOG_H 2 | #define EXCHANGEDIALOG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace Ui { 10 | class ExchangeDialog; 11 | } 12 | 13 | class ExchangeDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit ExchangeDialog(QtDataSync::AccountManager *manager, QWidget *parent = nullptr); 19 | ~ExchangeDialog(); 20 | 21 | static void exec(QtDataSync::AccountManager *manager, QWidget *parent = nullptr); 22 | 23 | private slots: 24 | void devicesChanged(QList devices); 25 | void userDataReceived(const QtDataSync::UserInfo &userInfo, bool trusted); 26 | void exchangeError(const QString &errorString); 27 | 28 | void on_treeWidget_itemActivated(QTreeWidgetItem *item, int column); 29 | void on_activeCheckBox_clicked(bool checked); 30 | 31 | private: 32 | Ui::ExchangeDialog *ui; 33 | QtDataSync::UserExchangeManager *_manager; 34 | }; 35 | 36 | #endif // EXCHANGEDIALOG_H 37 | -------------------------------------------------------------------------------- /src/messages/devicesmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_DEVICESMESSAGE_P_H 2 | #define QTDATASYNC_DEVICESMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "message_p.h" 10 | 11 | namespace QtDataSync { 12 | 13 | class Q_DATASYNC_EXPORT ListDevicesMessage : public Message 14 | { 15 | Q_GADGET 16 | 17 | protected: 18 | const QMetaObject *getMetaObject() const override; 19 | }; 20 | 21 | class Q_DATASYNC_EXPORT DevicesMessage : public Message 22 | { 23 | Q_GADGET 24 | 25 | Q_PROPERTY(QList devices MEMBER devices) 26 | 27 | public: 28 | using DeviceInfo = std::tuple; // (deviceid, name, fingerprint) 29 | 30 | QList devices; 31 | 32 | protected: 33 | const QMetaObject *getMetaObject() const override; 34 | }; 35 | 36 | } 37 | 38 | Q_DECLARE_METATYPE(QtDataSync::ListDevicesMessage) 39 | Q_DECLARE_METATYPE(QtDataSync::DevicesMessage) 40 | Q_DECLARE_METATYPE(QtDataSync::DevicesMessage::DeviceInfo) 41 | 42 | #endif // QTDATASYNC_DEVICESMESSAGE_P_H 43 | -------------------------------------------------------------------------------- /src/datasync/conflictresolver.cpp: -------------------------------------------------------------------------------- 1 | #include "conflictresolver.h" 2 | #include "conflictresolver_p.h" 3 | #include "defaults_p.h" 4 | using namespace QtDataSync; 5 | 6 | ConflictResolver::ConflictResolver(QObject *parent) : 7 | QObject{parent}, 8 | d{new ConflictResolverPrivate()} 9 | {} 10 | 11 | ConflictResolver::~ConflictResolver() = default; 12 | 13 | void ConflictResolver::setDefaults(const Defaults &defaults) 14 | { 15 | d->defaultsName = defaults.setupName(); 16 | d->logger = defaults.createLogger(name(), this); 17 | d->settings = defaults.createSettings(this, QString::fromUtf8(name())); 18 | } 19 | 20 | QString ConflictResolver::setupName() const 21 | { 22 | return d->defaultsName; 23 | } 24 | 25 | QByteArray ConflictResolver::name() const 26 | { 27 | return "resolver"; 28 | } 29 | 30 | Defaults ConflictResolver::defaults() const 31 | { 32 | return DefaultsPrivate::obtainDefaults(d->defaultsName); 33 | } 34 | 35 | Logger *ConflictResolver::logger() const 36 | { 37 | return d->logger; 38 | } 39 | 40 | QSettings *ConflictResolver::settings() const 41 | { 42 | return d->settings; 43 | } 44 | -------------------------------------------------------------------------------- /src/messages/devicekeysmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_DEVICEKEYSMESSAGE_P_H 2 | #define QTDATASYNC_DEVICEKEYSMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT DeviceKeysMessage : public Message 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 15 | Q_PROPERTY(bool duplicated MEMBER duplicated) 16 | Q_PROPERTY(QList devices MEMBER devices) 17 | 18 | public: 19 | using DeviceKey = std::tuple; // (deviceid, scheme, key, mac) 20 | 21 | DeviceKeysMessage(quint32 keyIndex = 0); 22 | DeviceKeysMessage(quint32 keyIndex, QList devices); 23 | 24 | quint32 keyIndex; 25 | bool duplicated; 26 | QList devices; 27 | 28 | protected: 29 | const QMetaObject *getMetaObject() const override; 30 | }; 31 | 32 | } 33 | 34 | Q_DECLARE_METATYPE(QtDataSync::DeviceKeysMessage) 35 | Q_DECLARE_METATYPE(QtDataSync::DeviceKeysMessage::DeviceKey) 36 | 37 | #endif // QTDATASYNC_DEVICEKEYSMESSAGE_P_H 38 | -------------------------------------------------------------------------------- /src/plugins/keystores/android/androidkeystore.h: -------------------------------------------------------------------------------- 1 | #ifndef ANDROIDKEYSTORE_H 2 | #define ANDROIDKEYSTORE_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | class AndroidKeyStore : public QtDataSync::KeyStore 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | explicit AndroidKeyStore(const QtDataSync::Defaults &defaults, QObject *parent = nullptr); 15 | 16 | QString providerName() const override; 17 | bool isOpen() const override; 18 | void openStore() override; 19 | void closeStore() override; 20 | bool contains(const QString &key) const override; 21 | void save(const QString &key, const QByteArray &pKey) override; 22 | QByteArray load(const QString &key) override; 23 | void remove(const QString &key) override; 24 | 25 | private: 26 | QAndroidJniObject _preferences; 27 | 28 | void jniThrow(QAndroidJniEnvironment &env) const; 29 | QAndroidJniObject prefEditor(QAndroidJniEnvironment &env); 30 | void prefApply(QAndroidJniObject &editor, QAndroidJniEnvironment &env); 31 | }; 32 | 33 | #endif // ANDROIDKEYSTORE_H 34 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/libsecretwrapper.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBSECRETWRAPPER_H 2 | #define LIBSECRETWRAPPER_H 3 | 4 | #include 5 | 6 | //fwd declare 7 | typedef struct _GError GError; 8 | typedef struct _GHashTable GHashTable; 9 | typedef struct _SecretService SecretService; 10 | 11 | class LibSecretException : public std::exception 12 | { 13 | public: 14 | LibSecretException(GError *error = nullptr); 15 | const char *what() const noexcept override; 16 | 17 | private: 18 | const QByteArray _message; 19 | }; 20 | 21 | class LibSecretWrapper 22 | { 23 | public: 24 | LibSecretWrapper(const QByteArray &appName); 25 | ~LibSecretWrapper(); 26 | 27 | static bool testAvailable(); 28 | 29 | bool isOpen() const; 30 | void setup(); 31 | void cleanup(); 32 | 33 | QByteArray loadSecret(const QByteArray &key); 34 | void storeSecret(const QByteArray &key, const QByteArray &data); 35 | void removeSecret(const QByteArray &key); 36 | 37 | private: 38 | QByteArray _appName; 39 | SecretService *_secret; 40 | 41 | GHashTable *attribs(const QByteArray &key); 42 | }; 43 | 44 | #endif // LIBSECRETWRAPPER_H 45 | -------------------------------------------------------------------------------- /src/messages/errormessage.cpp: -------------------------------------------------------------------------------- 1 | #include "errormessage_p.h" 2 | 3 | #include 4 | 5 | using namespace QtDataSync; 6 | 7 | ErrorMessage::ErrorMessage(ErrorMessage::ErrorType type, QString message, bool canRecover) : 8 | type{type}, 9 | message{std::move(message)}, 10 | canRecover{canRecover} 11 | {} 12 | 13 | const QMetaObject *ErrorMessage::getMetaObject() const 14 | { 15 | return &staticMetaObject; 16 | } 17 | 18 | bool ErrorMessage::validate() 19 | { 20 | if(!QMetaEnum::fromType().valueToKey(type)) 21 | type = ErrorMessage::UnknownError; 22 | return true; 23 | } 24 | 25 | QDebug QtDataSync::operator<<(QDebug debug, const ErrorMessage &message) 26 | { 27 | QDebugStateSaver saver(debug); 28 | debug.nospace().noquote() << "ErrorMessage[" 29 | << QMetaEnum::fromType().valueToKey(message.type) 30 | << ", " 31 | << (message.canRecover ? "recoverable" : "unrecoverable") 32 | << "]: " 33 | << (message.message.isNull() ? QStringLiteral("") : static_cast(message.message)); 34 | return debug; 35 | } 36 | -------------------------------------------------------------------------------- /src/messages/devicechangemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_DEVICECHANGEMESSAGE_P_H 2 | #define QTDATASYNC_DEVICECHANGEMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | #include "changemessage_p.h" 8 | 9 | namespace QtDataSync { 10 | 11 | class Q_DATASYNC_EXPORT DeviceChangeMessage : public ChangeMessage 12 | { 13 | Q_GADGET 14 | 15 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 16 | 17 | public: 18 | DeviceChangeMessage(QByteArray dataId = {}, QUuid deviceId = {}); 19 | 20 | QUuid deviceId; 21 | 22 | protected: 23 | const QMetaObject *getMetaObject() const override; 24 | }; 25 | 26 | class Q_DATASYNC_EXPORT DeviceChangeAckMessage : public ChangeAckMessage 27 | { 28 | Q_GADGET 29 | 30 | Q_PROPERTY(QUuid deviceId MEMBER deviceId) 31 | 32 | public: 33 | DeviceChangeAckMessage(const DeviceChangeMessage &message = {}); 34 | 35 | QUuid deviceId; 36 | 37 | protected: 38 | const QMetaObject *getMetaObject() const override; 39 | }; 40 | 41 | } 42 | 43 | Q_DECLARE_METATYPE(QtDataSync::DeviceChangeMessage) 44 | Q_DECLARE_METATYPE(QtDataSync::DeviceChangeAckMessage) 45 | 46 | #endif // QTDATASYNC_DEVICECHANGEMESSAGE_P_H 47 | -------------------------------------------------------------------------------- /examples/datasync/Sample/accountdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef ACCOUNTDIALOG_H 2 | #define ACCOUNTDIALOG_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace Ui { 10 | class AccountDialog; 11 | } 12 | 13 | class AccountDialog : public QDialog 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit AccountDialog(const QString &setup, QWidget *parent = nullptr); 19 | ~AccountDialog(); 20 | 21 | static void exec(const QString &setup, QWidget *parent = nullptr); 22 | 23 | private Q_SLOTS: 24 | void updateDevices(const QList &devices); 25 | void login(QtDataSync::LoginRequest request); 26 | void importDone(); 27 | void engineError(const QString &error); 28 | 29 | void on_action_Remove_Device_triggered(); 30 | void on_buttonBox_clicked(QAbstractButton *button); 31 | void on_pushButton_clicked(); 32 | void on_pushButton_2_clicked(); 33 | 34 | void on_exchangeButton_clicked(); 35 | 36 | private: 37 | Ui::AccountDialog *ui; 38 | QtDataSync::AccountManager *_manager; 39 | 40 | static QString printFingerprint(const QByteArray &fingerprint); 41 | }; 42 | 43 | #endif // ACCOUNTDIALOG_H 44 | -------------------------------------------------------------------------------- /src/datasync/rothreadedbackend/exchangebufferserver_p.h: -------------------------------------------------------------------------------- 1 | #ifndef EXCHANGEBUFFERSERVER_P_H 2 | #define EXCHANGEBUFFERSERVER_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "qtdatasync_global.h" 10 | #include "exchangebuffer_p.h" 11 | #include "qtrotransportregistry.h" 12 | 13 | namespace QtDataSync { 14 | 15 | class Q_DATASYNC_EXPORT ExchangeBufferServer : public QObject 16 | { 17 | Q_OBJECT 18 | 19 | public: 20 | static const QString UrlScheme(); 21 | static bool connectTo(const QUrl &url, 22 | ExchangeBuffer *clientBuffer, 23 | bool allowCaching = true); 24 | 25 | explicit ExchangeBufferServer(QRemoteObjectHostBase *host); 26 | 27 | bool registerInstance(const QUrl &url); 28 | 29 | private Q_SLOTS: 30 | void addConnection(ExchangeBuffer *clientBuffer); 31 | 32 | private: 33 | static QMutex _lock; 34 | static QHash _servers; 35 | static QMultiHash> _connectCache; 36 | 37 | QRemoteObjectHostBase *_host; 38 | QUrl _listenAddress; 39 | }; 40 | 41 | } 42 | 43 | #endif // EXCHANGEBUFFERSERVER_P_H 44 | -------------------------------------------------------------------------------- /tests/auto/qml/TestQmlDataSync/tst_qmldatasync.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import de.skycoder42.QtDataSync 4.2 3 | import QtTest 1.1 4 | 5 | Item { 6 | id: root 7 | 8 | TestCase { 9 | name: "DataStore" 10 | 11 | DataStore { 12 | id: store 13 | } 14 | 15 | DataStoreModel { 16 | id: storeModel1 17 | } 18 | 19 | DataStoreModel { 20 | id: storeModel2 21 | dataStore: store 22 | } 23 | 24 | SyncManager { 25 | id: syncManager 26 | } 27 | 28 | AccountManager { 29 | id: accountManager 30 | } 31 | 32 | UserExchangeManager { 33 | id: exchangeManager1 34 | } 35 | 36 | UserExchangeManager { 37 | id: exchangeManager2 38 | manager: accountManager 39 | } 40 | 41 | property EventCursor cursor: null 42 | 43 | function test_valid() { 44 | verify(store.valid); 45 | verify(storeModel1.valid); 46 | verify(storeModel2.valid); 47 | verify(syncManager.valid); 48 | verify(accountManager.valid); 49 | verify(exchangeManager1.valid); 50 | verify(exchangeManager2.valid); 51 | 52 | cursor = EventLog.first(); 53 | expectFail("", "No cursor until data was changed"); 54 | verify(cursor.valid); 55 | } 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/messages/changemessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_CHANGEMESSAGE_P_H 2 | #define QTDATASYNC_CHANGEMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | 6 | namespace QtDataSync { 7 | 8 | class Q_DATASYNC_EXPORT ChangeMessage : public Message 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(QByteArray dataId MEMBER dataId) 13 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 14 | Q_PROPERTY(QByteArray salt MEMBER salt) 15 | Q_PROPERTY(QByteArray data MEMBER data) 16 | 17 | public: 18 | ChangeMessage(QByteArray dataId = {}); 19 | 20 | QByteArray dataId; 21 | quint32 keyIndex = 0; 22 | QByteArray salt; 23 | QByteArray data; 24 | 25 | protected: 26 | const QMetaObject *getMetaObject() const override; 27 | }; 28 | 29 | class Q_DATASYNC_EXPORT ChangeAckMessage : public Message 30 | { 31 | Q_GADGET 32 | 33 | Q_PROPERTY(QByteArray dataId MEMBER dataId) 34 | 35 | public: 36 | ChangeAckMessage(const ChangeMessage &message = {}); 37 | 38 | QByteArray dataId; 39 | 40 | protected: 41 | const QMetaObject *getMetaObject() const override; 42 | }; 43 | 44 | } 45 | 46 | Q_DECLARE_METATYPE(QtDataSync::ChangeMessage) 47 | Q_DECLARE_METATYPE(QtDataSync::ChangeAckMessage) 48 | 49 | #endif // QTDATASYNC_CHANGEMESSAGE_P_H 50 | -------------------------------------------------------------------------------- /tools/appserver/clientconnector.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIENTCONNECTOR_H 2 | #define CLIENTCONNECTOR_H 3 | 4 | #include "client.h" 5 | #include "databasecontroller.h" 6 | 7 | #include 8 | #include 9 | 10 | class ClientConnector : public QObject 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit ClientConnector(DatabaseController *database, QObject *parent = nullptr); 15 | 16 | void recreateServer(); 17 | bool setupWss(); 18 | bool listen(); 19 | void close(); 20 | 21 | void setPaused(bool paused); 22 | 23 | public Q_SLOTS: 24 | void notifyChanged(QUuid deviceId); 25 | 26 | Q_SIGNALS: 27 | void disconnectAll(); 28 | 29 | private Q_SLOTS: 30 | void verifySecret(QWebSocketCorsAuthenticator *authenticator); 31 | void newConnection(); 32 | void serverError(); 33 | void sslErrors(const QList &errors); 34 | 35 | void clientConnected(QUuid deviceId); 36 | void proofRequested(QUuid partner, const QtDataSync::ProofMessage &message); 37 | void forceDisconnect(QUuid partner); 38 | 39 | private: 40 | DatabaseController *database; 41 | QWebSocketServer *server = nullptr; 42 | QString secret; 43 | bool isActivated = false; 44 | 45 | QHash clients; 46 | }; 47 | 48 | #endif // CLIENTCONNECTOR_H 49 | -------------------------------------------------------------------------------- /src/datasync/eventcursor_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_EVENTCURSOR_P_H 2 | #define QTDATASYNC_EVENTCURSOR_P_H 3 | 4 | #include 5 | 6 | #include "eventcursor.h" 7 | 8 | #include "defaults.h" 9 | #include "emitteradapter_p.h" 10 | 11 | namespace QtDataSync { 12 | 13 | class EventCursorPrivate 14 | { 15 | friend class QtDataSync::EventCursor; 16 | 17 | public: 18 | EventCursorPrivate(const QString &setupName, EventCursor *q_ptr); 19 | 20 | static bool isLogActive(const Defaults &defaults, DatabaseRef &database); 21 | static void initDatabase(const Defaults &defaults, DatabaseRef &database, Logger *logger, bool createTriggers); 22 | static void clearEventLog(const Defaults &defaults, DatabaseRef &database); 23 | 24 | private: 25 | void exec(QSqlQuery &query, quint64 qIndex = 0) const; 26 | void readQuery(const QSqlQuery &query); 27 | void prepareNextQuery(QSqlQuery &query, bool withData) const; 28 | 29 | Defaults defaults; 30 | DatabaseRef database; 31 | EmitterAdapter *emitter; 32 | Logger *logger; 33 | 34 | quint64 index = 0; 35 | QtDataSync::ObjectKey key; 36 | bool wasRemoved = false; 37 | QDateTime timestamp; 38 | 39 | bool skipObsolete = true; 40 | }; 41 | 42 | } 43 | 44 | #endif // QTDATASYNC_EVENTCURSOR_P_H 45 | -------------------------------------------------------------------------------- /src/datasyncios/iossyncdelegate_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_IOSSYNCDELEGATE_P_H 2 | #define QTDATASYNC_IOSSYNCDELEGATE_P_H 3 | 4 | #include "iossyncdelegate.h" 5 | 6 | #include 7 | #include 8 | 9 | namespace QtDataSync { 10 | 11 | class IosSyncDelegatePrivate 12 | { 13 | friend class IosSyncDelegate; 14 | 15 | public: 16 | static void performFetch(std::function callback); 17 | 18 | private: 19 | static const QString SyncStateGroup; 20 | static const QString SyncIntervalKey; 21 | static const QString SyncEnabledKey; 22 | static const QString SyncWaitKey; 23 | 24 | static QPointer delegateInstance; 25 | 26 | IosSyncDelegatePrivate(QSettings *settings, IosSyncDelegate *q_ptr); 27 | 28 | IosSyncDelegate *q; 29 | bool enabled = true; 30 | std::chrono::minutes interval{60}; 31 | bool waitFullSync = false; 32 | 33 | QSettings *settings; 34 | QtDataSync::SyncManager *manager = nullptr; 35 | bool allowUpdateSync = false; 36 | 37 | std::function currentCallback; 38 | 39 | void updateSyncInterval(); 40 | void storeState(); 41 | void onSyncDone(SyncManager::SyncState state); 42 | }; 43 | 44 | } 45 | 46 | #endif // QTDATASYNC_IOSSYNCDELEGATE_P_H 47 | -------------------------------------------------------------------------------- /src/datasync/datastoremodel_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_DATASTOREMODEL_P_H 2 | #define QTDATASYNC_DATASTOREMODEL_P_H 3 | 4 | #include "qtdatasync_global.h" 5 | #include "datastoremodel.h" 6 | 7 | namespace QtDataSync { 8 | 9 | //no export needed 10 | class DataStoreModelPrivate 11 | { 12 | public: 13 | DataStoreModelPrivate(DataStoreModel *q_ptr); 14 | 15 | DataStoreModel *q; 16 | DataStore *store = nullptr; 17 | bool editable = false; 18 | 19 | int type = QMetaType::UnknownType; 20 | bool isObject = false; 21 | QHash roleNames; 22 | 23 | QStringList keyList; 24 | QVariantHash dataHash; 25 | 26 | QStringList columns; 27 | QHash> roleMapping; //column -> (role -> property) 28 | 29 | bool isFetching = false; 30 | 31 | QStringList activeKeys(); 32 | 33 | void createRoleNames(); 34 | void clearHashObjects(); 35 | void deleteObject(const QVariant &value); 36 | bool testRoleValid(const QModelIndex &index, int role) const; 37 | QByteArray propertyName(const QModelIndex &index, int role) const; 38 | 39 | QVariant readProperty(const QString &key, const QByteArray &property); 40 | bool writeProperty(const QString &key, const QByteArray &property, const QVariant &value); 41 | }; 42 | 43 | } 44 | #endif // QTDATASYNC_DATASTOREMODEL_P_H 45 | -------------------------------------------------------------------------------- /src/datasync/migrationhelper_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_MIGRATIONHELPER_P_H 2 | #define QTDATASYNC_MIGRATIONHELPER_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qtdatasync_global.h" 8 | #include "migrationhelper.h" 9 | #include "defaults.h" 10 | 11 | namespace QtDataSync { 12 | 13 | class MigrationRunnable : public QRunnable 14 | { 15 | Q_DISABLE_COPY(MigrationRunnable) 16 | public: 17 | MigrationRunnable(Defaults defaults, 18 | MigrationHelper *helper, 19 | QString oldDir, 20 | MigrationHelper::MigrationFlags flags); 21 | 22 | void run() override; 23 | 24 | private: 25 | Defaults _defaults; 26 | const QPointer _helper; 27 | const QString _oldDir; 28 | const MigrationHelper::MigrationFlags _flags; 29 | 30 | QPointer _logger; 31 | int _progress = 0; 32 | 33 | void migrationPrepared(int count); 34 | void migrationProgress(); 35 | void migrationDone(bool ok); 36 | 37 | void copyConf(QSettings *old, const QString &oldKey, QSettings *current, const QString &newKey) const; 38 | }; 39 | 40 | class MigrationHelperPrivate 41 | { 42 | public: 43 | MigrationHelperPrivate(const QString &setupName); 44 | 45 | Defaults defaults; 46 | }; 47 | 48 | } 49 | 50 | #endif // QTDATASYNC_MIGRATIONHELPER_P_H 51 | -------------------------------------------------------------------------------- /src/messages/proofmessage.cpp: -------------------------------------------------------------------------------- 1 | #include "proofmessage_p.h" 2 | using namespace QtDataSync; 3 | 4 | ProofMessage::ProofMessage() = default; 5 | 6 | ProofMessage::ProofMessage(const AccessMessage &access, QUuid deviceId) : 7 | pNonce{access.pNonce}, 8 | deviceId{deviceId}, 9 | deviceName{access.deviceName}, 10 | signAlgorithm{access.signAlgorithm}, 11 | signKey{access.signKey}, 12 | cryptAlgorithm{access.cryptAlgorithm}, 13 | cryptKey{access.cryptKey}, 14 | macscheme{access.macscheme}, 15 | cmac{access.cmac}, 16 | trustmac{access.trustmac} 17 | {} 18 | 19 | const QMetaObject *ProofMessage::getMetaObject() const 20 | { 21 | return &staticMetaObject; 22 | } 23 | 24 | 25 | 26 | DenyMessage::DenyMessage(QUuid deviceId) : 27 | deviceId{deviceId} 28 | {} 29 | 30 | const QMetaObject *DenyMessage::getMetaObject() const 31 | { 32 | return &staticMetaObject; 33 | } 34 | 35 | 36 | 37 | AcceptMessage::AcceptMessage(QUuid deviceId) : 38 | deviceId{deviceId} 39 | {} 40 | 41 | const QMetaObject *AcceptMessage::getMetaObject() const 42 | { 43 | return &staticMetaObject; 44 | } 45 | 46 | 47 | 48 | AcceptAckMessage::AcceptAckMessage(QUuid deviceId) : 49 | deviceId{deviceId} 50 | {} 51 | 52 | const QMetaObject *AcceptAckMessage::getMetaObject() const 53 | { 54 | return &staticMetaObject; 55 | } 56 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2017 3 | 4 | version: build-{build} 5 | 6 | environment: 7 | QT_VER: 5.13.1 8 | EXTRA_MODULES: .skycoder42.jsonserializer;.skycoder42.service 9 | MAKE_RUN_TESTS: true 10 | TARGET_NAME: qtdatasync 11 | 12 | matrix: 13 | - PLATFORM: msvc2017_64 14 | - PLATFORM: mingw73_64 15 | - PLATFORM: mingw73_32 16 | - PLATFORM: winrt_x64_msvc2017 17 | - PLATFORM: msvc2017 18 | - PLATFORM: winrt_x86_msvc2017 19 | - PLATFORM: winrt_armv7_msvc2017 20 | 21 | install: 22 | - git submodule init 23 | - git submodule update 24 | - git clone https://github.com/Skycoder42/QtModules.git .\qtmodules-travis 25 | - .\qtmodules-travis\ci\win\setup.bat 26 | 27 | build_script: 28 | - if "%PLATFORM%" == "mingw73_32" set NO_TESTS=true 29 | - .\qtmodules-travis\ci\win\build.bat 30 | 31 | after_build: 32 | - .\qtmodules-travis\ci\win\upload-prepare.bat 33 | 34 | artifacts: 35 | - path: install\%TARGET_NAME%_*_%QT_VER%.zip 36 | 37 | deploy: 38 | provider: GitHub 39 | auth_token: 40 | secure: Cp5GRQku2ZWnKPE12NB5q11ZO0Fr5mlzdUTjnLpYJr/dki4LPVqm231edFggogy8 41 | artifact: /.*\.zip/ 42 | force_update: false 43 | on: 44 | appveyor_repo_tag: true 45 | 46 | cache: 47 | - 'C:\Users\appveyor\AppData\Local\qdep\qdep\Cache -> appveyor.yml' 48 | -------------------------------------------------------------------------------- /src/messages/errormessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ERRORMESSAGE_P_H 2 | #define QTDATASYNC_ERRORMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | 8 | namespace QtDataSync { 9 | 10 | class Q_DATASYNC_EXPORT ErrorMessage : public Message 11 | { 12 | Q_GADGET 13 | 14 | Q_PROPERTY(ErrorType type MEMBER type) 15 | Q_PROPERTY(QtDataSync::Utf8String message MEMBER message) 16 | Q_PROPERTY(bool canRecover MEMBER canRecover) 17 | 18 | public: 19 | enum ErrorType { 20 | UnknownError = 0, 21 | IncompatibleVersionError = 1, 22 | UnexpectedMessageError = 2, 23 | ServerError = 3, 24 | ClientError = 4, 25 | AuthenticationError = 5, 26 | AccessError = 6, 27 | KeyIndexError = 7, 28 | KeyPendingError = 8, 29 | QuotaHitError = 9 30 | }; 31 | Q_ENUM(ErrorType) 32 | 33 | ErrorMessage(ErrorType type = UnknownError, 34 | QString message = {}, 35 | bool canRecover = false); 36 | 37 | ErrorType type; 38 | Utf8String message; 39 | bool canRecover; 40 | 41 | protected: 42 | const QMetaObject *getMetaObject() const override; 43 | bool validate() override; 44 | }; 45 | 46 | Q_DATASYNC_EXPORT QDebug operator<<(QDebug debug, const ErrorMessage &message); 47 | 48 | } 49 | 50 | Q_DECLARE_METATYPE(QtDataSync::ErrorMessage) 51 | 52 | #endif // QTDATASYNC_ERRORMESSAGE_P_H 53 | -------------------------------------------------------------------------------- /src/datasync/userexchangemanager_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_USEREXCHANGEMANAGER_P_H 2 | #define QTDATASYNC_USEREXCHANGEMANAGER_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "qtdatasync_global.h" 11 | #include "userexchangemanager.h" 12 | #include "accountmanager.h" 13 | #include "logger.h" 14 | 15 | namespace QtDataSync { 16 | 17 | //no export needed 18 | class UserInfoPrivate : public QSharedData 19 | { 20 | public: 21 | UserInfoPrivate(QString name = {}, const QNetworkDatagram &datagram = {}); 22 | UserInfoPrivate(const UserInfoPrivate &other); 23 | 24 | QString name; 25 | QHostAddress address; 26 | quint16 port; 27 | }; 28 | 29 | //no export needed 30 | class UserExchangeManagerPrivate 31 | { 32 | public: 33 | enum DatagramType { 34 | DeviceInfo, 35 | DeviceDataUntrusted, 36 | DeviceDataTrusted 37 | }; 38 | 39 | UserExchangeManagerPrivate(UserExchangeManager *q_ptr); 40 | 41 | AccountManager *manager = nullptr; 42 | QPointer socket; 43 | QTimer *timer; 44 | 45 | bool allowReuseAddress = false; 46 | QHash devices; 47 | QHash exchangeData; 48 | 49 | void clearSocket(); 50 | }; 51 | 52 | } 53 | 54 | #endif // QTDATASYNC_USEREXCHANGEMANAGER_P_H 55 | -------------------------------------------------------------------------------- /src/messages/accessmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ACCESSMESSAGE_P_H 2 | #define QTDATASYNC_ACCESSMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | #include "registermessage_p.h" 8 | 9 | namespace QtDataSync { 10 | 11 | class Q_DATASYNC_EXPORT AccessMessage : public RegisterBaseMessage 12 | { 13 | Q_GADGET 14 | 15 | Q_PROPERTY(QByteArray pNonce MEMBER pNonce) 16 | Q_PROPERTY(QUuid partnerId MEMBER partnerId) 17 | Q_PROPERTY(QByteArray macscheme MEMBER macscheme) 18 | Q_PROPERTY(QByteArray cmac MEMBER cmac) 19 | Q_PROPERTY(QByteArray trustmac MEMBER trustmac) 20 | 21 | public: 22 | AccessMessage(); 23 | AccessMessage(QString deviceName, 24 | QByteArray nonce, 25 | const QSharedPointer &signKey, 26 | const QSharedPointer &cryptKey, 27 | AsymmetricCrypto *crypto, 28 | QByteArray pNonce, 29 | QUuid partnerId, 30 | QByteArray macscheme, 31 | QByteArray cmac, 32 | QByteArray trustmac); 33 | 34 | QByteArray pNonce; 35 | QUuid partnerId; 36 | QByteArray macscheme; 37 | QByteArray cmac; 38 | QByteArray trustmac; 39 | 40 | protected: 41 | const QMetaObject *getMetaObject() const override; 42 | }; 43 | 44 | } 45 | 46 | Q_DECLARE_METATYPE(QtDataSync::AccessMessage) 47 | 48 | #endif // QTDATASYNC_ACCESSMESSAGE_P_H 49 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "syncservice.h" 6 | 7 | namespace { 8 | 9 | //! [activity_main] 10 | int activityMain(int argc, char *argv[]) 11 | { 12 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 13 | QGuiApplication app(argc, argv); 14 | 15 | QAndroidJniObject::callStaticMethod("de/skycoder42/qtdatasync/sample/androidsync/SvcHelper", 16 | "registerNotificationChannel", 17 | "(Landroid/content/Context;)V", 18 | QtAndroid::androidContext().object()); 19 | 20 | QQmlApplicationEngine engine; 21 | engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); 22 | if (engine.rootObjects().isEmpty()) 23 | return -1; 24 | 25 | return app.exec(); 26 | } 27 | //! [activity_main] 28 | 29 | //! [service_main] 30 | int serviceMain(int argc, char *argv[]) 31 | { 32 | SyncService service{argc, argv}; 33 | return service.exec(); 34 | } 35 | //! [service_main] 36 | 37 | } 38 | 39 | //! [actual_main] 40 | int main(int argc, char *argv[]) 41 | { 42 | for(auto i = 0; i < argc; i++) { 43 | if(qstrcmp(argv[i], "--backend") == 0) 44 | return serviceMain(argc, argv); 45 | } 46 | return activityMain(argc, argv); 47 | } 48 | //! [actual_main] 49 | 50 | -------------------------------------------------------------------------------- /src/messages/newkeymessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_NEWKEYMESSAGE_P_H 2 | #define QTDATASYNC_NEWKEYMESSAGE_P_H 3 | 4 | #include 5 | 6 | #include "message_p.h" 7 | #include "macupdatemessage_p.h" 8 | 9 | namespace QtDataSync { 10 | 11 | class Q_DATASYNC_EXPORT NewKeyMessage : public MacUpdateMessage 12 | { 13 | Q_GADGET 14 | 15 | Q_PROPERTY(QByteArray scheme MEMBER scheme) 16 | Q_PROPERTY(QList deviceKeys MEMBER deviceKeys) 17 | 18 | public: 19 | using KeyUpdate = std::tuple; //(deviceId, key, cmac) 20 | 21 | QByteArray scheme; 22 | QList deviceKeys; 23 | 24 | QByteArray signatureData(const KeyUpdate &deviceInfo) const; 25 | 26 | protected: 27 | const QMetaObject *getMetaObject() const override; 28 | }; 29 | 30 | class Q_DATASYNC_EXPORT NewKeyAckMessage : public MacUpdateAckMessage 31 | { 32 | Q_GADGET 33 | 34 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 35 | 36 | public: 37 | NewKeyAckMessage(const NewKeyMessage &message = {}); 38 | 39 | quint32 keyIndex; 40 | 41 | protected: 42 | const QMetaObject *getMetaObject() const override; 43 | }; 44 | 45 | } 46 | 47 | Q_DECLARE_METATYPE(QtDataSync::NewKeyMessage) 48 | Q_DECLARE_METATYPE(QtDataSync::NewKeyMessage::KeyUpdate) 49 | Q_DECLARE_METATYPE(QtDataSync::NewKeyAckMessage) 50 | 51 | #endif // QTDATASYNC_NEWKEYMESSAGE_P_H 52 | -------------------------------------------------------------------------------- /tests/auto/datasync/tests.pri: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | QT = core testlib datasync-private 4 | 5 | CONFIG += console 6 | CONFIG -= app_bundle 7 | 8 | DEFINES += SRCDIR=\\\"$$_PRO_FILE_PWD_/\\\" 9 | 10 | linux: BUILD_LIB_DIR = $$shadowed($$dirname(_QMAKE_CONF_))/lib 11 | else: BUILD_LIB_DIR = $$OUT_PWD/../TestLib/ 12 | 13 | win32:CONFIG(release, debug|release): LIBS += -L$$BUILD_LIB_DIR/release -lTestLib 14 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$BUILD_LIB_DIR/debug -lTestLib 15 | else:unix: LIBS += -L$$BUILD_LIB_DIR -lTestLib 16 | 17 | INCLUDEPATH += $$PWD/TestLib 18 | DEPENDPATH += $$PWD/TestLib 19 | 20 | !linux { 21 | win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestLib/release/libTestLib.a 22 | else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestLib/debug/libTestLib.a 23 | else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestLib/release/TestLib.lib 24 | else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../TestLib/debug/TestLib.lib 25 | else:unix: PRE_TARGETDEPS += $$OUT_PWD/../TestLib/libTestLib.a 26 | } 27 | 28 | INCLUDEPATH += $$PWD/../../../src/messages 29 | 30 | DEFINES += KEYSTORE_PATH=\\\"$$OUT_PWD/../../../../plugins/keystores/\\\" 31 | 32 | include($$PWD/../../../src/3rdparty/cryptopp/cryptopp.pri) 33 | include($$PWD/../testrun.pri) 34 | -------------------------------------------------------------------------------- /src/datasync/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.h" 2 | #include "logger_p.h" 3 | #include "setup_p.h" 4 | using namespace QtDataSync; 5 | 6 | Logger::Logger(QByteArray subCategory, const QString &setupName, QObject *parent) : 7 | QObject{parent}, 8 | d{new LoggerPrivate(setupName, std::move(subCategory))} 9 | {} 10 | 11 | Logger::~Logger() = default; 12 | 13 | const QLoggingCategory &Logger::loggingCategory() const 14 | { 15 | return d->logCat; 16 | } 17 | 18 | void Logger::reportFatalError(const QString &error, const char *file, int line, const char *function) 19 | { 20 | QMessageLogger logger(file, line, function, d->logCat.categoryName()); 21 | logger.critical("%s", qUtf8Printable(error)); 22 | 23 | try { 24 | SetupPrivate::engine(d->setupName)->enterFatalState(error, file, line, function, d->logCat.categoryName()); 25 | } catch(...) { 26 | logger.fatal("%s", qUtf8Printable(error)); 27 | } 28 | } 29 | 30 | void Logger::reportFatalError(const char *error, const char *file, int line, const char *function) 31 | { 32 | reportFatalError(QString::fromUtf8(error), file, line, function); 33 | } 34 | 35 | // ------------- PRIVATE IMPLEMENTATION ------------- 36 | 37 | LoggerPrivate::LoggerPrivate(QString setupName, const QByteArray &subCategory) : 38 | setupName{std::move(setupName)}, 39 | catName{"qtdatasync." + this->setupName.toUtf8() + "." + subCategory}, 40 | logCat{catName.constData(), QtInfoMsg} 41 | {} 42 | -------------------------------------------------------------------------------- /tools/appserver/datasyncservice.h: -------------------------------------------------------------------------------- 1 | #ifndef DATASYNCSERVICE_H 2 | #define DATASYNCSERVICE_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include "clientconnector.h" 10 | #include "databasecontroller.h" 11 | 12 | class DatasyncService : public QtService::Service 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | enum ServiceCodes { 18 | CodeOffset = 128, 19 | CleanupCode 20 | }; 21 | Q_ENUM(ServiceCodes) 22 | 23 | explicit DatasyncService(int &argc, char **argv); 24 | 25 | const QSettings *configuration() const; 26 | QThreadPool *threadPool() const; 27 | QString absolutePath(const QString &path) const; 28 | 29 | protected: 30 | CommandResult onStart() override; 31 | CommandResult onStop(int &exitCode) override; 32 | CommandResult onReload() override; 33 | CommandResult onPause() override; 34 | CommandResult onResume() override; 35 | 36 | private Q_SLOTS: 37 | void completeStartup(bool ok); 38 | 39 | private: 40 | const QSettings *_config; 41 | QThreadPool *_mainPool; 42 | ClientConnector *_connector; 43 | DatabaseController *_database; 44 | 45 | QString findConfig() const; 46 | 47 | void sigusr1(); 48 | void command(int cmd); 49 | void setLogLevel(); 50 | void setupThreadPool(); 51 | }; 52 | 53 | #undef qService 54 | #define qService static_cast(QtService::Service::instance()) 55 | 56 | #endif // DATASYNCSERVICE_H 57 | -------------------------------------------------------------------------------- /src/datasync/accountmanager_p.rep: -------------------------------------------------------------------------------- 1 | #include "qtdatasync_global.h" 2 | #include "accountmanager.h" 3 | 4 | class AccountManagerPrivate { 5 | PROP(QString setupName READONLY) 6 | PROP(QString deviceName READWRITE); 7 | PROP(QByteArray deviceFingerprint READONLY); 8 | PROP(QString lastError READONLY); 9 | 10 | SLOT(void listDevices()); 11 | SLOT(void removeDevice(QUuid deviceId)); 12 | SLOT(void updateExchangeKey()); 13 | SLOT(void resetAccount(bool keepData)); 14 | SLOT(void changeRemote(const QtDataSync::RemoteConfig &config, bool keepData)); 15 | SLOT(void exportAccount(QUuid id, bool includeServer)); 16 | SLOT(void exportAccountTrusted(QUuid id, bool includeServer, const QString &password)); 17 | SLOT(void importAccount(const QtDataSync::JsonObject &importData, bool keepData)); 18 | SLOT(void importAccountTrusted(const QtDataSync::JsonObject &importData, const QString &password, bool keepData)); 19 | SLOT(void replyToLogin(QUuid deviceId, bool accept)); 20 | 21 | SIGNAL(accountDevices(const QList &devices)); 22 | SIGNAL(accountExportReady(QUuid id, const QtDataSync::JsonObject &exportData)); 23 | SIGNAL(accountExportError(QUuid id, const QString &errorString)); 24 | SIGNAL(accountImportResult(bool success, const QString &error)); 25 | SIGNAL(loginRequested(const QtDataSync::DeviceInfo &deviceInfo)); 26 | SIGNAL(importCompleted()); 27 | SIGNAL(accountAccessGranted(QUuid deviceId)); 28 | }; 29 | -------------------------------------------------------------------------------- /src/datasync/rothreadedbackend/exchangebuffer_p.h: -------------------------------------------------------------------------------- 1 | #ifndef EXCHANGEBUFFER_P_H 2 | #define EXCHANGEBUFFER_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "qtdatasync_global.h" 10 | 11 | namespace QtDataSync { 12 | 13 | class Q_DATASYNC_EXPORT ExchangeBuffer : public QIODevice 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit ExchangeBuffer(QObject *parent = nullptr); 19 | ~ExchangeBuffer() override; 20 | 21 | bool connectTo(ExchangeBuffer *partner, bool blocking = false); 22 | 23 | bool isSequential() const override; 24 | void close() override; 25 | qint64 bytesAvailable() const override; 26 | 27 | Q_SIGNALS: 28 | void partnerConnected(QPrivateSignal); 29 | void partnerDisconnected(QPrivateSignal); 30 | void disconnected(QPrivateSignal); //alias signal of partnerDisconnected for remote objects (naming convention) 31 | 32 | protected: 33 | qint64 readData(char *data, qint64 maxlen) override; 34 | qint64 writeData(const char *data, qint64 len) override; 35 | 36 | private Q_SLOTS: 37 | bool openInteral(ExchangeBuffer *partner); 38 | void receiveData(const QByteArray &data); 39 | void partnerClosed(); 40 | 41 | private: 42 | QPointer _partner; 43 | 44 | QQueue _buffers; 45 | int _index; 46 | qint64 _size; 47 | 48 | bool open(OpenMode mode) override; 49 | }; 50 | 51 | } 52 | 53 | Q_DECLARE_LOGGING_CATEGORY(rothreadedbackend) 54 | 55 | #endif // EXCHANGEBUFFER_P_H 56 | -------------------------------------------------------------------------------- /src/datasync/controller_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_CONTROLLER_P_H 2 | #define QTDATASYNC_CONTROLLER_P_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "qtdatasync_global.h" 11 | #include "defaults.h" 12 | #include "logger.h" 13 | 14 | namespace QtDataSync { 15 | 16 | class Q_DATASYNC_EXPORT Controller : public QObject 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit Controller(const QByteArray &name, 22 | Defaults defaults, 23 | QObject *parent = nullptr); 24 | 25 | virtual void initialize(const QVariantHash ¶ms); //exceptions are allowed! 26 | virtual void finalize(); 27 | 28 | Q_SIGNALS: 29 | void controllerError(const QString &error); 30 | void operationTimeout(); 31 | void specialOperationTimeout(); 32 | void progressAdded(quint32 delta); 33 | void progressIncrement(); 34 | 35 | protected: 36 | Defaults defaults() const; 37 | Logger *logger() const; 38 | QSettings *settings() const; 39 | 40 | void beginOp(std::chrono::minutes interval = std::chrono::minutes(5), 41 | bool startIfNotRunning = true); 42 | void beginSpecialOp(std::chrono::minutes interval); 43 | void endOp(); 44 | 45 | private Q_SLOTS: 46 | void onTimeout(); 47 | 48 | private: 49 | Defaults _defaults; 50 | Logger *_logger; 51 | QSettings *_settings; 52 | QTimer *_opTimer; 53 | 54 | QDeadlineTimer _specialOp; 55 | }; 56 | 57 | } 58 | 59 | #define QTDATASYNC_LOG_CONTROLLER logger() 60 | 61 | #endif // QTDATASYNC_CONTROLLER_P_H 62 | -------------------------------------------------------------------------------- /src/datasync/changeemitter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_CHANGEEMITTER_P_H 2 | #define QTDATASYNC_CHANGEEMITTER_P_H 3 | 4 | #include 5 | #include 6 | 7 | #include "qtdatasync_global.h" 8 | #include "defaults.h" 9 | #include "emitteradapter_p.h" 10 | 11 | #include "rep_changeemitter_p_source.h" 12 | 13 | namespace QtDataSync { 14 | 15 | //not exported because base it not, too 16 | class ChangeEmitter : public ChangeEmitterSource 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit ChangeEmitter(const Defaults &defaults, QObject *parent = nullptr); 22 | 23 | public Q_SLOTS: 24 | void triggerChange(QObject *origin, 25 | const QtDataSync::ObjectKey &key, 26 | bool deleted, 27 | bool changed); 28 | void triggerClear(QObject *origin, const QByteArray &typeName, const QStringList &ids); 29 | void triggerReset(QObject *origin); 30 | void triggerUpload() override; 31 | 32 | Q_SIGNALS: 33 | void uploadNeeded(); 34 | 35 | void dataChanged(QObject *origin, const QtDataSync::ObjectKey &key, bool deleted); 36 | void dataResetted(QObject *origin); 37 | 38 | protected Q_SLOTS: 39 | //remcon interface 40 | void triggerRemoteChange(const ObjectKey &key, bool deleted, bool changed) override; 41 | void triggerRemoteClear(const QByteArray &typeName, const QStringList &ids) override; 42 | void triggerRemoteReset() override; 43 | 44 | private: 45 | QSharedPointer _cache;//needed to clear cache on remote changes 46 | }; 47 | 48 | } 49 | 50 | #endif // QTDATASYNC_CHANGEEMITTER_P_H 51 | -------------------------------------------------------------------------------- /src/datasync/objectkey.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_OBJECTKEY_H 2 | #define QTDATASYNC_OBJECTKEY_H 3 | 4 | #include 5 | 6 | #include "QtDataSync/qtdatasync_global.h" 7 | 8 | namespace QtDataSync { 9 | 10 | //! Defines a unique key to identify a dataset globally 11 | struct Q_DATASYNC_EXPORT ObjectKey 12 | { 13 | //! The name of the type the dataset is of 14 | QByteArray typeName; 15 | //! The id of the dataset (it's USER property) 16 | QString id; 17 | 18 | //! Default constructor, with optional parameters 19 | ObjectKey(const QByteArray &typeName = {}, const QString &id = {}); 20 | 21 | //! Creates a hash of the object key to anonymize ize 22 | QByteArray hashed() const; 23 | 24 | //! Equality operator 25 | bool operator==(const ObjectKey &other) const; 26 | //! Inequality operator 27 | bool operator!=(const ObjectKey &other) const; 28 | }; 29 | 30 | //! Overload of qHash to use ObjectKey with QHash 31 | uint Q_DATASYNC_EXPORT qHash(const ObjectKey &key, uint seed = 0); 32 | //! Stream operator to stream into a QDataStream 33 | QDataStream Q_DATASYNC_EXPORT &operator<<(QDataStream &stream, const ObjectKey &key); 34 | //! Stream operator to stream out of a QDataStream 35 | QDataStream Q_DATASYNC_EXPORT &operator>>(QDataStream &stream, ObjectKey &key); 36 | //! Stream operator to stream into a QDebug 37 | QDebug Q_DATASYNC_EXPORT operator<<(QDebug debug, const ObjectKey &key); 38 | 39 | } 40 | 41 | Q_DECLARE_METATYPE(QtDataSync::ObjectKey) 42 | Q_DECLARE_TYPEINFO(QtDataSync::ObjectKey, Q_MOVABLE_TYPE); 43 | 44 | #endif // QTDATASYNC_OBJECTKEY_H 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Felix Barz 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/datasync/objectkey.cpp: -------------------------------------------------------------------------------- 1 | #include "objectkey.h" 2 | #include "message_p.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace QtDataSync; 9 | 10 | ObjectKey::ObjectKey(const QByteArray &typeName, const QString &id) : 11 | typeName{typeName}, 12 | id{id} 13 | {} 14 | 15 | QByteArray ObjectKey::hashed() const 16 | { 17 | QCryptographicHash hash(QCryptographicHash::Sha3_256); 18 | hash.addData(typeName); 19 | hash.addData(id.toUtf8()); 20 | return hash.result(); 21 | } 22 | 23 | bool ObjectKey::operator==(const QtDataSync::ObjectKey &other) const 24 | { 25 | return typeName == other.typeName && 26 | id == other.id; 27 | } 28 | 29 | bool ObjectKey::operator!=(const QtDataSync::ObjectKey &other) const 30 | { 31 | return typeName != other.typeName || 32 | id != other.id; 33 | } 34 | 35 | uint QtDataSync::qHash(const QtDataSync::ObjectKey &key, uint seed) { 36 | return qHash(key.typeName, seed) ^ qHash(key.id, seed); 37 | } 38 | 39 | QDataStream &QtDataSync::operator<<(QDataStream &stream, const ObjectKey &key) 40 | { 41 | stream << key.typeName 42 | << static_cast(key.id); 43 | return stream; 44 | } 45 | 46 | QDataStream &QtDataSync::operator>>(QDataStream &stream, ObjectKey &key) 47 | { 48 | Utf8String id; 49 | stream >> key.typeName 50 | >> id; 51 | key.id = id; 52 | return stream; 53 | } 54 | 55 | QDebug QtDataSync::operator<<(QDebug debug, const ObjectKey &key) 56 | { 57 | QDebugStateSaver saver(debug); 58 | debug.nospace().noquote() << '[' << key.typeName << ':' << key.id << ']'; 59 | return debug; 60 | } 61 | -------------------------------------------------------------------------------- /doc/rothreaded.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @page ro_threaded Threaded remote objects 3 | @brief Details on the "threaded" scheme extension to remote objects 4 | 5 | @tableofcontents 6 | 7 | @section ro_intro Threaded RemoteObjects connection 8 | QtRemoteObjects allows to register custom transport protocols. This library implements such a 9 | custom connection mode called `threaded`. Unlike most other protocls, this one only works 10 | within the same process and uses signals in order to transfer the data between source and 11 | replica. 12 | 13 | @section ro_motivation Motivation for such a connection 14 | The reasons are simply: security and performance. For most applications, a single process setup 15 | will be used, and there is no need to expose any of the engines interfaces outside of the 16 | process. This increases the security, as these interfaces could be used by an attacker to add 17 | a new device to your account without you noticing. 18 | 19 | @section ro_usage How to use 20 | The protocol can be used by anyone that links to the datasync library. The protocol gets 21 | selected by specifying a special scheme for the url. One example would be: 22 | @code 23 | threaded://some/identifier 24 | @endcode 25 | 26 | @section ro_multiproc Multi-Process setups 27 | In case you want to use datasync in a multi process context, you cannot use the threaded mode. 28 | Instead, use the QtDataSync::Setup::remoteObjectHost property to specify a custom url on all 29 | setups. As long as you stay on the same machine, it is recommended to use the "local" mode: 30 | @code{.cpp} 31 | setup.setRemoteObjectHost(QUrl("local:datasync_setup_myapp")); 32 | @endcode 33 | */ 34 | -------------------------------------------------------------------------------- /src/messages/registermessage.cpp: -------------------------------------------------------------------------------- 1 | #include "registermessage_p.h" 2 | 3 | using namespace QtDataSync; 4 | 5 | RegisterBaseMessage::RegisterBaseMessage() = default; 6 | 7 | RegisterBaseMessage::RegisterBaseMessage(QString deviceName, QByteArray nonce, const QSharedPointer &signKey, const QSharedPointer &cryptKey, AsymmetricCrypto *crypto) : 8 | InitMessage{std::move(nonce)}, 9 | signAlgorithm{crypto->signatureScheme()}, 10 | signKey{crypto->writeKey(signKey)}, 11 | cryptAlgorithm{crypto->encryptionScheme()}, 12 | cryptKey{crypto->writeKey(cryptKey)}, 13 | deviceName{std::move(deviceName)} 14 | {} 15 | 16 | AsymmetricCryptoInfo *RegisterBaseMessage::createCryptoInfo(CryptoPP::RandomNumberGenerator &rng, QObject *parent) const 17 | { 18 | return new AsymmetricCryptoInfo(rng, 19 | signAlgorithm, 20 | signKey, 21 | cryptAlgorithm, 22 | cryptKey, 23 | parent); 24 | } 25 | 26 | const QMetaObject *RegisterBaseMessage::getMetaObject() const 27 | { 28 | return &staticMetaObject; 29 | } 30 | 31 | 32 | 33 | RegisterMessage::RegisterMessage() = default; 34 | 35 | RegisterMessage::RegisterMessage(QString deviceName, QByteArray nonce, const QSharedPointer &signKey, const QSharedPointer &cryptKey, AsymmetricCrypto *crypto, QByteArray cmac) : 36 | RegisterBaseMessage{std::move(deviceName), 37 | std::move(nonce), 38 | signKey, 39 | cryptKey, 40 | crypto}, 41 | cmac{std::move(cmac)} 42 | {} 43 | 44 | const QMetaObject *RegisterMessage::getMetaObject() const 45 | { 46 | return &staticMetaObject; 47 | } 48 | -------------------------------------------------------------------------------- /src/datasync/setup_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_SETUP_P_H 2 | #define QTDATASYNC_SETUP_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include "qtdatasync_global.h" 11 | #include "setup.h" 12 | #include "defaults.h" 13 | #include "exchangeengine_p.h" 14 | #include "conflictresolver.h" 15 | 16 | namespace QtDataSync { 17 | 18 | //must be exported for tests 19 | class Q_DATASYNC_EXPORT SetupPrivate 20 | { 21 | friend class QtDataSync::Setup; 22 | friend class QtDataSync::EngineThread; 23 | 24 | public: 25 | static void cleanupHandler(); 26 | static unsigned long currentTimeout(); 27 | 28 | static ExchangeEngine *engine(const QString &setupName); 29 | 30 | QDir createStorageDir(const QString &setupName); 31 | void createDefaults(const QString &setupName, const QDir &storageDir, bool passive); 32 | 33 | static QJsonObject parseObj(const QByteArray &data); 34 | 35 | private: 36 | static const QString DefaultLocalDir; 37 | 38 | static QMutex setupMutex; 39 | static QHash> engines; 40 | static unsigned long timeout; 41 | 42 | QString localDir; 43 | QUrl roAddress; 44 | QScopedPointer serializer; 45 | QScopedPointer resolver; 46 | QHash properties; 47 | Setup::FatalErrorHandler fatalErrorHandler; 48 | ExchangeEngine::ImportData initialImport; 49 | 50 | SetupPrivate(); 51 | 52 | static void deleteThread(EngineThread *thread); 53 | }; 54 | 55 | } 56 | 57 | Q_DECLARE_LOGGING_CATEGORY(qdssetup) 58 | 59 | #endif // QTDATASYNC_SETUP_P_H 60 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | } 5 | 6 | dependencies { 7 | classpath 'com.android.tools.build:gradle:2.2.3' 8 | } 9 | } 10 | 11 | allprojects { 12 | repositories { 13 | jcenter() 14 | maven { 15 | url "https://maven.google.com" 16 | } 17 | } 18 | } 19 | 20 | apply plugin: 'com.android.application' 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile "com.android.support:support-compat:+" 25 | } 26 | 27 | android { 28 | /******************************************************* 29 | * The following variables: 30 | * - androidBuildToolsVersion, 31 | * - androidCompileSdkVersion 32 | * - qt5AndroidDir - holds the path to qt android files 33 | * needed to build any Qt application 34 | * on Android. 35 | * 36 | * are defined in gradle.properties file. This file is 37 | * updated by QtCreator and androiddeployqt tools. 38 | * Changing them manually might break the compilation! 39 | *******************************************************/ 40 | 41 | compileSdkVersion androidCompileSdkVersion.toInteger() 42 | 43 | buildToolsVersion androidBuildToolsVersion 44 | 45 | sourceSets { 46 | main { 47 | manifest.srcFile 'AndroidManifest.xml' 48 | java.srcDirs = [qt5AndroidDir + '/src', 'src', 'java'] 49 | aidl.srcDirs = [qt5AndroidDir + '/src', 'src', 'aidl'] 50 | res.srcDirs = [qt5AndroidDir + '/res', 'res'] 51 | resources.srcDirs = ['src'] 52 | renderscript.srcDirs = ['src'] 53 | assets.srcDirs = ['assets'] 54 | jniLibs.srcDirs = ['libs'] 55 | } 56 | } 57 | 58 | lintOptions { 59 | abortOnError false 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/datasync/keystore.cpp: -------------------------------------------------------------------------------- 1 | #include "keystore.h" 2 | #include "cryptocontroller_p.h" 3 | using namespace QtDataSync; 4 | 5 | namespace QtDataSync { 6 | class Q_DATASYNC_EXPORT KeyStorePrivate 7 | { 8 | public: 9 | explicit KeyStorePrivate(Defaults defaults); 10 | Defaults defaults; 11 | }; 12 | } 13 | 14 | KeyStore::KeyStore(const Defaults &defaults, QObject *parent) : 15 | QObject{parent}, 16 | d{new KeyStorePrivate(defaults)} 17 | {} 18 | 19 | QString KeyStore::setupName() const 20 | { 21 | return d->defaults.setupName(); 22 | } 23 | 24 | KeyStore::~KeyStore() = default; 25 | 26 | Defaults KeyStore::defaults() const 27 | { 28 | return d->defaults; 29 | } 30 | 31 | 32 | 33 | KeyStorePrivate::KeyStorePrivate(Defaults defaults) : 34 | defaults{std::move(defaults)} 35 | {} 36 | 37 | 38 | 39 | KeyStoreException::KeyStoreException(const KeyStore * const keyStore, const QString &what) : 40 | Exception{keyStore->defaults(), what}, 41 | _keyStoreName{keyStore->providerName()} 42 | {} 43 | 44 | KeyStoreException::KeyStoreException(const KeyStoreException * const other) : 45 | Exception{other}, 46 | _keyStoreName{other->_keyStoreName} 47 | {} 48 | 49 | QString KeyStoreException::storeProviderName() const 50 | { 51 | return _keyStoreName; 52 | } 53 | 54 | QByteArray KeyStoreException::className() const noexcept 55 | { 56 | return QTDATASYNC_EXCEPTION_NAME(KeyStoreException); 57 | } 58 | 59 | QString KeyStoreException::qWhat() const 60 | { 61 | return Exception::qWhat() + 62 | QStringLiteral("\n\tKeystore: %1") 63 | .arg(_keyStoreName); 64 | } 65 | 66 | void KeyStoreException::raise() const 67 | { 68 | throw (*this); 69 | } 70 | 71 | QException *KeyStoreException::clone() const 72 | { 73 | return new KeyStoreException(this); 74 | } 75 | -------------------------------------------------------------------------------- /src/messages/messages.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | 3 | CONFIG += static 4 | 5 | TARGET = qtdatasync_messages 6 | 7 | DEFINES += QT_BUILD_DATASYNC_LIB #is build as part of the lib regarding exports 8 | 9 | HEADERS += \ 10 | message_p.h \ 11 | identifymessage_p.h \ 12 | registermessage_p.h \ 13 | asymmetriccrypto_p.h \ 14 | accountmessage_p.h \ 15 | loginmessage_p.h \ 16 | welcomemessage_p.h \ 17 | errormessage_p.h \ 18 | syncmessage_p.h \ 19 | changemessage_p.h \ 20 | changedmessage_p.h \ 21 | devicesmessage_p.h \ 22 | removemessage_p.h \ 23 | accessmessage_p.h \ 24 | proofmessage_p.h \ 25 | grantmessage_p.h \ 26 | devicechangemessage_p.h \ 27 | macupdatemessage_p.h \ 28 | keychangemessage_p.h \ 29 | devicekeysmessage_p.h \ 30 | newkeymessage_p.h 31 | 32 | SOURCES += \ 33 | message.cpp \ 34 | identifymessage.cpp \ 35 | registermessage.cpp \ 36 | asymmetriccrypto.cpp \ 37 | accountmessage.cpp \ 38 | loginmessage.cpp \ 39 | welcomemessage.cpp \ 40 | errormessage.cpp \ 41 | syncmessage.cpp \ 42 | changemessage.cpp \ 43 | changedmessage.cpp \ 44 | devicesmessage.cpp \ 45 | removemessage.cpp \ 46 | accessmessage.cpp \ 47 | proofmessage.cpp \ 48 | grantmessage.cpp \ 49 | devicechangemessage.cpp \ 50 | macupdatemessage.cpp \ 51 | keychangemessage.cpp \ 52 | devicekeysmessage.cpp \ 53 | newkeymessage.cpp 54 | 55 | DISTFILES += \ 56 | messages.pri 57 | 58 | include(../3rdparty/cryptopp/cryptopp.pri) 59 | 60 | MODULE_INCLUDEPATH += $$PWD 61 | 62 | load(qt_helper_lib) 63 | CONFIG += qt warning_clean 64 | QT = core 65 | 66 | QDEP_DEPENDS += Skycoder42/CryptoQQ@2.0.3 67 | QDEP_EXPORTS += Skycoder42/CryptoQQ@2.0.3 68 | CONFIG += qdep_no_link 69 | 70 | !load(qdep):error("Failed to load qdep feature! Run 'qdep prfgen --qmake $$QMAKE_QMAKE' to create it.") 71 | -------------------------------------------------------------------------------- /examples/datasync/IosSync/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDisplayName 6 | ${PRODUCT_NAME} 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleGetInfoString 10 | Created by Qt/QMake 11 | CFBundleIconFile 12 | ${ASSETCATALOG_COMPILER_APPICON_NAME} 13 | CFBundleIdentifier 14 | ${PRODUCT_BUNDLE_IDENTIFIER} 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | ${QMAKE_SHORT_VERSION} 21 | CFBundleSignature 22 | ${QMAKE_PKGINFO_TYPEINFO} 23 | CFBundleVersion 24 | ${QMAKE_FULL_VERSION} 25 | LSRequiresIPhoneOS 26 | 27 | MinimumOSVersion 28 | ${IPHONEOS_DEPLOYMENT_TARGET} 29 | NOTE 30 | This file was generated by Qt/QMake. 31 | UILaunchStoryboardName 32 | LaunchScreen 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationPortraitUpsideDown 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationLandscapeRight 39 | 40 | 41 | UIBackgroundModes 42 | 43 | fetch 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/messages/changedmessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_CHANGEDMESSAGE_P_H 2 | #define QTDATASYNC_CHANGEDMESSAGE_P_H 3 | 4 | #include "message_p.h" 5 | 6 | namespace QtDataSync { 7 | 8 | class Q_DATASYNC_EXPORT ChangedMessage : public Message 9 | { 10 | Q_GADGET 11 | 12 | Q_PROPERTY(quint64 dataIndex MEMBER dataIndex) 13 | Q_PROPERTY(quint32 keyIndex MEMBER keyIndex) 14 | Q_PROPERTY(QByteArray salt MEMBER salt) 15 | Q_PROPERTY(QByteArray data MEMBER data) 16 | 17 | public: 18 | quint64 dataIndex = 0; 19 | quint32 keyIndex = 0; 20 | QByteArray salt; 21 | QByteArray data; 22 | 23 | protected: 24 | const QMetaObject *getMetaObject() const override; 25 | }; 26 | 27 | class Q_DATASYNC_EXPORT ChangedInfoMessage : public ChangedMessage 28 | { 29 | Q_GADGET 30 | 31 | Q_PROPERTY(quint32 changeEstimate MEMBER changeEstimate) 32 | 33 | public: 34 | ChangedInfoMessage(quint32 changeEstimate = 0); 35 | 36 | quint32 changeEstimate; 37 | 38 | protected: 39 | const QMetaObject *getMetaObject() const override; 40 | }; 41 | 42 | class Q_DATASYNC_EXPORT LastChangedMessage : public Message 43 | { 44 | Q_GADGET 45 | 46 | protected: 47 | const QMetaObject *getMetaObject() const override; 48 | }; 49 | 50 | class Q_DATASYNC_EXPORT ChangedAckMessage : public Message 51 | { 52 | Q_GADGET 53 | 54 | Q_PROPERTY(quint64 dataIndex MEMBER dataIndex) 55 | 56 | public: 57 | ChangedAckMessage(quint64 dataIndex = 0); 58 | 59 | quint64 dataIndex; 60 | 61 | protected: 62 | const QMetaObject *getMetaObject() const override; 63 | }; 64 | 65 | } 66 | 67 | Q_DECLARE_METATYPE(QtDataSync::ChangedMessage) 68 | Q_DECLARE_METATYPE(QtDataSync::ChangedInfoMessage) 69 | Q_DECLARE_METATYPE(QtDataSync::LastChangedMessage) 70 | Q_DECLARE_METATYPE(QtDataSync::ChangedAckMessage) 71 | 72 | #endif // QTDATASYNC_CHANGEDMESSAGE_P_H 73 | -------------------------------------------------------------------------------- /tools/appserver/singletaskqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef SINGLETASKQUEUE_H 2 | #define SINGLETASKQUEUE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class SingleTaskQueue : public QObject 13 | { 14 | Q_OBJECT 15 | 16 | public: 17 | class Task : public QRunnable { 18 | friend class SingleTaskQueue; 19 | public: 20 | Task(SingleTaskQueue *queue); 21 | virtual void safeRun() = 0; 22 | void run() final; 23 | 24 | private: 25 | QWeakPointer _lockRef; 26 | SingleTaskQueue *_queue; 27 | }; 28 | 29 | template 30 | class GenericTask : public Task { 31 | public: 32 | GenericTask(const TFunction &fn, SingleTaskQueue *queue); 33 | void safeRun() final; 34 | 35 | private: 36 | const TFunction _fn; 37 | }; 38 | 39 | explicit SingleTaskQueue(QThreadPool *pool, QObject *parent = nullptr); 40 | ~SingleTaskQueue() override; 41 | 42 | void enqueueTask(Task *task); 43 | template 44 | inline void enqueue(const TFunction &fn) { 45 | enqueueTask(new GenericTask(fn, this)); 46 | } 47 | 48 | bool clear(); 49 | bool isFinished() const; 50 | 51 | private: 52 | QThreadPool *_pool; 53 | 54 | QSharedPointer _lock; 55 | QQueue _tasks; 56 | 57 | void nextTask(QMutexLocker &lock); 58 | void completeTask(const Task * const task, QMutexLocker &lock); 59 | }; 60 | 61 | template 62 | SingleTaskQueue::GenericTask::GenericTask(const TFunction &fn, SingleTaskQueue *queue) : 63 | Task(queue), 64 | _fn(fn) 65 | {} 66 | 67 | template 68 | void SingleTaskQueue::GenericTask::safeRun() 69 | { 70 | _fn(); 71 | } 72 | 73 | #endif // SINGLETASKQUEUE_H 74 | -------------------------------------------------------------------------------- /doc/migrationhelper.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @class QtDataSync::MigrationHelper 3 | 4 | If you used QtDataSync below version 4 before, you will have to use this class to migrate the data 5 | from that old datasync to the current new one, as they are not compatible. This is what this class 6 | is used for. 7 | 8 | The migration is performed asynchronously once started and cannot be stopped. To start a 9 | migration, use startMigration(). 10 | 11 | @sa MigrationHelper::startMigration, MigrationHelper::migrationDone 12 | */ 13 | 14 | /*! 15 | @fn QtDataSync::MigrationHelper::MigrationHelper(QObject *) 16 | 17 | @param parent The parent object 18 | @throws SetupDoesNotExistException Thrown if the default setup was not created yet 19 | */ 20 | 21 | /*! 22 | @fn QtDataSync::MigrationHelper::MigrationHelper(const QString &, QObject *) 23 | 24 | @param setupName The name of the setup to connect to 25 | @param parent The parent object 26 | @throws SetupDoesNotExistException Thrown if the given setup was not created yet 27 | */ 28 | 29 | /*! 30 | @fn QtDataSync::MigrationHelper::startMigration 31 | 32 | @param storageDir The old datasync directory to import the data from 33 | @param flags Flags to configure what and how to migrate the data 34 | 35 | The `storageDir` must be the directory that the old datasync used as storage directory. If you 36 | did not change it, the DefaultOldStorageDir constant can be used, as it points to the previous 37 | default datasync storage dir. 38 | 39 | Migration is performed asynchronously with the status beeing reported via the signals. Errors, 40 | warnings and other stuff is logged as usual. Use the `qtdatasync..migration` logging 41 | category to filter for it. 42 | 43 | @sa MigrationHelper::MigrationFlag, MigrationHelper::DefaultOldStorageDir, 44 | MigrationHelper::migrationDone, MigrationHelper::migrationPrepared, 45 | MigrationHelper::migrationProgress, 46 | */ 47 | -------------------------------------------------------------------------------- /src/datasyncios/QIOSApplicationDelegate+QtDatasyncAppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "QIOSApplicationDelegate+QtDatasyncAppDelegate_p.h" 2 | #import "qtdatasyncappdelegate_capi_p.h" 3 | #include 4 | #include "iossyncdelegate_p.h" 5 | 6 | @implementation QIOSApplicationDelegate (QtDatasyncAppDelegate) 7 | 8 | -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 9 | { 10 | qDebug() << "initialized QtDatasyncAppDelegate"; 11 | return YES; 12 | } 13 | 14 | -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler 15 | { 16 | QtDataSync::IosSyncDelegatePrivate::performFetch([=](QtDataSync::IosSyncDelegate::SyncResult result) { 17 | switch(result) { 18 | case QtDataSync::IosSyncDelegate::SyncResult::NewData: 19 | completionHandler(UIBackgroundFetchResultNewData); 20 | break; 21 | case QtDataSync::IosSyncDelegate::SyncResult::NoData: 22 | completionHandler(UIBackgroundFetchResultNoData); 23 | break; 24 | case QtDataSync::IosSyncDelegate::SyncResult::Error: 25 | completionHandler(UIBackgroundFetchResultFailed); 26 | break; 27 | default: 28 | Q_UNREACHABLE(); 29 | break; 30 | } 31 | }); 32 | } 33 | 34 | 35 | 36 | void QtDatasyncAppDelegateInitialize() 37 | { 38 | QIOSApplicationDelegate *appDelegate = (QIOSApplicationDelegate *)[[UIApplication sharedApplication] delegate]; 39 | Q_ASSERT_X(appDelegate, Q_FUNC_INFO, "Failed to initialize QIOSApplicationDelegate (QtDatasyncAppDelegate)"); 40 | } 41 | 42 | void setSyncInterval(double intervalSeconds) 43 | { 44 | if(intervalSeconds == -1.0) 45 | [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalNever]; 46 | else 47 | [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:intervalSeconds]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/imports/datasync/datasync.pro: -------------------------------------------------------------------------------- 1 | QT = core datasync qml 2 | android: QT += datasyncandroid 3 | ios: QT += datasyncios 4 | 5 | CXX_MODULE = datasync 6 | TARGETPATH = de/skycoder42/QtDataSync 7 | TARGET = declarative_datasync 8 | IMPORT_VERSION = $$MODULE_VERSION_IMPORT 9 | DEFINES += "VERSION_MAJOR=$$MODULE_VERSION_MAJOR" 10 | DEFINES += "VERSION_MINOR=$$MODULE_VERSION_MINOR" 11 | 12 | HEADERS += \ 13 | qqmldatastore.h \ 14 | qqmlsyncmanager.h \ 15 | qqmlaccountmanager.h \ 16 | qqmldatastoremodel.h \ 17 | qqmluserexchangemanager.h \ 18 | qtdatasync_plugin.h \ 19 | qqmleventcursor.h 20 | 21 | SOURCES += \ 22 | qqmldatastore.cpp \ 23 | qqmlsyncmanager.cpp \ 24 | qqmlaccountmanager.cpp \ 25 | qqmldatastoremodel.cpp \ 26 | qqmluserexchangemanager.cpp \ 27 | qtdatasync_plugin.cpp \ 28 | qqmleventcursor.cpp 29 | 30 | ios { 31 | HEADERS += qqmliossyncsingleton.h 32 | SOURCES += qqmliossyncsingleton.cpp 33 | } 34 | 35 | OTHER_FILES += qmldir 36 | 37 | CONFIG += qmlcache 38 | load(qml_plugin) 39 | 40 | generate_qmltypes { 41 | # run again to overwrite module env 42 | ldpath.name = LD_LIBRARY_PATH 43 | ldpath.value = "$$shadowed($$dirname(_QMAKE_CONF_))/lib/:$$[QT_INSTALL_LIBS]:$$(LD_LIBRARY_PATH)" 44 | qmlpath.name = QML2_IMPORT_PATH 45 | qmlpath.value = "$$shadowed($$dirname(_QMAKE_CONF_))/qml/:$$[QT_INSTALL_QML]:$$(QML2_IMPORT_PATH)" 46 | PLGDUMP_ENV = ldpath qmlpath 47 | QT_TOOL_ENV = ldpath qmlpath 48 | qtPrepareTool(QMLPLUGINDUMP, qmlplugindump) 49 | QT_TOOL_ENV = 50 | 51 | #overwrite the target deps as make target is otherwise not detected 52 | qmltypes.depends = ../../../qml/$$TARGETPATH/$(TARGET) 53 | OLDDMP = $$take_first(qmltypes.commands) 54 | qmltypes.commands = $$QMLPLUGINDUMP $${qmltypes.commands} 55 | message("replaced $$OLDDMP with $$QMLPLUGINDUMP") 56 | 57 | mfirst.target = all 58 | mfirst.depends += qmltypes 59 | QMAKE_EXTRA_TARGETS += mfirst 60 | } 61 | 62 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/mockserver.cpp: -------------------------------------------------------------------------------- 1 | #include "mockserver.h" 2 | 3 | #ifdef Q_OS_WIN 4 | #define WAIT_TIMEOUT 10000 5 | #else 6 | #define WAIT_TIMEOUT 5000 7 | #endif 8 | 9 | MockServer::MockServer(QObject *parent) : 10 | QObject(parent), 11 | _server(new QWebSocketServer(QStringLiteral("mockserver"), QWebSocketServer::NonSecureMode, this)), 12 | _connectedSpy(_server, &QWebSocketServer::newConnection) 13 | { 14 | connect(_server, &QWebSocketServer::acceptError, this, [this]() { 15 | QFAIL(qUtf8Printable(_server->errorString())); 16 | }); 17 | connect(_server, &QWebSocketServer::serverError, this, [this]() { 18 | QFAIL(qUtf8Printable(_server->errorString())); 19 | }); 20 | connect(_server, &QWebSocketServer::closed, this, [this]() { 21 | QFAIL(qUtf8Printable(_server->errorString())); 22 | }); 23 | connect(_server, &QWebSocketServer::peerVerifyError, this, [this](const QSslError &error) { 24 | QFAIL(qUtf8Printable(error.errorString())); 25 | }); 26 | connect(_server, &QWebSocketServer::sslErrors, this, [this](const QList &errors) { 27 | for(auto error : errors) 28 | QFAIL(qUtf8Printable(error.errorString())); 29 | }); 30 | } 31 | 32 | void MockServer::init() 33 | { 34 | QVERIFY(_server->listen(QHostAddress::LocalHost)); 35 | } 36 | 37 | QUrl MockServer::url() const 38 | { 39 | return _server->serverUrl(); 40 | } 41 | 42 | void MockServer::clear() 43 | { 44 | _connectedSpy.clear(); 45 | } 46 | 47 | bool MockServer::waitForConnected(MockConnection **connection, int timeout) 48 | { 49 | auto ok = false; 50 | [&]() { 51 | QVERIFY(connection); 52 | if(_connectedSpy.isEmpty()) 53 | QVERIFY(_connectedSpy.wait(WAIT_TIMEOUT + timeout)); 54 | QVERIFY(!_connectedSpy.isEmpty()); 55 | QVERIFY(_server->hasPendingConnections()); 56 | _connectedSpy.removeFirst(); 57 | *connection = new MockConnection(_server->nextPendingConnection(), this); 58 | ok = true; 59 | }(); 60 | return ok; 61 | } 62 | -------------------------------------------------------------------------------- /src/messages/identifymessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_IDENTIFYMESSAGE_H 2 | #define QTDATASYNC_IDENTIFYMESSAGE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "message_p.h" 10 | 11 | namespace QtDataSync { 12 | 13 | class Q_DATASYNC_EXPORT IncompatibleVersionException : public QException 14 | { 15 | public: 16 | IncompatibleVersionException(QVersionNumber invalidVersion); 17 | 18 | QVersionNumber invalidVersion() const; 19 | 20 | const char *what() const noexcept override; 21 | void raise() const override; 22 | QException *clone() const override; 23 | 24 | private: 25 | const QVersionNumber _version; 26 | const QByteArray _msg; 27 | }; 28 | 29 | class Q_DATASYNC_EXPORT InitMessage : public Message 30 | { 31 | Q_GADGET 32 | 33 | Q_PROPERTY(QVersionNumber protocolVersion MEMBER protocolVersion) 34 | Q_PROPERTY(QByteArray nonce MEMBER nonce) 35 | 36 | public: 37 | static const QVersionNumber CurrentVersion; 38 | static const QVersionNumber CompatVersion; 39 | static const int NonceSize = 16; 40 | InitMessage(); 41 | 42 | QVersionNumber protocolVersion = CurrentVersion; 43 | QByteArray nonce; 44 | 45 | protected: 46 | InitMessage(QByteArray nonce); 47 | 48 | const QMetaObject *getMetaObject() const override; 49 | bool validate() override; 50 | }; 51 | 52 | class Q_DATASYNC_EXPORT IdentifyMessage : public InitMessage 53 | { 54 | Q_GADGET 55 | 56 | Q_PROPERTY(quint32 uploadLimit MEMBER uploadLimit) 57 | 58 | public: 59 | IdentifyMessage(quint32 uploadLimit = 0); 60 | 61 | static IdentifyMessage createRandom(quint32 uploadLimit, CryptoPP::RandomNumberGenerator &rng); 62 | 63 | quint32 uploadLimit; 64 | 65 | protected: 66 | const QMetaObject *getMetaObject() const override; 67 | }; 68 | 69 | } 70 | 71 | Q_DECLARE_METATYPE(QtDataSync::InitMessage) 72 | Q_DECLARE_METATYPE(QtDataSync::IdentifyMessage) 73 | 74 | #endif // QTDATASYNC_IDENTIFYMESSAGE_H 75 | -------------------------------------------------------------------------------- /tools/appserver/dockerbuild/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | export MAKEFLAGS=-j$(nproc) 5 | export QDEP_CACHE_DIR=/tmp/qdep-cache 6 | 7 | DS_NAME=qdsappd 8 | MAIN_DEP="qt5-qtbase qt5-qtbase-postgresql qt5-qtwebsockets icu-libs" 9 | DEV_DEP="qt5-qtbase-dev qt5-qtwebsockets-dev qt5-qttools qt5-qttools-dev icu-dev build-base python3 git perl gawk" 10 | PIP_DEV_DEPS="qdep appdirs lockfile argcomplete" 11 | 12 | if [ ! -d "/tmp/src/.git" ]; then 13 | echo "Failed to find .git directory - not supported!" 14 | exit 1 15 | fi 16 | 17 | apk add --no-cache $MAIN_DEP $DEV_DEP 18 | pip3 install $PIP_DEV_DEPS 19 | 20 | # prepare qdep 21 | qdep prfgen --qmake qmake-qt5 22 | 23 | # build json serializer, qtservice 24 | mkdir /tmp/sysbuild 25 | cd /tmp/sysbuild 26 | for repo in QtJsonSerializer QtService; do 27 | git clone https://github.com/Skycoder42/$repo.git ./$repo 28 | cd $repo 29 | git checkout $(git describe --tags --abbrev=0) 30 | 31 | if [ -f src/imports/imports.pro ]; then 32 | echo "SUBDIRS -= imports" >> src/src.pro 33 | fi 34 | 35 | qmake-qt5 36 | make 37 | make install 38 | cd .. 39 | done 40 | 41 | # build datasync 42 | cd /tmp/src 43 | echo "SUBDIRS = 3rdparty messages" >> src/src.pro 44 | echo "SUBDIRS = " >> examples/examples.pro 45 | echo "SUBDIRS = " >> tests/tests.pro 46 | 47 | qmake-qt5 48 | make qmake_all 49 | make 50 | make install 51 | 52 | #create special symlinks, dirs and move the env script 53 | mkdir -p /etc/$DS_NAME 54 | ln -s $(qmake-qt5 -query QT_INSTALL_BINS)/$DS_NAME /usr/bin/$DS_NAME || true #allow to fail if already exists 55 | mv /tmp/src/tools/appserver/dockerbuild/env_start.sh /usr/bin/ 56 | 57 | # test if working 58 | /usr/bin/$DS_NAME --version 59 | 60 | # remove unused stuff 61 | pip3 uninstall -y $PIP_DEV_DEPS 62 | apk del --no-cache --purge "*-dev" $DEV_DEP 63 | rm -rf /tmp/* 64 | rm -rf $HOME/.cache/qpmx 65 | rm -rf /usr/local/bin/qpm 66 | 67 | # test if still working 68 | /usr/bin/$DS_NAME --version 69 | -------------------------------------------------------------------------------- /src/plugins/keystores/plain/plainkeystore.cpp: -------------------------------------------------------------------------------- 1 | #include "plainkeystore.h" 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | PlainKeyStore::PlainKeyStore(const QtDataSync::Defaults &defaults, QObject *parent) : 8 | KeyStore(defaults, parent), 9 | _settings(nullptr) 10 | {} 11 | 12 | QString PlainKeyStore::providerName() const 13 | { 14 | return QStringLiteral("plain"); 15 | } 16 | 17 | bool PlainKeyStore::isOpen() const 18 | { 19 | return _settings; 20 | } 21 | 22 | void PlainKeyStore::openStore() 23 | { 24 | if(!_settings) { 25 | _settings = new QSettings(defaults().storageDir().absoluteFilePath(QStringLiteral("plain.keystore")), 26 | QSettings::IniFormat, 27 | this); 28 | if(_settings->status() != QSettings::NoError) { 29 | _settings->deleteLater(); 30 | _settings = nullptr; 31 | throw QtDataSync::KeyStoreException(this, QStringLiteral("Keystore file is not accessible")); 32 | } 33 | } 34 | } 35 | 36 | void PlainKeyStore::closeStore() 37 | { 38 | if(_settings) { 39 | _settings->sync(); 40 | _settings->deleteLater(); 41 | _settings = nullptr; 42 | } 43 | } 44 | 45 | bool PlainKeyStore::contains(const QString &key) const 46 | { 47 | return _settings->contains(key); 48 | } 49 | 50 | void PlainKeyStore::save(const QString &key, const QByteArray &pKey) 51 | { 52 | _settings->setValue(key, pKey); 53 | _settings->sync(); 54 | if(_settings->status() != QSettings::NoError) 55 | throw QtDataSync::KeyStoreException(this, QStringLiteral("Failed to write to keystore file")); 56 | } 57 | 58 | QByteArray PlainKeyStore::load(const QString &key) 59 | { 60 | return _settings->value(key).toByteArray(); 61 | } 62 | 63 | void PlainKeyStore::remove(const QString &key) 64 | { 65 | _settings->remove(key); 66 | _settings->sync(); 67 | if(_settings->status() != QSettings::NoError) 68 | throw QtDataSync::KeyStoreException(this, QStringLiteral("Failed to delete from keystore file")); 69 | } 70 | -------------------------------------------------------------------------------- /doc/makedoc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # $1: $$SRCDIR 3 | # $2: $$VERSION 4 | # $3: $$[QT_INSTALL_BINS] 5 | # $4: $$[QT_INSTALL_HEADERS] 6 | # $5: $$[QT_INSTALL_DOCS] 7 | # $pwd: dest dir 8 | set -e 9 | 10 | scriptDir=$(dirname "$0") 11 | destDir="$(pwd)" 12 | srcDir=$1 13 | version=$2 14 | verTag=$(echo "$version" | sed -e 's/\.//g') 15 | qtBins=$3 16 | qtHeaders=$4 17 | qtDocs=$5 18 | doxyTemplate="$srcDir/Doxyfile" 19 | doxyRes=Doxyfile.generated 20 | readme="$destDir/README.md" 21 | doxme="$scriptDir/doxme.py" 22 | 23 | python3 "$doxme" "$srcDir/../README.md" 24 | 25 | cat "$doxyTemplate" > $doxyRes 26 | echo "PROJECT_NUMBER = \"$version\"" >> $doxyRes 27 | echo "INPUT += \"$readme\"" >> $doxyRes 28 | echo "USE_MDFILE_AS_MAINPAGE = \"$readme\"" >> $doxyRes 29 | echo "OUTPUT_DIRECTORY = \"$destDir\"" >> $doxyRes 30 | echo "QHP_NAMESPACE = \"de.skycoder42.qtdatasync.$verTag\"" >> $doxyRes 31 | echo "QHP_CUST_FILTER_NAME = \"DataSync $version\"" >> $doxyRes 32 | echo "QHP_CUST_FILTER_ATTRS = \"qtdatasync $version\"" >> $doxyRes 33 | echo "QHG_LOCATION = \"$qtBins/qhelpgenerator\"" >> $doxyRes 34 | echo "INCLUDE_PATH += \"$qtHeaders\"" >> $doxyRes 35 | echo "GENERATE_TAGFILE = \"$destDir/qtdatasync/qtdatasync.tags\"" >> $doxyRes 36 | if [ "$DOXY_STYLE" ]; then 37 | echo "HTML_STYLESHEET = \"$DOXY_STYLE\"" >> $doxyRes 38 | fi 39 | if [ "$DOXY_STYLE_EXTRA" ]; then 40 | echo "HTML_EXTRA_STYLESHEET = \"$DOXY_STYLE_EXTRA\"" >> $doxyRes 41 | fi 42 | 43 | for tagFile in $(find "$qtDocs" -name *.tags); do 44 | if [ $(basename "$tagFile") == "qtjsonserializer.tags" ]; then 45 | echo "TAGFILES += \"$tagFile=https://skycoder42.github.io/QtJsonSerializer\"" >> $doxyRes 46 | elif [ $(basename "$tagFile") == "qtservice.tags" ]; then 47 | echo "TAGFILES += \"$tagFile=https://skycoder42.github.io/QtService\"" >> $doxyRes 48 | elif [ $(basename "$tagFile") != "qtdatasync.tags" ]; then 49 | echo "TAGFILES += \"$tagFile=https://doc.qt.io/qt-5\"" >> $doxyRes 50 | fi 51 | done 52 | 53 | cd "$srcDir" 54 | doxygen "$destDir/$doxyRes" 55 | -------------------------------------------------------------------------------- /src/datasync/emitteradapter_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_EMITTERADAPTER_P_H 2 | #define QTDATASYNC_EMITTERADAPTER_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "qtdatasync_global.h" 9 | #include "objectkey.h" 10 | #include "defaults.h" 11 | 12 | namespace QtDataSync { 13 | 14 | class Q_DATASYNC_EXPORT EmitterAdapter : public QObject 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | struct Q_DATASYNC_EXPORT CacheInfo { 20 | QReadWriteLock lock; 21 | QCache cache; 22 | 23 | CacheInfo(int maxSize); 24 | }; 25 | 26 | explicit EmitterAdapter(QObject *changeEmitter, 27 | QSharedPointer cacheInfo, 28 | QObject *origin = nullptr); 29 | 30 | void triggerChange(const QtDataSync::ObjectKey &key, bool deleted, bool changed); 31 | void triggerClear(const QByteArray &typeName, const QStringList &ids); 32 | void triggerReset(); 33 | void triggerUpload(); 34 | 35 | void putCached(const ObjectKey &key, const QJsonObject &data, int costs); 36 | void putCached(const QList &keys, const QList &data, const QList &costs); 37 | bool getCached(const ObjectKey &key, QJsonObject &data); 38 | bool dropCached(const ObjectKey &key); 39 | void dropCached(const QByteArray &typeName, const QStringList &ids); 40 | void dropCached(); 41 | 42 | Q_SIGNALS: 43 | void dataChanged(const QtDataSync::ObjectKey &key, bool deleted); 44 | void dataResetted(); 45 | 46 | private Q_SLOTS: 47 | void dataChangedImpl(QObject *origin, const QtDataSync::ObjectKey &key, bool deleted); 48 | void dataResettedImpl(QObject *origin); 49 | void remoteDataChangedImpl(const QtDataSync::ObjectKey &key, bool deleted); 50 | void remoteDataResettedImpl(); 51 | 52 | private: 53 | bool _isPrimary; 54 | QObject *_emitterBackend; 55 | QSharedPointer _cache; 56 | }; 57 | 58 | } 59 | 60 | Q_DECLARE_METATYPE(QSharedPointer) 61 | 62 | #endif // QTDATASYNC_EMITTERADAPTER_P_H 63 | -------------------------------------------------------------------------------- /src/plugins/keystores/secretservice/secretservicekeystore.cpp: -------------------------------------------------------------------------------- 1 | #include "secretservicekeystore.h" 2 | 3 | #include 4 | 5 | SecretServiceKeyStore::SecretServiceKeyStore(const QtDataSync::Defaults &defaults, const QString &providerName, QObject *parent) : 6 | KeyStore(defaults, parent), 7 | _providerName(providerName), 8 | _libSecret(new LibSecretWrapper(QCoreApplication::applicationName().toUtf8())) 9 | {} 10 | 11 | QString SecretServiceKeyStore::providerName() const 12 | { 13 | return _providerName; 14 | } 15 | 16 | bool SecretServiceKeyStore::isOpen() const 17 | { 18 | return _libSecret->isOpen(); 19 | } 20 | 21 | void SecretServiceKeyStore::openStore() 22 | { 23 | try { 24 | _libSecret->setup(); 25 | } catch(LibSecretException &e) { 26 | throw QtDataSync::KeyStoreException(this, QString::fromUtf8(e.what())); 27 | } 28 | } 29 | 30 | void SecretServiceKeyStore::closeStore() 31 | { 32 | _libSecret->cleanup(); 33 | } 34 | 35 | bool SecretServiceKeyStore::contains(const QString &key) const 36 | { 37 | try { 38 | if(_libSecret->loadSecret(key.toUtf8()).isEmpty()) 39 | return false; 40 | else 41 | return true; 42 | } catch (...) { 43 | return false; 44 | } 45 | } 46 | 47 | void SecretServiceKeyStore::save(const QString &key, const QByteArray &pKey) 48 | { 49 | try { 50 | _libSecret->storeSecret(key.toUtf8(), pKey); 51 | } catch(LibSecretException &e) { 52 | throw QtDataSync::KeyStoreException(this, QString::fromUtf8(e.what())); 53 | } 54 | } 55 | 56 | QByteArray SecretServiceKeyStore::load(const QString &key) 57 | { 58 | try { 59 | return _libSecret->loadSecret(key.toUtf8()); 60 | } catch(LibSecretException &e) { 61 | throw QtDataSync::KeyStoreException(this, QString::fromUtf8(e.what())); 62 | } 63 | } 64 | 65 | void SecretServiceKeyStore::remove(const QString &key) 66 | { 67 | try { 68 | _libSecret->removeSecret(key.toUtf8()); 69 | } catch(LibSecretException &e) { 70 | throw QtDataSync::KeyStoreException(this, QString::fromUtf8(e.what())); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /examples/datasync/AndroidSync/android/src/de/skycoder42/qtdatasync/sample/androidsync/SvcHelper.java: -------------------------------------------------------------------------------- 1 | package de.skycoder42.qtdatasync.sample.androidsync; 2 | 3 | import android.os.Build; 4 | 5 | import android.content.Context; 6 | 7 | import android.app.Notification; 8 | import android.app.NotificationChannel; 9 | import android.app.NotificationManager; 10 | 11 | import android.graphics.BitmapFactory; 12 | 13 | import android.support.v4.app.NotificationCompat; 14 | 15 | public class SvcHelper { 16 | private static final String ForegroundChannelId = "de.skycoder42.qtdatasync.sample.androidsync.notify"; 17 | 18 | //! [java_create_notification] 19 | public static Notification createFgNotification(Context context) { 20 | return new NotificationCompat.Builder(context, ForegroundChannelId) 21 | .setContentTitle("AndroidSync Synchronization Service") 22 | .setContentText("Synchronizing…") 23 | .setContentInfo("AndroidSync") 24 | .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.icon)) 25 | .setSmallIcon(R.drawable.icon) 26 | .setLocalOnly(true) 27 | .setOngoing(true) 28 | .setCategory(NotificationCompat.CATEGORY_SERVICE) 29 | .build(); 30 | } 31 | //! [java_create_notification] 32 | 33 | //! [java_create_channel] 34 | public static void registerNotificationChannel(Context context) { 35 | if(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) 36 | return; 37 | 38 | NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); 39 | 40 | //create foreground channel 41 | NotificationChannel foreground = new NotificationChannel(ForegroundChannelId, 42 | "Synchronization Service", 43 | NotificationManager.IMPORTANCE_MIN); 44 | foreground.setDescription("Is shown when the application synchronizes"); 45 | foreground.enableLights(false); 46 | foreground.enableVibration(false); 47 | foreground.setShowBadge(false); 48 | manager.createNotificationChannel(foreground); 49 | } 50 | //! [java_create_channel] 51 | } 52 | -------------------------------------------------------------------------------- /src/datasync/accountmanager_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_ACCOUNTMANAGER_P_H 2 | #define QTDATASYNC_ACCOUNTMANAGER_P_H 3 | 4 | #include 5 | 6 | #include "qtdatasync_global.h" 7 | #include "exchangeengine_p.h" 8 | 9 | #include "rep_accountmanager_p_source.h" 10 | 11 | namespace QtDataSync { 12 | 13 | //not exported, because base class is not too 14 | class AccountManagerPrivate : public AccountManagerPrivateSource 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit AccountManagerPrivate(ExchangeEngine *engineParent); 20 | 21 | QString setupName() const override; 22 | QString deviceName() const override; 23 | QByteArray deviceFingerprint() const override; 24 | QString lastError() const override; 25 | void setDeviceName(QString deviceName) override; 26 | 27 | void importAccountInternal(const JsonObject &importData, bool keepData); 28 | void importAccountTrustedInternal(const JsonObject &importData, const QString &password, bool keepData); 29 | 30 | public Q_SLOTS: 31 | void listDevices() override; 32 | void removeDevice(QUuid deviceId) override; 33 | void updateExchangeKey() override; 34 | void resetAccount(bool keepData) override; 35 | void changeRemote(const RemoteConfig &config, bool keepData) override; 36 | void exportAccount(QUuid id, bool includeServer) override; 37 | void exportAccountTrusted(QUuid id, bool includeServer, const QString &password) override; 38 | void importAccount(const JsonObject &importData, bool keepData) override; 39 | void importAccountTrusted(const JsonObject &importData, const QString &password, bool keepData) override; 40 | void replyToLogin(QUuid deviceId, bool accept) override; 41 | 42 | private Q_SLOTS: 43 | void requestLogin(const DeviceInfo &deviceInfo); 44 | 45 | private: 46 | QPointer _engine; 47 | Logger *_logger; 48 | QSet _loginRequests; 49 | 50 | QJsonObject serializeExportData(const ExportData &data) const; 51 | ExportData deserializeExportData(const QJsonObject &importData) const; 52 | }; 53 | 54 | } 55 | 56 | #endif // QTDATASYNC_ACCOUNTMANAGER_P_H 57 | -------------------------------------------------------------------------------- /src/imports/datasync/qqmleventcursor.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLEVENTCURSOR_H 2 | #define QQMLEVENTCURSOR_H 3 | 4 | #include 5 | 6 | #ifdef DOXYGEN_RUN 7 | namespace de::skycoder42::QtDataSync { 8 | 9 | /*! @brief The QML bindings for the static methods of of QtDataSync::EventCursor 10 | * 11 | * @extends QtQml.QtObject 12 | * @since 4.2 13 | * 14 | * @sa QtDataSync::EventCursor 15 | */ 16 | class EventLog 17 | #else 18 | namespace QtDataSync { 19 | 20 | class QQmlEventCursor : public QObject 21 | #endif 22 | { 23 | Q_OBJECT 24 | 25 | public: 26 | //! @private 27 | explicit QQmlEventCursor(QObject *parent = nullptr); 28 | 29 | //! @copydoc QtDataSync::EventCursor::first(QObject*) 30 | Q_INVOKABLE QtDataSync::EventCursor *first(QObject *parent = nullptr); 31 | //! @copydoc QtDataSync::EventCursor::first(const QString &, QObject*) 32 | Q_INVOKABLE QtDataSync::EventCursor *first(const QString &setupName, QObject *parent = nullptr); 33 | //! @copydoc QtDataSync::EventCursor::last(QObject*) 34 | Q_INVOKABLE QtDataSync::EventCursor *last(QObject *parent = nullptr); 35 | //! @copydoc QtDataSync::EventCursor::last(const QString &, QObject*) 36 | Q_INVOKABLE QtDataSync::EventCursor *last(const QString &setupName, QObject *parent = nullptr); 37 | //! @copydoc QtDataSync::EventCursor::create(quint64, QObject*) 38 | Q_INVOKABLE QtDataSync::EventCursor *create(quint64 index, QObject *parent = nullptr); 39 | //! @copydoc QtDataSync::EventCursor::create(quint64, const QString &, QObject*) 40 | Q_INVOKABLE QtDataSync::EventCursor *create(quint64 index, const QString &setupName, QObject *parent = nullptr); 41 | //! @copydoc QtDataSync::EventCursor::load(const QByteArray &, QObject*) 42 | Q_INVOKABLE QtDataSync::EventCursor *load(const QByteArray &data, QObject *parent = nullptr); 43 | //! @copydoc QtDataSync::EventCursor::load(const QByteArray &, const QString &, QObject*) 44 | Q_INVOKABLE QtDataSync::EventCursor *load(const QByteArray &data, const QString &setupName, QObject *parent = nullptr); 45 | }; 46 | 47 | } 48 | 49 | #endif // QQMLEVENTCURSOR_H 50 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testlib.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTLIB_H 2 | #define TESTLIB_H 3 | 4 | #include 5 | #include 6 | #include "testdata.h" 7 | 8 | #ifndef KEYSTORE_PATH 9 | #define KEYSTORE_PATH "" 10 | #endif 11 | 12 | class TestLib 13 | { 14 | public: 15 | typedef QHash DataSet; 16 | static const QByteArray TypeName; 17 | 18 | static void init(const QByteArray &keystorePath = KEYSTORE_PATH); 19 | static QtDataSync::Setup &setup(QtDataSync::Setup &setup); 20 | 21 | static QtDataSync::ObjectKey generateKey(int index); 22 | static TestData generateData(int index); 23 | static QList generateData(int from, int to); 24 | static QString generateDataKey(int index); 25 | static QStringList generateDataKeys(int from, int to); 26 | static QJsonObject generateDataJson(int index, const QString &specialText = {}); 27 | static DataSet generateDataJson(int from, int to); 28 | static QJsonArray dataListJson(const DataSet &data); 29 | 30 | static QTemporaryDir tDir; 31 | }; 32 | 33 | namespace Tst { 34 | 35 | template 36 | bool compareUnordered(const QList &actual, QList expected, QByteArray aName, QByteArray eName, const char *file, int line) { 37 | if(actual.size() != expected.size()) { 38 | QTest::qFail(aName + " and " + eName + 39 | " differ in size (" + 40 | QByteArray::number(actual.size()) + " vs. " + 41 | QByteArray::number(expected.size()) + ")", 42 | file, 43 | line); 44 | return false; 45 | } 46 | 47 | auto i = 0; 48 | for(auto a : actual) { 49 | if(!expected.removeOne(a)) { 50 | QTest::qFail("Data of " + aName + 51 | " at index" + QByteArray::number(i) + 52 | " is not contained in " + eName, 53 | file, 54 | line); 55 | return false; 56 | } 57 | } 58 | 59 | return true; 60 | } 61 | 62 | } 63 | 64 | #define QCOMPAREUNORDERED(actual, expected) \ 65 | do {\ 66 | if (!Tst::compareUnordered(actual, expected, #actual, #expected, __FILE__, __LINE__))\ 67 | return;\ 68 | } while (false) 69 | 70 | #endif // TESTLIB_H 71 | -------------------------------------------------------------------------------- /src/messages/registermessage_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QTDATASYNC_REGISTERMESSAGE_H 2 | #define QTDATASYNC_REGISTERMESSAGE_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | #include "message_p.h" 9 | #include "asymmetriccrypto_p.h" 10 | #include "identifymessage_p.h" 11 | 12 | namespace QtDataSync { 13 | 14 | class Q_DATASYNC_EXPORT RegisterBaseMessage : public InitMessage 15 | { 16 | Q_GADGET 17 | 18 | Q_PROPERTY(QByteArray signAlgorithm MEMBER signAlgorithm) 19 | Q_PROPERTY(QByteArray signKey MEMBER signKey) 20 | Q_PROPERTY(QByteArray cryptAlgorithm MEMBER cryptAlgorithm) 21 | Q_PROPERTY(QByteArray cryptKey MEMBER cryptKey) 22 | Q_PROPERTY(QtDataSync::Utf8String deviceName MEMBER deviceName) 23 | 24 | public: 25 | RegisterBaseMessage(); 26 | RegisterBaseMessage(QString deviceName, 27 | QByteArray nonce, 28 | const QSharedPointer &signKey, 29 | const QSharedPointer &cryptKey, 30 | AsymmetricCrypto *crypto); 31 | 32 | QByteArray signAlgorithm; 33 | QByteArray signKey; 34 | QByteArray cryptAlgorithm; 35 | QByteArray cryptKey; 36 | Utf8String deviceName; 37 | 38 | AsymmetricCryptoInfo *createCryptoInfo(CryptoPP::RandomNumberGenerator &rng, QObject *parent = nullptr) const; 39 | 40 | protected: 41 | const QMetaObject *getMetaObject() const override; 42 | }; 43 | 44 | class Q_DATASYNC_EXPORT RegisterMessage : public RegisterBaseMessage 45 | { 46 | Q_GADGET 47 | 48 | Q_PROPERTY(QByteArray cmac MEMBER cmac) 49 | 50 | public: 51 | RegisterMessage(); 52 | RegisterMessage(QString deviceName, 53 | QByteArray nonce, 54 | const QSharedPointer &signKey, 55 | const QSharedPointer &cryptKey, 56 | AsymmetricCrypto *crypto, 57 | QByteArray cmac); 58 | 59 | QByteArray cmac; 60 | 61 | protected: 62 | const QMetaObject *getMetaObject() const override; 63 | }; 64 | 65 | } 66 | 67 | Q_DECLARE_METATYPE(QtDataSync::RegisterBaseMessage) 68 | Q_DECLARE_METATYPE(QtDataSync::RegisterMessage) 69 | 70 | #endif // QTDATASYNC_REGISTERMESSAGE_H 71 | -------------------------------------------------------------------------------- /modeling/exchange.txt: -------------------------------------------------------------------------------- 1 | Semantics: 2 | *1: local 3 | *2: remote 4 | 5 | Environment: 6 | action{[exists,noexists,cachedDelete]<->[changed,deleted]} 7 | policy{[changed,deleted]} 8 | persistent{} 9 | 10 | Parameters: 11 | version{v*} 12 | chksum{c*} (on demand) 13 | data{d*} (on demand) 14 | 15 | action(exists<->deleted): 16 | switch(v1, v2): 17 | case v1 < v2: 18 | choose v2 19 | if not persistent: 20 | changed #changed again, because the other side does not know delete was choosen 21 | done 22 | case v1 > v2: 23 | choose v1 24 | done 25 | case v1 == v2: 26 | policy(changed): 27 | choose v1 + 1 28 | policy(deleted): 29 | choose v2 + 1 30 | changed 31 | done 32 | 33 | action(exists<->changed): 34 | switch(v1,c1; v2,c2): 35 | case v1 < v2: 36 | choose v2 37 | done 38 | case v1 > v2: 39 | choose v1 40 | done 41 | case v1 == v2; c1 == c2: 42 | unchanged 43 | done 44 | case v1 == v2; c1 != c2: 45 | if : 46 | choose result 47 | else if c1 < c2: 48 | choose v2 + 1 49 | else if c1 > c2: 50 | choose v1 + 1 51 | changed 52 | done 53 | 54 | action(cachedDelete<->deleted): 55 | if v1 <= v2: 56 | if persistent: 57 | choose v2 58 | else 59 | unchanged 60 | done 61 | 62 | action(cachedDelete<->changed): #special, happens only when deleted, but change not yet pushed, or when persistent is true 63 | switch(v1, v2): 64 | case v1 < v2: 65 | choose v2 66 | done 67 | case v1 > v2: 68 | choose v1 69 | done 70 | default: 71 | policy(changed): 72 | choose v2 + 1 73 | changed 74 | done 75 | policy(deleted): 76 | choose v1 + 1 77 | changed 78 | done 79 | 80 | action(noexists<->deleted): 81 | if persistent: 82 | choose v2 83 | done 84 | 85 | action(noexists<->changed): 86 | choose v2 87 | done 88 | # !!! no information is given whether locally was just deleted or never existed or was deleted long ago. 89 | # But this is addressed by the other side, if delete is prefered, they will resend a higher versioned delete change (Lines 19/20) 90 | 91 | 92 | -------------------------------------------------------------------------------- /doc/logger.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | @class QtDataSync::Logger 3 | 4 | @note Do not use this class and it's methods directly. Instead, make use of the macros defined in the header 5 | 6 | The macros behave just like their `qDebug` equivalents. The macros are: 7 | 8 | - #logDebug 9 | - #logInfo 10 | - #logWarning 11 | - #logCritical 12 | - #logFatal (special case, read the Logger::reportFatalError documentation) 13 | 14 | To use this macros, you must define the `QTDATASYNC_LOG` macro to a pointer to a logger instance. The 15 | recommended way is do this is to define the macro in your sourcefile to the logger member: 16 | 17 | @code{.cpp} 18 | #include 19 | 20 | #define QTDATASYNC_LOG this->logger 21 | 22 | //... 23 | 24 | void MyClass::initialize(Defaults *defaults) 25 | { 26 | this->logger = defaults->createLogger("myclass", this); 27 | 28 | //... 29 | 30 | logDebug() << "It is working"; 31 | } 32 | @endcode 33 | 34 | @sa Defaults::createLogger 35 | */ 36 | 37 | /*! 38 | @fn QtDataSync::Logger::loggingCategory 39 | 40 | @returns The logging category (constant reference) 41 | 42 | The category will have the format `qtdatasync..`, with both 43 | beeing the the constructor parameters. When using Defaults::createLogger, the setup 44 | name is taken from the defaults. 45 | 46 | @sa #logDebug, #logInfo, #logWarning, #logCritical, #logFatal 47 | */ 48 | 49 | /*! 50 | @fn QtDataSync::Logger::reportFatalError(const QString &, const char *, int, const char *) 51 | 52 | @param error A string describing what went wrong 53 | @param file The file where the error happend 54 | @param line The line in the file where the error happend 55 | @param function The function in where the error happend 56 | @returns This method does not return! 57 | 58 | When using #logFatal, this method is used to report the error. It is first printed 59 | out, using #logCritical, and then the Setup::fatalErrorHandler is called to react to the 60 | error. The default error handler implementation will abort the application using std::abort 61 | 62 | A custom handler can be set via the Setup 63 | 64 | @sa Setup::fatalErrorHandler, #logFatal 65 | */ 66 | -------------------------------------------------------------------------------- /src/messages/identifymessage.cpp: -------------------------------------------------------------------------------- 1 | #include "identifymessage_p.h" 2 | 3 | using namespace QtDataSync; 4 | #if CRYPTOPP_VERSION >= 600 5 | using byte = CryptoPP::byte; 6 | #endif 7 | 8 | const QVersionNumber InitMessage::CurrentVersion(1); //NOTE update accordingly 9 | const QVersionNumber InitMessage::CompatVersion(1); 10 | 11 | InitMessage::InitMessage() = default; 12 | 13 | InitMessage::InitMessage(QByteArray nonce) : 14 | nonce{std::move(nonce)} 15 | {} 16 | 17 | const QMetaObject *InitMessage::getMetaObject() const 18 | { 19 | return &staticMetaObject; 20 | } 21 | 22 | bool InitMessage::validate() 23 | { 24 | if(protocolVersion < InitMessage::CompatVersion) 25 | throw IncompatibleVersionException(protocolVersion); 26 | return nonce.size() >= InitMessage::NonceSize; 27 | } 28 | 29 | 30 | 31 | IdentifyMessage::IdentifyMessage(quint32 uploadLimit) : 32 | InitMessage{}, 33 | uploadLimit{uploadLimit} 34 | {} 35 | 36 | IdentifyMessage IdentifyMessage::createRandom(quint32 uploadLimit, CryptoPP::RandomNumberGenerator &rng) 37 | { 38 | IdentifyMessage msg(uploadLimit); 39 | msg.nonce.resize(NonceSize); 40 | rng.GenerateBlock(reinterpret_cast(msg.nonce.data()), 41 | static_cast(msg.nonce.size())); 42 | return msg; 43 | } 44 | 45 | const QMetaObject *IdentifyMessage::getMetaObject() const 46 | { 47 | return &staticMetaObject; 48 | } 49 | 50 | 51 | 52 | IncompatibleVersionException::IncompatibleVersionException(QVersionNumber invalidVersion) : 53 | _version(std::move(invalidVersion)), 54 | _msg(QStringLiteral("Incompatible protocol versions. Must be at least %1, but remote proposed with %2") 55 | .arg(InitMessage::CompatVersion.toString(), _version.toString()) 56 | .toUtf8()) 57 | {} 58 | 59 | QVersionNumber IncompatibleVersionException::invalidVersion() const 60 | { 61 | return _version; 62 | } 63 | 64 | const char *IncompatibleVersionException::what() const noexcept 65 | { 66 | return _msg.constData(); 67 | } 68 | 69 | void IncompatibleVersionException::raise() const 70 | { 71 | throw (*this); 72 | } 73 | 74 | QException *IncompatibleVersionException::clone() const 75 | { 76 | return new IncompatibleVersionException(_version); 77 | } 78 | -------------------------------------------------------------------------------- /src/datasync/exception.cpp: -------------------------------------------------------------------------------- 1 | #include "exception.h" 2 | #include "defaults.h" 3 | using namespace QtDataSync; 4 | 5 | Exception::Exception(const QString &setupName, const QString &message) : 6 | QException{}, 7 | _setupName{setupName}, 8 | _message{message} 9 | {} 10 | 11 | Exception::Exception(const Defaults &defaults, const QString &message) : 12 | Exception{defaults.setupName(), message} 13 | {} 14 | 15 | Exception::Exception(const Exception * const other) : //MAJOR use normal copy ctr instead 16 | QException{}, 17 | _setupName{other->_setupName}, 18 | _message{other->_message} 19 | {} 20 | 21 | QByteArray Exception::className() const noexcept 22 | { 23 | return QTDATASYNC_EXCEPTION_NAME(Exception); 24 | } 25 | 26 | QString Exception::setupName() const 27 | { 28 | return _setupName; 29 | } 30 | 31 | QString Exception::message() const 32 | { 33 | return _message; 34 | } 35 | 36 | QString Exception::qWhat() const 37 | { 38 | return QStringLiteral("Message: %1" 39 | "\n\tException-Type: %2" 40 | "\n\tSetup: %3") 41 | .arg(_message, QString::fromUtf8(className()), _setupName); 42 | } 43 | 44 | const char *Exception::what() const noexcept 45 | { 46 | if(_qWhat.isEmpty()) 47 | _qWhat = qWhat().toUtf8(); 48 | return _qWhat.constData(); 49 | } 50 | 51 | void Exception::raise() const 52 | { 53 | throw (*this); 54 | } 55 | 56 | QException *Exception::clone() const 57 | { 58 | return new Exception(this); 59 | } 60 | 61 | 62 | 63 | SetupDoesNotExistException::SetupDoesNotExistException(const QString &setupName) : 64 | Exception{setupName, QStringLiteral("The requested setup does not exist! Create it with Setup::create")} 65 | {} 66 | 67 | SetupDoesNotExistException::SetupDoesNotExistException(const SetupDoesNotExistException * const other) : 68 | Exception{other} 69 | {} 70 | 71 | QByteArray SetupDoesNotExistException::className() const noexcept 72 | { 73 | return QTDATASYNC_EXCEPTION_NAME(SetupDoesNotExistException); 74 | } 75 | 76 | void SetupDoesNotExistException::raise() const 77 | { 78 | throw (*this); 79 | } 80 | 81 | QException *SetupDoesNotExistException::clone() const 82 | { 83 | return new SetupDoesNotExistException(this); 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/imports/datasync/qqmleventcursor.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmleventcursor.h" 2 | #include 3 | using namespace QtDataSync; 4 | 5 | QQmlEventCursor::QQmlEventCursor(QObject *parent) : 6 | QObject{parent} 7 | {} 8 | 9 | EventCursor *QQmlEventCursor::first(QObject *parent) 10 | { 11 | try { 12 | return EventCursor::first(parent); 13 | } catch(Exception &e) { 14 | qmlWarning(this) << e.what(); 15 | return nullptr; 16 | } 17 | } 18 | 19 | EventCursor *QQmlEventCursor::first(const QString &setupName, QObject *parent) 20 | { 21 | try { 22 | return EventCursor::first(setupName, parent); 23 | } catch(Exception &e) { 24 | qmlWarning(this) << e.what(); 25 | return nullptr; 26 | } 27 | } 28 | 29 | EventCursor *QQmlEventCursor::last(QObject *parent) 30 | { 31 | try { 32 | return EventCursor::last(parent); 33 | } catch(Exception &e) { 34 | qmlWarning(this) << e.what(); 35 | return nullptr; 36 | } 37 | } 38 | 39 | EventCursor *QQmlEventCursor::last(const QString &setupName, QObject *parent) 40 | { 41 | try { 42 | return EventCursor::last(setupName, parent); 43 | } catch(Exception &e) { 44 | qmlWarning(this) << e.what(); 45 | return nullptr; 46 | } 47 | } 48 | 49 | EventCursor *QQmlEventCursor::create(quint64 index, QObject *parent) 50 | { 51 | try { 52 | return EventCursor::create(index, parent); 53 | } catch(Exception &e) { 54 | qmlWarning(this) << e.what(); 55 | return nullptr; 56 | } 57 | } 58 | 59 | EventCursor *QQmlEventCursor::create(quint64 index, const QString &setupName, QObject *parent) 60 | { 61 | try { 62 | return EventCursor::create(index, setupName, parent); 63 | } catch(Exception &e) { 64 | qmlWarning(this) << e.what(); 65 | return nullptr; 66 | } 67 | } 68 | 69 | EventCursor *QQmlEventCursor::load(const QByteArray &data, QObject *parent) 70 | { 71 | try { 72 | return EventCursor::load(data, parent); 73 | } catch(Exception &e) { 74 | qmlWarning(this) << e.what(); 75 | return nullptr; 76 | } 77 | } 78 | 79 | EventCursor *QQmlEventCursor::load(const QByteArray &data, const QString &setupName, QObject *parent) 80 | { 81 | try { 82 | return EventCursor::load(data, setupName, parent); 83 | } catch(Exception &e) { 84 | qmlWarning(this) << e.what(); 85 | return nullptr; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/imports/datasync/qqmldatastoremodel.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmldatastoremodel.h" 2 | #include 3 | using namespace QtDataSync; 4 | 5 | QQmlDataStoreModel::QQmlDataStoreModel(QObject *parent) : 6 | DataStoreModel(parent, nullptr), 7 | _setupName(DefaultSetup), 8 | _dataStore(nullptr) 9 | { 10 | connect(this, &QQmlDataStoreModel::modelReset, 11 | this, [this]() { 12 | emit typeNameChanged(typeName()); 13 | }); 14 | } 15 | 16 | void QQmlDataStoreModel::classBegin() {} 17 | 18 | void QQmlDataStoreModel::componentComplete() 19 | { 20 | if(!_dataStore) { 21 | _dataStore = new QQmlDataStore(this); 22 | _dataStore->classBegin(); 23 | _dataStore->setSetupName(_setupName); 24 | _dataStore->componentComplete(); 25 | emit dataStoreChanged(_dataStore); 26 | } 27 | connect(_dataStore, &QQmlDataStore::validChanged, 28 | this, &QQmlDataStoreModel::validChanged); 29 | initStore(_dataStore); 30 | 31 | if(_dataStore->valid()) 32 | emit validChanged(true); 33 | } 34 | 35 | QString QQmlDataStoreModel::setupName() const 36 | { 37 | return _setupName; 38 | } 39 | 40 | QQmlDataStore *QQmlDataStoreModel::dataStore() const 41 | { 42 | return _dataStore; 43 | } 44 | 45 | bool QQmlDataStoreModel::valid() const 46 | { 47 | return _dataStore && _dataStore->valid(); 48 | } 49 | 50 | QString QQmlDataStoreModel::typeName() const 51 | { 52 | return QString::fromUtf8(QMetaType::typeName(typeId())); 53 | } 54 | 55 | void QQmlDataStoreModel::setSetupName(QString setupName) 56 | { 57 | if(valid()) { 58 | qmlWarning(this) << "Cannot change setupName property after initialization"; 59 | return; 60 | } 61 | 62 | if (_setupName == setupName) 63 | return; 64 | 65 | _setupName = std::move(setupName); 66 | emit setupNameChanged(_setupName); 67 | } 68 | 69 | void QQmlDataStoreModel::setDataStore(QQmlDataStore *dataStore) 70 | { 71 | if(valid()) { 72 | qmlWarning(this) << "Cannot change dataStore property after initialization"; 73 | return; 74 | } 75 | 76 | if (_dataStore == dataStore) 77 | return; 78 | 79 | _dataStore = dataStore; 80 | emit dataStoreChanged(_dataStore); 81 | } 82 | 83 | void QQmlDataStoreModel::setTypeName(const QString &typeName) 84 | { 85 | try { 86 | setTypeId(QMetaType::type(typeName.toUtf8())); 87 | } catch(Exception &e) { 88 | qmlWarning(this) << e.what(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/datasync/changeemitter.cpp: -------------------------------------------------------------------------------- 1 | #include "changeemitter_p.h" 2 | using namespace QtDataSync; 3 | 4 | ChangeEmitter::ChangeEmitter(const Defaults &defaults, QObject *parent) : 5 | ChangeEmitterSource{parent}, 6 | _cache{defaults.cacheHandle().value>()} 7 | {} 8 | 9 | void ChangeEmitter::triggerChange(QObject *origin, const ObjectKey &key, bool deleted, bool changed) 10 | { 11 | if(changed) 12 | emit uploadNeeded(); 13 | emit dataChanged(origin, key, deleted); 14 | emit remoteDataChanged(key, deleted); 15 | } 16 | 17 | void ChangeEmitter::triggerClear(QObject *origin, const QByteArray &typeName, const QStringList &ids) 18 | { 19 | emit uploadNeeded(); 20 | for(const auto &id : ids) { 21 | emit dataChanged(origin, {typeName, id}, true); 22 | emit remoteDataChanged({typeName, id}, true); 23 | } 24 | } 25 | 26 | void ChangeEmitter::triggerReset(QObject *origin) 27 | { 28 | emit uploadNeeded(); 29 | emit dataResetted(origin); 30 | emit remoteDataResetted(); 31 | } 32 | 33 | void ChangeEmitter::triggerUpload() 34 | { 35 | emit uploadNeeded(); 36 | } 37 | 38 | void ChangeEmitter::triggerRemoteChange(const ObjectKey &key, bool deleted, bool changed) 39 | { 40 | if(_cache) { 41 | auto contains = false; 42 | //check if cached 43 | { 44 | QReadLocker _(&_cache->lock); 45 | contains = _cache->cache.contains(key); 46 | } 47 | //if chached, remove 48 | if(contains) { 49 | QWriteLocker _(&_cache->lock); 50 | _cache->cache.remove(key); 51 | } 52 | } 53 | if(changed) 54 | emit uploadNeeded(); 55 | emit dataChanged(nullptr, key, deleted); 56 | emit remoteDataChanged(key, deleted); 57 | } 58 | 59 | void ChangeEmitter::triggerRemoteClear(const QByteArray &typeName, const QStringList &ids) 60 | { 61 | if(_cache) { 62 | QWriteLocker _(&_cache->lock); 63 | for(const auto &id : ids) 64 | _cache->cache.remove({typeName, id}); 65 | } 66 | emit uploadNeeded(); 67 | for(const auto &id : ids) { 68 | emit dataChanged(nullptr, {typeName, id}, true); 69 | emit remoteDataChanged({typeName, id}, true); 70 | } 71 | } 72 | 73 | void ChangeEmitter::triggerRemoteReset() 74 | { 75 | if(_cache) { 76 | QWriteLocker _(&_cache->lock); 77 | _cache->cache.clear(); 78 | } 79 | emit uploadNeeded(); 80 | emit dataResetted(nullptr); 81 | emit remoteDataResetted(); 82 | } 83 | -------------------------------------------------------------------------------- /tests/auto/datasync/TestLib/testlib.cpp: -------------------------------------------------------------------------------- 1 | #include "testlib.h" 2 | using namespace QtDataSync; 3 | 4 | const QByteArray TestLib::TypeName("TestData"); 5 | QTemporaryDir TestLib::tDir; 6 | 7 | void TestLib::init(const QByteArray &keystorePath) 8 | { 9 | qputenv("PLUGIN_KEYSTORES_PATH", keystorePath); 10 | qRegisterMetaType(); 11 | QJsonSerializer::registerListConverters(); 12 | Setup::setCleanupTimeout(10000); 13 | #ifdef VERBOSE_TESTS 14 | QLoggingCategory::setFilterRules(QStringLiteral("qtdatasync.*.debug=true")); 15 | #endif 16 | } 17 | 18 | Setup &TestLib::setup(Setup &setup) 19 | { 20 | tDir.setAutoRemove(false); 21 | qInfo() << "storage path:" << tDir.path(); 22 | return setup.setLocalDir(tDir.path()) 23 | .setKeyStoreProvider(QStringLiteral("plain")) 24 | .setSignatureScheme(Setup::RSA_PSS_SHA3_512) 25 | .setSignatureKeyParam(2048) 26 | .setEncryptionScheme(Setup::RSA_OAEP_SHA3_512) 27 | .setEncryptionKeyParam(2048); 28 | } 29 | 30 | ObjectKey TestLib::generateKey(int index) 31 | { 32 | return {TypeName, QString::number(index)}; 33 | } 34 | 35 | TestData TestLib::generateData(int index) 36 | { 37 | return {index, QString::number(index)}; 38 | } 39 | 40 | QList TestLib::generateData(int from, int to) 41 | { 42 | QList list; 43 | for(auto i = from; i <= to; i++) 44 | list.append({i, QString::number(i)}); 45 | return list; 46 | } 47 | 48 | QString TestLib::generateDataKey(int index) 49 | { 50 | return QString::number(index); 51 | } 52 | 53 | QStringList TestLib::generateDataKeys(int from, int to) 54 | { 55 | QStringList list; 56 | for(auto i = from; i <= to; i++) 57 | list.append(generateDataKey(i)); 58 | return list; 59 | } 60 | 61 | QJsonObject TestLib::generateDataJson(int index, const QString &specialText) 62 | { 63 | QJsonObject data; 64 | data[QStringLiteral("id")] = index; 65 | data[QStringLiteral("text")] = specialText.isNull() ? QString::number(index) : specialText; 66 | return data; 67 | } 68 | 69 | TestLib::DataSet TestLib::generateDataJson(int from, int to) 70 | { 71 | DataSet hash; 72 | for(auto i = from; i <= to; i++) 73 | hash.insert(generateKey(i), generateDataJson(i)); 74 | return hash; 75 | } 76 | 77 | QJsonArray TestLib::dataListJson(const TestLib::DataSet &data) 78 | { 79 | QJsonArray v; 80 | for(auto d : data) 81 | v.append(d); 82 | return v; 83 | } 84 | -------------------------------------------------------------------------------- /src/datasync/controller.cpp: -------------------------------------------------------------------------------- 1 | #include "controller_p.h" 2 | 3 | using namespace QtDataSync; 4 | using namespace std::chrono; 5 | 6 | #if QT_HAS_INCLUDE() 7 | #define scdtime(x) x 8 | #else 9 | #define scdtime(x) duration_cast(x).count() 10 | #endif 11 | 12 | #define QTDATASYNC_LOG _logger 13 | 14 | QtDataSync::Controller::Controller(const QByteArray &name, Defaults defaults, QObject *parent) : 15 | QObject{parent}, 16 | _defaults{std::move(defaults)}, 17 | _logger{_defaults.createLogger(name, this)}, 18 | _settings{_defaults.createSettings(this, QString::fromUtf8(name))}, 19 | _opTimer{new QTimer(this)} 20 | { 21 | connect(_opTimer, &QTimer::timeout, 22 | this, &Controller::onTimeout); 23 | _opTimer->setSingleShot(true); 24 | _opTimer->setTimerType(Qt::VeryCoarseTimer); 25 | } 26 | 27 | void Controller::initialize(const QVariantHash ¶ms) 28 | { 29 | Q_UNUSED(params) 30 | } 31 | 32 | void Controller::finalize() {} 33 | 34 | Defaults Controller::defaults() const 35 | { 36 | return _defaults; 37 | } 38 | 39 | Logger *Controller::logger() const 40 | { 41 | return _logger; 42 | } 43 | 44 | QSettings *Controller::settings() const 45 | { 46 | return _settings; 47 | } 48 | 49 | void Controller::beginOp(minutes interval, bool startIfNotRunning) 50 | { 51 | if(!startIfNotRunning && !_opTimer->isActive()) 52 | return; 53 | 54 | #if QT_HAS_INCLUDE() 55 | if(_opTimer->remainingTimeAsDuration() < interval) 56 | _opTimer->start(interval); 57 | #else 58 | if(_opTimer->remainingTime() < scdtime(interval)) 59 | _opTimer->start(scdtime(interval)); 60 | #endif 61 | logDebug() << "Started or refreshed operation timeout"; 62 | } 63 | 64 | void Controller::beginSpecialOp(minutes interval) 65 | { 66 | #if QT_HAS_INCLUDE() 67 | if(interval < _specialOp.remainingTimeAsDuration()) 68 | #else 69 | if(scdtime(interval) < _specialOp.remainingTime()) 70 | #endif 71 | _specialOp.setRemainingTime(scdtime(interval)); 72 | beginOp(interval); 73 | } 74 | 75 | void Controller::endOp() 76 | { 77 | _opTimer->stop(); 78 | _specialOp.setDeadline(QDeadlineTimer::Forever); 79 | logDebug() << "Cleared operation timeout"; 80 | } 81 | 82 | void Controller::onTimeout() 83 | { 84 | if(_specialOp.hasExpired()) { 85 | _specialOp.setDeadline(QDeadlineTimer::Forever); 86 | emit specialOperationTimeout(); 87 | } else 88 | emit operationTimeout(); 89 | } 90 | --------------------------------------------------------------------------------