~aleteoryx/muditaos

d6a63be1fe4588f0b535cd26f8bb0567f1755f89 — Pawel Olejniczak 3 years ago 150f1cf
[CP-1484] Add new mechanism for data synchronization between MOS and MC

This mechanism is similar to the current backup implementation,
but is stripped of irrelevant data that is not required by the
MC to perform data synchronization.
M module-services/service-db/DBServiceAPI.cpp => module-services/service-db/DBServiceAPI.cpp +14 -0
@@ 295,6 295,20 @@ auto DBServiceAPI::DBBackup(sys::Service *serv, std::string backupPath) -> bool
    return false;
}

auto DBServiceAPI::DBPrepareSyncPackage(sys::Service *serv, const std::string &syncPackagePath) -> bool
{
    LOG_INFO("DBPrepareSyncPackage %s", syncPackagePath.c_str());

    auto msg = std::make_shared<DBServiceMessageSyncPackage>(MessageType::DBSyncPackage, syncPackagePath);

    auto ret = serv->bus.sendUnicastSync(std::move(msg), service::name::db, DefaultTimeoutInMs);
    if (auto retMsg = dynamic_cast<DBServiceResponseMessage *>(ret.second.get()); retMsg) {
        return retMsg->retCode;
    }
    LOG_ERROR("DBPrepareSyncPackage error, return code: %s", c_str(ret.first));
    return false;
}

bool DBServiceAPI::AddSMS(sys::Service *serv, const SMSRecord &record, std::unique_ptr<db::QueryListener> &&listener)
{
    auto query = std::make_unique<db::query::SMSAdd>(record);

M module-services/service-db/include/service-db/DBServiceAPI.hpp => module-services/service-db/include/service-db/DBServiceAPI.hpp +1 -0
@@ 111,6 111,7 @@ class DBServiceAPI
    [[deprecated]] static auto CalllogUpdate(sys::Service *serv, const CalllogRecord &rec) -> bool;

    static auto DBBackup(sys::Service *serv, std::string backupPath) -> bool;
    static auto DBPrepareSyncPackage(sys::Service *serv, const std::string &syncPackagePath) -> bool;

    static auto IsContactInFavourites(sys::Service *serv, const utils::PhoneNumber::View &numberView) -> bool;
    static auto IsContactInEmergency(sys::Service *serv, const utils::PhoneNumber::View &numberView) -> bool;

M module-services/service-db/include/service-db/DBServiceMessage.hpp => module-services/service-db/include/service-db/DBServiceMessage.hpp +8 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 17,6 17,13 @@ class DBServiceMessageBackup : public DBMessage
    std::string backupPath;
};

class DBServiceMessageSyncPackage : public DBMessage
{
  public:
    DBServiceMessageSyncPackage(MessageType messageType, const std::string &syncPackagePath);
    std::string syncPackagePath;
};

class DBServiceResponseMessage : public DBResponseMessage
{
  public:

M module-services/service-db/messages/DBServiceMessage.cpp => module-services/service-db/messages/DBServiceMessage.cpp +5 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-db/DBServiceMessage.hpp>


@@ 7,5 7,9 @@ DBServiceMessageBackup::DBServiceMessageBackup(MessageType messageType, std::str
    : DBMessage(messageType), backupPath(backupPath)
{}

DBServiceMessageSyncPackage::DBServiceMessageSyncPackage(MessageType messageType, const std::string &syncPackagePath)
    : DBMessage(messageType), syncPackagePath(syncPackagePath)
{}

DBServiceResponseMessage::DBServiceResponseMessage(uint32_t retCode, uint32_t count, MessageType respTo)
    : DBResponseMessage(retCode, count, respTo){};

M module-services/service-desktop/BackupRestore.cpp => module-services/service-desktop/BackupRestore.cpp +224 -35
@@ 40,43 40,75 @@ static bool isValidDirentry(const std::filesystem::directory_entry &direntry)
    return direntry.path() != "." && direntry.path() != ".." && direntry.path() != "...";
}

BackupRestore::CompletionCode BackupRestore::BackupUserFiles(sys::Service *ownerService, std::filesystem::path &path)
BackupSyncRestore::CompletionCode BackupSyncRestore::BackupUserFiles(sys::Service *ownerService,
                                                                     std::filesystem::path &path)
{
    assert(ownerService != nullptr);
    LOG_INFO("Backup started...");

    if (BackupRestore::RemoveBackupDir(path) == false) {
    if (BackupSyncRestore::RemoveBackupDir(path) == false) {
        return CompletionCode::FSError;
    }

    if (BackupRestore::CreateBackupDir(path) == false) {
    if (BackupSyncRestore::CreateBackupDir(path) == false) {
        return CompletionCode::FSError;
    }

    LOG_DEBUG("Database backup started...");
    if (DBServiceAPI::DBBackup(ownerService, path) == false) {
        LOG_ERROR("Database backup failed, quitting...");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveBackupDir(path);
        return CompletionCode::DBError;
    }

    if (WriteBackupInfo(ownerService, path) == false) {
        LOG_ERROR("Failed to save backup info");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveBackupDir(path);
        return CompletionCode::CopyError;
    }

    LOG_DEBUG("Packing files");
    if (BackupRestore::PackUserFiles(path) == false) {
    if (BackupSyncRestore::PackUserFiles(path) == false) {
        LOG_ERROR("Failed pack backup");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveBackupDir(path);
        return CompletionCode::PackError;
    }

    return CompletionCode::Success;
}

bool BackupRestore::WriteBackupInfo(sys::Service *ownerService, const std::filesystem::path &path)
BackupSyncRestore::CompletionCode BackupSyncRestore::PrepareSyncPackage(sys::Service *ownerService,
                                                                        std::filesystem::path &path)
{
    assert(ownerService != nullptr);
    LOG_INFO("Sync package preparation started...");

    if (!BackupSyncRestore::RemoveSyncDir(path)) {
        return CompletionCode::FSError;
    }

    if (!BackupSyncRestore::CreateSyncDir(path)) {
        return CompletionCode::FSError;
    }

    LOG_DEBUG("Sync package preparation started...");
    if (!DBServiceAPI::DBPrepareSyncPackage(ownerService, path)) {
        LOG_ERROR("Sync package preparation, quitting...");
        BackupSyncRestore::RemoveSyncDir(path);
        return CompletionCode::DBError;
    }

    LOG_DEBUG("Packing files");
    if (!BackupSyncRestore::PackSyncFiles(path)) {
        LOG_ERROR("Failed pack sync files");
        BackupSyncRestore::RemoveSyncDir(path);
        return CompletionCode::PackError;
    }

    return CompletionCode::Success;
}

bool BackupSyncRestore::WriteBackupInfo(sys::Service *ownerService, const std::filesystem::path &path)
{
    LOG_INFO("Writing backup info");



@@ 100,19 132,19 @@ bool BackupRestore::WriteBackupInfo(sys::Service *ownerService, const std::files
    return true;
}

BackupRestore::CompletionCode BackupRestore::RestoreUserFiles(sys::Service *ownerService,
                                                              const std::filesystem::path &path)
BackupSyncRestore::CompletionCode BackupSyncRestore::RestoreUserFiles(sys::Service *ownerService,
                                                                      const std::filesystem::path &path)
{
    assert(ownerService != nullptr);

    LOG_INFO("Restore started");

    if (BackupRestore::UnpackBackupFile(path) == false) {
    if (BackupSyncRestore::UnpackBackupFile(path) == false) {
        LOG_ERROR("Can't unpack user files");
        return CompletionCode::UnpackError;
    }

    if (BackupRestore::CanRestoreFromBackup(TempPathForBackupFile(path)) == false) {
    if (BackupSyncRestore::CanRestoreFromBackup(TempPathForBackupFile(path)) == false) {
        LOG_ERROR("Can't restore user files");
        return CompletionCode::FSError;
    }


@@ 124,7 156,7 @@ BackupRestore::CompletionCode BackupRestore::RestoreUserFiles(sys::Service *owne

    LOG_INFO("Entered restore state");

    if (BackupRestore::ReplaceUserFiles(path) == false) {
    if (BackupSyncRestore::ReplaceUserFiles(path) == false) {
        LOG_ERROR("Can't restore user files");
        return CompletionCode::CopyError;
    }


@@ 132,7 164,7 @@ BackupRestore::CompletionCode BackupRestore::RestoreUserFiles(sys::Service *owne
    return CompletionCode::Success;
}

bool BackupRestore::RemoveBackupDir(const std::filesystem::path &path)
bool BackupSyncRestore::RemoveBackupDir(const std::filesystem::path &path)
{
    /* prepare directories */
    if (std::filesystem::is_directory(path)) {


@@ 148,7 180,23 @@ bool BackupRestore::RemoveBackupDir(const std::filesystem::path &path)
    return true;
}

bool BackupRestore::CreateBackupDir(const std::filesystem::path &path)
bool BackupSyncRestore::RemoveSyncDir(const std::filesystem::path &path)
{
    /* prepare directories */
    if (std::filesystem::is_directory(path)) {
        LOG_INFO("Removing sync directory %s...", path.c_str());
        std::error_code errorCode;

        if (std::filesystem::remove_all(path, errorCode) == 0) {
            LOG_ERROR("Removing sync directory %s failed, error: %d.", path.c_str(), errorCode.value());
            return false;
        }
    }

    return true;
}

bool BackupSyncRestore::CreateBackupDir(const std::filesystem::path &path)
{
    LOG_INFO("Creating backup directory %s...", path.c_str());
    std::error_code errorCode;


@@ 163,11 211,26 @@ bool BackupRestore::CreateBackupDir(const std::filesystem::path &path)
    return true;
}

bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
bool BackupSyncRestore::CreateSyncDir(const std::filesystem::path &path)
{
    LOG_INFO("Creating sync directory %s...", path.c_str());
    std::error_code errorCode;

    if (!std::filesystem::exists(path)) {
        if (!std::filesystem::create_directories(path, errorCode)) {
            LOG_ERROR("Failed to create directory: %s, error: %d", path.c_str(), errorCode.value());
            return false;
        }
    }

    return true;
}

bool BackupSyncRestore::PackUserFiles(const std::filesystem::path &path)
{
    if (std::filesystem::is_empty(path)) {
        LOG_ERROR("Backup dir is empty, nothing to backup, quitting...");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveBackupDir(path);
        return false;
    }



@@ 179,7 242,7 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
    int ret = mtar_open(&tarFile, tarFilePath.c_str(), "w");
    if (ret != MTAR_ESUCCESS) {
        LOG_ERROR("Opening tar file failed, quitting...");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveBackupDir(path);
        return false;
    }



@@ 200,7 263,7 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
        if (file == nullptr) {
            LOG_ERROR("Archiving file failed, cannot open file, quitting...");
            mtar_close(&tarFile);
            BackupRestore::RemoveBackupDir(path);
            BackupSyncRestore::RemoveBackupDir(path);
            return false;
        }



@@ 212,14 275,14 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
            LOG_ERROR("Writing tar header failed");
            std::fclose(file);
            mtar_close(&tarFile);
            BackupRestore::RemoveBackupDir(path);
            BackupSyncRestore::RemoveBackupDir(path);
            return false;
        }

        uintmax_t filesize = std::filesystem::file_size(direntry.path(), errorCode);
        if (errorCode) {
            LOG_ERROR("Failed to get size for file %s, error: %d", direntry.path().c_str(), errorCode.value());
            BackupRestore::RemoveBackupDir(path);
            BackupSyncRestore::RemoveBackupDir(path);
            return false;
        }
        uint32_t loopcount = (filesize / purefs::buffer::tar_buf) + 1u;


@@ 239,7 302,7 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
                LOG_ERROR("Reading file failed, quitting...");
                std::fclose(file);
                mtar_close(&tarFile);
                BackupRestore::RemoveBackupDir(path);
                BackupSyncRestore::RemoveBackupDir(path);
                return false;
            }



@@ 248,7 311,133 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
                LOG_ERROR("Writting into backup failed, quitting...");
                std::fclose(file);
                mtar_close(&tarFile);
                BackupRestore::RemoveBackupDir(path);
                BackupSyncRestore::RemoveBackupDir(path);
                return false;
            }
        }

        LOG_INFO("Closing file...");
        if (std::fclose(file) != 0) {
            LOG_ERROR("Closing file failed, quitting...");
            mtar_close(&tarFile);
            BackupSyncRestore::RemoveBackupDir(path);
            return false;
        }

        LOG_INFO("Deleting file ...");

        if (!std::filesystem::remove(direntry.path(), errorCode)) {
            LOG_ERROR("Deleting file failed, error: %d, quitting...", errorCode.value());
            mtar_close(&tarFile);
            BackupSyncRestore::RemoveBackupDir(path);
            return false;
        }
    }

    LOG_INFO("Finalizing tar file...");
    if (mtar_finalize(&tarFile) != MTAR_ESUCCESS) {
        LOG_ERROR("Finalizing tar file failed, quitting....");
        mtar_close(&tarFile);
        BackupSyncRestore::RemoveBackupDir(path);
        return false;
    }

    LOG_INFO("Closing tar file...");
    if (mtar_close(&tarFile) != MTAR_ESUCCESS) {
        LOG_ERROR("Closing tar file failed, quitting...");
        BackupSyncRestore::RemoveBackupDir(path);
        return false;
    }

    return true;
}

bool BackupSyncRestore::PackSyncFiles(const std::filesystem::path &path)
{
    if (std::filesystem::is_empty(path)) {
        LOG_ERROR("Sync dir is empty, quitting...");
        BackupSyncRestore::RemoveSyncDir(path);
        return false;
    }

    std::filesystem::path tarFilePath = (purefs::dir::getSyncPackagePath() / path.filename());
    mtar_t tarFile;

    LOG_INFO("Opening tar %s file...", tarFilePath.c_str());

    int ret = mtar_open(&tarFile, tarFilePath.c_str(), "w");
    if (ret != MTAR_ESUCCESS) {
        LOG_ERROR("Opening tar file failed, quitting...");
        BackupSyncRestore::RemoveSyncDir(path);
        return false;
    }

    auto buffer                       = std::make_unique<unsigned char[]>(purefs::buffer::tar_buf);
    constexpr size_t streamBufferSize = 64 * 1024;
    auto streamBuffer                 = std::make_unique<char[]>(streamBufferSize);
    setvbuf(tarFile.stream, streamBuffer.get(), _IOFBF, streamBufferSize);
    std::error_code errorCode;

    for (auto &direntry : std::filesystem::directory_iterator(path)) {
        if (!isValidDirentry(direntry)) {
            continue;
        }

        LOG_INFO("Archiving file ...");
        auto *file = std::fopen(direntry.path().string().c_str(), "r");

        if (file == nullptr) {
            LOG_ERROR("Archiving file failed, cannot open file, quitting...");
            mtar_close(&tarFile);
            BackupSyncRestore::RemoveSyncDir(path);
            return false;
        }

        LOG_DEBUG("Writting tar header ...");

        if (mtar_write_file_header(&tarFile,
                                   direntry.path().filename().c_str(),
                                   static_cast<unsigned>(std::filesystem::file_size(direntry))) != MTAR_ESUCCESS) {
            LOG_ERROR("Writing tar header failed");
            std::fclose(file);
            mtar_close(&tarFile);
            BackupSyncRestore::RemoveSyncDir(path);
            return false;
        }

        uintmax_t filesize = std::filesystem::file_size(direntry.path(), errorCode);
        if (errorCode) {
            LOG_ERROR("Failed to get size for file %s, error: %d", direntry.path().c_str(), errorCode.value());
            BackupSyncRestore::RemoveSyncDir(path);
            return false;
        }
        uint32_t loopcount = (filesize / purefs::buffer::tar_buf) + 1u;
        uint32_t readsize;

        for (uint32_t i = 0u; i < loopcount; i++) {
            if (i + 1u == loopcount) {
                readsize = filesize % purefs::buffer::tar_buf;
            }
            else {
                readsize = purefs::buffer::tar_buf;
            }

            LOG_DEBUG("Reading file ...");

            if (std::fread(buffer.get(), 1, readsize, file) != readsize) {
                LOG_ERROR("Reading file failed, quitting...");
                std::fclose(file);
                mtar_close(&tarFile);
                BackupSyncRestore::RemoveSyncDir(path);
                return false;
            }

            LOG_DEBUG("Writting into sync package...");
            if (mtar_write_data(&tarFile, buffer.get(), readsize) != MTAR_ESUCCESS) {
                LOG_ERROR("Writting into sync package failed, quitting...");
                std::fclose(file);
                mtar_close(&tarFile);
                BackupSyncRestore::RemoveSyncDir(path);
                return false;
            }
        }


@@ 257,7 446,7 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
        if (std::fclose(file) != 0) {
            LOG_ERROR("Closing file failed, quitting...");
            mtar_close(&tarFile);
            BackupRestore::RemoveBackupDir(path);
            BackupSyncRestore::RemoveSyncDir(path);
            return false;
        }



@@ 266,7 455,7 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
        if (!std::filesystem::remove(direntry.path(), errorCode)) {
            LOG_ERROR("Deleting file failed, error: %d, quitting...", errorCode.value());
            mtar_close(&tarFile);
            BackupRestore::RemoveBackupDir(path);
            BackupSyncRestore::RemoveSyncDir(path);
            return false;
        }
    }


@@ 275,21 464,21 @@ bool BackupRestore::PackUserFiles(const std::filesystem::path &path)
    if (mtar_finalize(&tarFile) != MTAR_ESUCCESS) {
        LOG_ERROR("Finalizing tar file failed, quitting....");
        mtar_close(&tarFile);
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveSyncDir(path);
        return false;
    }

    LOG_INFO("Closing tar file...");
    if (mtar_close(&tarFile) != MTAR_ESUCCESS) {
        LOG_ERROR("Closing tar file failed, quitting...");
        BackupRestore::RemoveBackupDir(path);
        BackupSyncRestore::RemoveSyncDir(path);
        return false;
    }

    return true;
}

auto BackupRestore::TempPathForBackupFile(const std::filesystem::path &tarFilePath) -> std::filesystem::path const
auto BackupSyncRestore::TempPathForBackupFile(const std::filesystem::path &tarFilePath) -> std::filesystem::path const
{
    std::filesystem::path extractFolder;



@@ 303,7 492,7 @@ auto BackupRestore::TempPathForBackupFile(const std::filesystem::path &tarFilePa
    return purefs::dir::getTemporaryPath() / extractFolder;
}

bool BackupRestore::UnpackBackupFile(const std::filesystem::path &tarFilePath)
bool BackupSyncRestore::UnpackBackupFile(const std::filesystem::path &tarFilePath)
{
    mtar_t tarFile;
    mtar_header_t tarHeader;


@@ 402,7 591,7 @@ bool BackupRestore::UnpackBackupFile(const std::filesystem::path &tarFilePath)
    return ret == MTAR_ENULLRECORD ? true : false;
}

std::string BackupRestore::ReadFileAsString(const std::filesystem::path &fileToRead)
std::string BackupSyncRestore::ReadFileAsString(const std::filesystem::path &fileToRead)
{
    const auto file = std::ifstream(fileToRead);



@@ 419,7 608,7 @@ std::string BackupRestore::ReadFileAsString(const std::filesystem::path &fileToR

using namespace sdesktop::endpoints;

std::string BackupRestore::ReadVersionFromJsonFile(const std::filesystem::path &jsonFilePath)
std::string BackupSyncRestore::ReadVersionFromJsonFile(const std::filesystem::path &jsonFilePath)
{
    const auto jsonFile = ReadFileAsString(jsonFilePath);



@@ 445,7 634,7 @@ std::string BackupRestore::ReadVersionFromJsonFile(const std::filesystem::path &
    return (bootVersionObject[json::version]).string_value();
}

bool BackupRestore::CheckBackupVersion(const std::filesystem::path &extractedBackup)
bool BackupSyncRestore::CheckBackupVersion(const std::filesystem::path &extractedBackup)
{
    auto versionOK           = true;
    const auto backupVersion = ReadVersionFromJsonFile(extractedBackup / bkp::backupInfo);


@@ 486,12 675,12 @@ bool BackupRestore::CheckBackupVersion(const std::filesystem::path &extractedBac
    return versionOK;
}

bool BackupRestore::CanRestoreFromBackup(const std::filesystem::path &extractedBackup)
bool BackupSyncRestore::CanRestoreFromBackup(const std::filesystem::path &extractedBackup)
{
    return CheckBackupVersion(extractedBackup);
}

bool BackupRestore::ReplaceUserFiles(const std::filesystem::path &path)
bool BackupSyncRestore::ReplaceUserFiles(const std::filesystem::path &path)
{
    /* replace existing files that have respective backup files existing */
    const auto tempDir = purefs::dir::getTemporaryPath() / path.stem();


@@ 539,7 728,7 @@ bool BackupRestore::ReplaceUserFiles(const std::filesystem::path &path)
    return true;
}

json11::Json BackupRestore::GetBackupFiles()
json11::Json BackupSyncRestore::GetBackupFiles()
{
    auto dirEntryVector = std::vector<std::string>();
    std::error_code errorCode;

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +60 -19
@@ 46,6 46,7 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
    connectHandler<message::bluetooth::ResponseVisibleDevices>();
    connectHandler<sdesktop::developerMode::DeveloperModeRequest>();
    connectHandler<sdesktop::BackupMessage>();
    connectHandler<sdesktop::SyncMessage>();
    connectHandler<sdesktop::RestoreMessage>();
    connectHandler<sdesktop::FactoryMessage>();
    connectHandler<sdesktop::usb::USBConfigured>();


@@ 101,20 102,39 @@ std::string ServiceDesktop::prepareBackupFilename()
    return std::string(backupFileName.data());
}

std::string ServiceDesktop::prepareSyncFilename()
{
    const std::size_t maxFileNameSize = 64;
    std::array<char, maxFileNameSize> syncFileName{};
    std::time_t now;
    std::time(&now);
    std::strftime(syncFileName.data(), syncFileName.size(), "%FT%OH%OM%OSZ", std::localtime(&now));

    return std::string(syncFileName.data());
}

void ServiceDesktop::prepareBackupData()
{
    backupRestoreStatus.operation     = BackupRestore::Operation::Backup;
    backupRestoreStatus.taskId        = prepareBackupFilename();
    backupRestoreStatus.state         = BackupRestore::OperationState::Stopped;
    backupRestoreStatus.backupTempDir = purefs::dir::getTemporaryPath() / backupRestoreStatus.taskId;
    backupSyncRestoreStatus.operation     = BackupSyncRestore::Operation::Backup;
    backupSyncRestoreStatus.taskId        = prepareBackupFilename();
    backupSyncRestoreStatus.state         = BackupSyncRestore::OperationState::Stopped;
    backupSyncRestoreStatus.backupTempDir = purefs::dir::getTemporaryPath() / backupSyncRestoreStatus.taskId;
}

void ServiceDesktop::prepareSyncData()
{
    backupSyncRestoreStatus.operation     = BackupSyncRestore::Operation::Sync;
    backupSyncRestoreStatus.taskId        = prepareSyncFilename();
    backupSyncRestoreStatus.state         = BackupSyncRestore::OperationState::Stopped;
    backupSyncRestoreStatus.backupTempDir = purefs::dir::getTemporaryPath() / backupSyncRestoreStatus.taskId;
}

void ServiceDesktop::prepareRestoreData(const std::filesystem::path &restoreLocation)
{
    backupRestoreStatus.operation = BackupRestore::Operation::Restore;
    backupRestoreStatus.taskId    = restoreLocation.filename();
    backupRestoreStatus.state     = BackupRestore::OperationState::Stopped;
    backupRestoreStatus.location  = purefs::dir::getBackupOSPath() / backupRestoreStatus.taskId;
    backupSyncRestoreStatus.operation = BackupSyncRestore::Operation::Restore;
    backupSyncRestoreStatus.taskId    = restoreLocation.filename();
    backupSyncRestoreStatus.state     = BackupSyncRestore::OperationState::Stopped;
    backupSyncRestoreStatus.location  = purefs::dir::getBackupOSPath() / backupSyncRestoreStatus.taskId;
}

auto ServiceDesktop::requestLogsFlush() -> void


@@ 315,17 335,37 @@ auto ServiceDesktop::handle(sdesktop::developerMode::DeveloperModeRequest *msg) 

auto ServiceDesktop::handle(sdesktop::BackupMessage * /*msg*/) -> std::shared_ptr<sys::Message>
{
    backupRestoreStatus.state          = BackupRestore::OperationState::Running;
    backupRestoreStatus.completionCode = BackupRestore::BackupUserFiles(this, backupRestoreStatus.backupTempDir);
    backupRestoreStatus.location       = backupRestoreStatus.taskId;
    backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Running;
    backupSyncRestoreStatus.completionCode =
        BackupSyncRestore::BackupUserFiles(this, backupSyncRestoreStatus.backupTempDir);
    backupSyncRestoreStatus.location = backupSyncRestoreStatus.taskId;

    if (backupRestoreStatus.completionCode == BackupRestore::CompletionCode::Success) {
    if (backupSyncRestoreStatus.completionCode == BackupSyncRestore::CompletionCode::Success) {
        LOG_INFO("Backup finished");
        backupRestoreStatus.state = BackupRestore::OperationState::Finished;
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Finished;
    }
    else {
        LOG_ERROR("Backup failed");
        backupRestoreStatus.state = BackupRestore::OperationState::Error;
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Error;
    }

    return sys::MessageNone{};
}

auto ServiceDesktop::handle(sdesktop::SyncMessage * /*msg*/) -> std::shared_ptr<sys::Message>
{
    backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Running;
    backupSyncRestoreStatus.completionCode =
        BackupSyncRestore::PrepareSyncPackage(this, backupSyncRestoreStatus.backupTempDir);
    backupSyncRestoreStatus.location = backupSyncRestoreStatus.taskId;

    if (backupSyncRestoreStatus.completionCode == BackupSyncRestore::CompletionCode::Success) {
        LOG_INFO("Sync package preparation finished");
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Finished;
    }
    else {
        LOG_ERROR("Sync package preparation failed");
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Error;
    }

    return sys::MessageNone{};


@@ 333,17 373,18 @@ auto ServiceDesktop::handle(sdesktop::BackupMessage * /*msg*/) -> std::shared_pt

auto ServiceDesktop::handle(sdesktop::RestoreMessage * /*msg*/) -> std::shared_ptr<sys::Message>
{
    backupRestoreStatus.state          = BackupRestore::OperationState::Running;
    backupRestoreStatus.completionCode = BackupRestore::RestoreUserFiles(this, backupRestoreStatus.location);
    backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Running;
    backupSyncRestoreStatus.completionCode =
        BackupSyncRestore::RestoreUserFiles(this, backupSyncRestoreStatus.location);

    if (backupRestoreStatus.completionCode == BackupRestore::CompletionCode::Success) {
    if (backupSyncRestoreStatus.completionCode == BackupSyncRestore::CompletionCode::Success) {
        LOG_DEBUG("Restore finished");
        backupRestoreStatus.state = BackupRestore::OperationState::Finished;
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Finished;
        sys::SystemManagerCommon::Reboot(this);
    }
    else {
        LOG_ERROR("Restore failed");
        backupRestoreStatus.state = BackupRestore::OperationState::Error;
        backupSyncRestoreStatus.state = BackupSyncRestore::OperationState::Error;
    }

    return sys::MessageNone{};

M module-services/service-desktop/endpoints/backup/BackupHelper.cpp => module-services/service-desktop/endpoints/backup/BackupHelper.cpp +72 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <endpoints/Context.hpp>


@@ 19,11 19,17 @@ namespace sdesktop::endpoints

    auto BackupHelper::processGet(Context &context) -> ProcessResult
    {
        if (context.getBody()[json::messages::category].string_value() == json::messages::categorySync) {
            return checkSyncState(context);
        }
        return checkState(context);
    }

    auto BackupHelper::processPost(Context &context) -> ProcessResult
    {
        if (context.getBody()[json::messages::category].string_value() == json::messages::categorySync) {
            return executeSyncRequest(context);
        }
        return executeRequest(context);
    }



@@ 31,7 37,7 @@ namespace sdesktop::endpoints
    {
        auto ownerServicePtr = static_cast<ServiceDesktop *>(owner);

        if (ownerServicePtr->getBackupRestoreStatus().state == BackupRestore::OperationState::Running) {
        if (ownerServicePtr->getBackupSyncRestoreStatus().state == BackupSyncRestore::OperationState::Running) {
            LOG_DEBUG("Backup already running");
            // a backup is already running, don't start a second task
            context.setResponseStatus(http::Code::NotAcceptable);


@@ 46,7 52,7 @@ namespace sdesktop::endpoints
                                             service::name::service_desktop);

            // return new generated backup info
            context.setResponseBody(ownerServicePtr->getBackupRestoreStatus());
            context.setResponseBody(ownerServicePtr->getBackupSyncRestoreStatus());
        }

        putToSendQueue(context.createSimpleResponse());


@@ 59,15 65,75 @@ namespace sdesktop::endpoints
        auto ownerServicePtr = static_cast<ServiceDesktop *>(owner);

        if (context.getBody()[json::taskId].is_string()) {
            if (ownerServicePtr->getBackupRestoreStatus().taskId == context.getBody()[json::taskId].string_value()) {
                if (ownerServicePtr->getBackupRestoreStatus().state == BackupRestore::OperationState::Finished) {
            if (ownerServicePtr->getBackupSyncRestoreStatus().taskId ==
                context.getBody()[json::taskId].string_value()) {
                if (ownerServicePtr->getBackupSyncRestoreStatus().state ==
                    BackupSyncRestore::OperationState::Finished) {
                    context.setResponseStatus(http::Code::SeeOther);
                }
                else {
                    context.setResponseStatus(http::Code::OK);
                }

                context.setResponseBody(ownerServicePtr->getBackupSyncRestoreStatus());
            }
            else {
                context.setResponseStatus(http::Code::NotFound);
            }
        }
        else {
            LOG_DEBUG("Backup task not found");
            context.setResponseStatus(http::Code::BadRequest);
        }

        LOG_DEBUG("Responding");
        putToSendQueue(context.createSimpleResponse());

        return {sent::yes, std::nullopt};
    }

    auto BackupHelper::executeSyncRequest(Context &context) -> ProcessResult
    {
        auto ownerServicePtr = static_cast<ServiceDesktop *>(owner);

        if (ownerServicePtr->getBackupSyncRestoreStatus().state == BackupSyncRestore::OperationState::Running) {
            LOG_DEBUG("Sync already running");
            // a sync package preparation is already running, don't start a second task
            context.setResponseStatus(http::Code::NotAcceptable);
        }
        else {
            LOG_DEBUG("Starting a sync package preparation");
            // initialize new sync information
            ownerServicePtr->prepareSyncData();

            // start the sync package preparation process in the background
            ownerServicePtr->bus.sendUnicast(std::make_shared<sdesktop::SyncMessage>(), service::name::service_desktop);

            // return new generated sync package info
            context.setResponseBody(ownerServicePtr->getBackupSyncRestoreStatus());
        }

        putToSendQueue(context.createSimpleResponse());

        return {sent::yes, std::nullopt};
    }

    auto BackupHelper::checkSyncState(Context &context) -> ProcessResult
    {
        auto ownerServicePtr = static_cast<ServiceDesktop *>(owner);

        if (context.getBody()[json::taskId].is_string()) {
            if (ownerServicePtr->getBackupSyncRestoreStatus().taskId ==
                context.getBody()[json::taskId].string_value()) {
                if (ownerServicePtr->getBackupSyncRestoreStatus().state ==
                    BackupSyncRestore::OperationState::Finished) {
                    context.setResponseStatus(http::Code::SeeOther);
                }
                else {
                    context.setResponseStatus(http::Code::OK);
                }

                context.setResponseBody(ownerServicePtr->getBackupRestoreStatus());
                context.setResponseBody(ownerServicePtr->getBackupSyncRestoreStatus());
            }
            else {
                context.setResponseStatus(http::Code::NotFound);

M module-services/service-desktop/endpoints/include/endpoints/JsonKeyNames.hpp => module-services/service-desktop/endpoints/include/endpoints/JsonKeyNames.hpp +31 -28
@@ 25,34 25,35 @@ namespace sdesktop::endpoints::json
    inline constexpr auto networkOperatorName = "networkOperatorName";
    inline constexpr auto accessTechnology    = "accessTechnology";

    inline constexpr auto update         = "update";
    inline constexpr auto updateInfo     = "updateInfo";
    inline constexpr auto updateError    = "updateError";
    inline constexpr auto errorCode      = "errorCode";
    inline constexpr auto statusCode     = "statusCode";
    inline constexpr auto updateHistory  = "updateHistory";
    inline constexpr auto usbMscMode     = "usbMscMode";
    inline constexpr auto versionString  = "string";
    inline constexpr auto fileExists     = "fileExists";
    inline constexpr auto boot           = "boot";
    inline constexpr auto version        = "version";
    inline constexpr auto taskId         = "id";
    inline constexpr auto state          = "state";
    inline constexpr auto success        = "success";
    inline constexpr auto reboot         = "reboot";
    inline constexpr auto rebootMode     = "rebootMode";
    inline constexpr auto request        = "request";
    inline constexpr auto restore        = "restore";
    inline constexpr auto finished       = "finished";
    inline constexpr auto pending        = "pending";
    inline constexpr auto location       = "location";
    inline constexpr auto reason         = "reason";
    inline constexpr auto serialNumber   = "serialNumber";
    inline constexpr auto caseColour     = "caseColour";
    inline constexpr auto fileList       = "fileList";
    inline constexpr auto files          = "files";
    inline constexpr auto backupLocation = "backupLocation";
    inline constexpr auto deviceToken    = "deviceToken";
    inline constexpr auto update              = "update";
    inline constexpr auto updateInfo          = "updateInfo";
    inline constexpr auto updateError         = "updateError";
    inline constexpr auto errorCode           = "errorCode";
    inline constexpr auto statusCode          = "statusCode";
    inline constexpr auto updateHistory       = "updateHistory";
    inline constexpr auto usbMscMode          = "usbMscMode";
    inline constexpr auto versionString       = "string";
    inline constexpr auto fileExists          = "fileExists";
    inline constexpr auto boot                = "boot";
    inline constexpr auto version             = "version";
    inline constexpr auto taskId              = "id";
    inline constexpr auto state               = "state";
    inline constexpr auto success             = "success";
    inline constexpr auto reboot              = "reboot";
    inline constexpr auto rebootMode          = "rebootMode";
    inline constexpr auto request             = "request";
    inline constexpr auto restore             = "restore";
    inline constexpr auto finished            = "finished";
    inline constexpr auto pending             = "pending";
    inline constexpr auto location            = "location";
    inline constexpr auto reason              = "reason";
    inline constexpr auto serialNumber        = "serialNumber";
    inline constexpr auto caseColour          = "caseColour";
    inline constexpr auto fileList            = "fileList";
    inline constexpr auto files               = "files";
    inline constexpr auto backupLocation      = "backupLocation";
    inline constexpr auto syncPackageLocation = "syncPackageLocation";
    inline constexpr auto deviceToken         = "deviceToken";

    namespace updateprocess
    {


@@ 71,6 72,8 @@ namespace sdesktop::endpoints::json
        inline constexpr auto categoryMessage  = "message";
        inline constexpr auto categoryThread   = "thread";
        inline constexpr auto categoryTemplate = "template";
        inline constexpr auto categoryBackup   = "backup";
        inline constexpr auto categorySync     = "sync";

        inline constexpr auto limit              = "limit";
        inline constexpr auto offset             = "offset";

M module-services/service-desktop/endpoints/include/endpoints/backup/BackupHelper.hpp => module-services/service-desktop/endpoints/include/endpoints/backup/BackupHelper.hpp +3 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 19,5 19,7 @@ namespace sdesktop::endpoints
      private:
        auto executeRequest(Context &context) -> ProcessResult;
        auto checkState(Context &context) -> ProcessResult;
        auto executeSyncRequest(Context &context) -> ProcessResult;
        auto checkSyncState(Context &context) -> ProcessResult;
    };
} // namespace sdesktop::endpoints

M module-services/service-desktop/endpoints/restore/RestoreHelper.cpp => module-services/service-desktop/endpoints/restore/RestoreHelper.cpp +6 -6
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <endpoints/Context.hpp>


@@ 31,9 31,9 @@ namespace sdesktop::endpoints
        auto ownerService = static_cast<ServiceDesktop *>(owner);

        if (context.getBody()[json::taskId].is_string()) {
            if (ownerService->getBackupRestoreStatus().taskId == context.getBody()[json::taskId].string_value()) {
            if (ownerService->getBackupSyncRestoreStatus().taskId == context.getBody()[json::taskId].string_value()) {
                context.setResponseStatus(http::Code::OK);
                context.setResponseBody(ownerService->getBackupRestoreStatus());
                context.setResponseBody(ownerService->getBackupSyncRestoreStatus());
            }
            else {
                return {sent::no, ResponseContext{.status = http::Code::NotFound}};


@@ 46,7 46,7 @@ namespace sdesktop::endpoints

                return {sent::no, ResponseContext{.status = http::Code::BadRequest}};
            }
            auto filesList = json11::Json::object{{json::files, BackupRestore::GetBackupFiles()}};
            auto filesList = json11::Json::object{{json::files, BackupSyncRestore::GetBackupFiles()}};
            context.setResponseBody(filesList);
        }



@@ 61,7 61,7 @@ namespace sdesktop::endpoints
        auto ownerService = static_cast<ServiceDesktop *>(owner);

        if (context.getBody()[json::restore].is_string()) {
            if (ownerService->getBackupRestoreStatus().state == BackupRestore::OperationState::Running) {
            if (ownerService->getBackupSyncRestoreStatus().state == BackupSyncRestore::OperationState::Running) {
                LOG_WARN("Restore is running, try again later");

                return {sent::no, ResponseContext{.status = http::Code::NotAcceptable}};


@@ 88,7 88,7 @@ namespace sdesktop::endpoints
                                              service::name::service_desktop);

                // return new generated restore info
                context.setResponseBody(ownerService->getBackupRestoreStatus());
                context.setResponseBody(ownerService->getBackupSyncRestoreStatus());
            }
        }
        else {

M module-services/service-desktop/include/service-desktop/BackupRestore.hpp => module-services/service-desktop/include/service-desktop/BackupRestore.hpp +6 -1
@@ 13,12 13,13 @@ namespace sys
    class Service;
} // namespace sys

class BackupRestore
class BackupSyncRestore
{
  public:
    enum class Operation
    {
        Backup,
        Sync,
        Restore
    };



@@ 102,13 103,17 @@ class BackupRestore
    };

    static CompletionCode BackupUserFiles(sys::Service *ownerService, std::filesystem::path &path);
    static CompletionCode PrepareSyncPackage(sys::Service *ownerService, std::filesystem::path &path);
    static CompletionCode RestoreUserFiles(sys::Service *ownerService, const std::filesystem::path &path);
    static json11::Json GetBackupFiles();

  private:
    static bool RemoveBackupDir(const std::filesystem::path &path);
    static bool CreateBackupDir(const std::filesystem::path &path);
    static bool RemoveSyncDir(const std::filesystem::path &path);
    static bool CreateSyncDir(const std::filesystem::path &path);
    static bool PackUserFiles(const std::filesystem::path &path);
    static bool PackSyncFiles(const std::filesystem::path &path);
    static bool UnpackBackupFile(const std::filesystem::path &path);
    static std::string ReadVersionFromJsonFile(const std::filesystem::path &jsonFilePath);
    static bool CheckBackupVersion(const std::filesystem::path &extractedBackup);

M module-services/service-desktop/include/service-desktop/DesktopMessages.hpp => module-services/service-desktop/include/service-desktop/DesktopMessages.hpp +9 -1
@@ 1,4 1,4 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once


@@ 20,6 20,14 @@ namespace sdesktop
        ~BackupMessage() override = default;
    };

    class SyncMessage : public sys::DataMessage
    {
      public:
        SyncMessage() : sys::DataMessage(MessageType::Sync)
        {}
        ~SyncMessage() override = default;
    };

    class RestoreMessage : public sys::DataMessage
    {
      public:

M module-services/service-desktop/include/service-desktop/ServiceDesktop.hpp => module-services/service-desktop/include/service-desktop/ServiceDesktop.hpp +6 -3
@@ 55,7 55,7 @@ class ServiceDesktop : public sys::Service
    ~ServiceDesktop() override;

    std::unique_ptr<WorkerDesktop> desktopWorker;
    BackupRestore::OperationStatus backupRestoreStatus;
    BackupSyncRestore::OperationStatus backupSyncRestoreStatus;

    sys::ReturnCodes InitHandler() override;
    sys::ReturnCodes DeinitHandler() override;


@@ 63,11 63,13 @@ class ServiceDesktop : public sys::Service
    sys::MessagePointer DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) override;

    std::string prepareBackupFilename();
    std::string prepareSyncFilename();
    void prepareBackupData();
    void prepareSyncData();
    void prepareRestoreData(const std::filesystem::path &restoreLocation);
    const BackupRestore::OperationStatus getBackupRestoreStatus()
    const BackupSyncRestore::OperationStatus getBackupSyncRestoreStatus()
    {
        return backupRestoreStatus;
        return backupSyncRestoreStatus;
    }
    const sdesktop::USBSecurityModel *getSecurity()
    {


@@ 120,6 122,7 @@ class ServiceDesktop : public sys::Service
    [[nodiscard]] auto handle(message::bluetooth::ResponseVisibleDevices *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::developerMode::DeveloperModeRequest *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::BackupMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::SyncMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::RestoreMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::FactoryMessage *msg) -> std::shared_ptr<sys::Message>;
    [[nodiscard]] auto handle(sdesktop::usb::USBConfigured *msg) -> std::shared_ptr<sys::Message>;

M module-vfs/paths/filesystem_paths.cpp => module-vfs/paths/filesystem_paths.cpp +6 -0
@@ 14,6 14,7 @@ namespace
    constexpr inline auto PATH_UPDATES      = "updates";
    constexpr inline auto PATH_TMP          = "tmp";
    constexpr inline auto PATH_BACKUP       = "backup";
    constexpr inline auto PATH_SYNC  = "sync";
    constexpr inline auto PATH_FACTORY      = "factory";
    constexpr inline auto PATH_LOGS         = "logs";
    constexpr inline auto PATH_CRASH_DUMPS  = "crash_dumps";


@@ 71,6 72,11 @@ namespace purefs
            return getUserDiskPath() / PATH_BACKUP;
        }

        std::filesystem::path getSyncPackagePath() noexcept
        {
            return getUserDiskPath() / PATH_SYNC;
        }

        std::filesystem::path getFactoryOSPath() noexcept
        {
            return std::filesystem::path{eMMC_disk} / PATH_FACTORY;

M module-vfs/paths/include/purefs/filesystem_paths.hpp => module-vfs/paths/include/purefs/filesystem_paths.hpp +1 -0
@@ 19,6 19,7 @@ namespace purefs
        std::filesystem::path getUpdatesOSPath() noexcept;
        std::filesystem::path getTemporaryPath() noexcept;
        std::filesystem::path getBackupOSPath() noexcept;
        std::filesystem::path getSyncPackagePath() noexcept;
        std::filesystem::path getFactoryOSPath() noexcept;
        std::filesystem::path getLogsPath() noexcept;
        std::filesystem::path getCrashDumpsPath() noexcept;

M products/PurePhone/services/db/ServiceDB.cpp => products/PurePhone/services/db/ServiceDB.cpp +22 -0
@@ 228,6 228,13 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        responseMsg = std::make_shared<DBServiceResponseMessage>(ret);
    } break;

    case MessageType::DBSyncPackage: {
        auto time   = utils::time::Scoped("DBSyncPackage");
        auto msg    = static_cast<DBServiceMessageSyncPackage *>(msgl);
        auto ret    = StoreIntoSyncPackage({msg->syncPackagePath});
        responseMsg = std::make_shared<DBServiceResponseMessage>(ret);
    } break;

    default:
        break;
    }


@@ 348,3 355,18 @@ bool ServiceDB::StoreIntoBackup(const std::filesystem::path &backupPath)

    return true;
}

bool ServiceDB::StoreIntoSyncPackage(const std::filesystem::path &syncPackagePath)
{
    if (!contactsDB->storeIntoFile(syncPackagePath / std::filesystem::path(contactsDB->getName()).filename())) {
        LOG_ERROR("Store contactsDB in sync package failed");
        return false;
    }

    if (!smsDB->storeIntoFile(syncPackagePath / std::filesystem::path(smsDB->getName()).filename())) {
        LOG_ERROR("Store smsDB in sync package failed");
        return false;
    }

    return true;
}

M products/PurePhone/services/db/include/db/ServiceDB.hpp => products/PurePhone/services/db/include/db/ServiceDB.hpp +1 -0
@@ 43,6 43,7 @@ class ServiceDB : public ServiceDBCommon
    ~ServiceDB() override;

    bool StoreIntoBackup(const std::filesystem::path &backupPath);
    bool StoreIntoSyncPackage(const std::filesystem::path &syncPackagePath);

  private:
    std::unique_ptr<EventsDB> eventsDB;

M products/PurePhone/services/desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp => products/PurePhone/services/desktop/endpoints/deviceInfo/DeviceInfoEndpoint.cpp +1 -0
@@ 59,6 59,7 @@ namespace sdesktop::endpoints
             {json::serialNumber, getSerialNumber()},
             {json::caseColour, getCaseColour()},
             {json::backupLocation, purefs::dir::getBackupOSPath().string()},
             {json::syncPackageLocation, purefs::dir::getSyncPackagePath().string()},
             {json::deviceToken, getDeviceToken()}}));

        return http::Code::OK;

M source/MessageType.hpp => source/MessageType.hpp +2 -0
@@ 17,6 17,7 @@ enum class MessageType

    DBServiceNotification, ///< Common service-db notification message.
    DBServiceBackup,
    DBSyncPackage,

    DBSettingsGet,    ///< get current settings from database
    DBSettingsUpdate, ///< update settings


@@ 119,6 120,7 @@ enum class MessageType
    // service-desktop  messages
    UpdateOS,
    Backup,
    Sync,
    Restore,
    Factory,
    DeveloperModeRequest,