~aleteoryx/muditaos

19c2c0373607115d26edb1ada4773cd8e681ffeb — Pawel Olejniczak 3 years ago 8fb2a72
[CP-1080] Collect contacts notifications in outbox ep

When contact record is created/updated/removed during
connection with Mudita Center, notification of that
action should be collected in outbox endpoint to
keep contacts data synchronized between MuditaOS
and Mudita Center.
M module-services/service-db/ServiceDBCommon.cpp => module-services/service-db/ServiceDBCommon.cpp +2 -2
@@ 99,8 99,8 @@ sys::ReturnCodes ServiceDBCommon::SwitchPowerModeHandler(const sys::ServicePower
    return sys::ReturnCodes::Success;
}

void ServiceDBCommon::sendUpdateNotification(db::Interface::Name interface, db::Query::Type type)
void ServiceDBCommon::sendUpdateNotification(db::Interface::Name interface, db::Query::Type type, uint32_t recordId)
{
    auto notificationMessage = std::make_shared<db::NotificationMessage>(interface, type);
    auto notificationMessage = std::make_shared<db::NotificationMessage>(interface, type, recordId);
    bus.sendMulticast(notificationMessage, sys::BusChannel::ServiceDBNotifications);
}

M module-services/service-db/include/service-db/DBNotificationMessage.hpp => module-services/service-db/include/service-db/DBNotificationMessage.hpp +3 -2
@@ 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


@@ 15,9 15,10 @@ namespace db
    class NotificationMessage : public sys::DataMessage
    {
      public:
        NotificationMessage(db::Interface::Name interface, Query::Type type);
        NotificationMessage(db::Interface::Name interface, Query::Type type, uint32_t recordId);
        const db::Interface::Name interface;
        const Query::Type type;
        const uint32_t recordId;

        bool dataModified();
    };

M module-services/service-db/include/service-db/ServiceDBCommon.hpp => module-services/service-db/include/service-db/ServiceDBCommon.hpp +2 -2
@@ 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


@@ 31,5 31,5 @@ class ServiceDBCommon : public sys::Service

    sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) final;

    void sendUpdateNotification(db::Interface::Name interface, db::Query::Type type);
    void sendUpdateNotification(db::Interface::Name interface, db::Query::Type type, uint32_t recordId = 0);
};

M module-services/service-db/messages/DBNotificationMessage.cpp => module-services/service-db/messages/DBNotificationMessage.cpp +3 -3
@@ 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/DBNotificationMessage.hpp>


@@ 9,8 9,8 @@

namespace db
{
    NotificationMessage::NotificationMessage(db::Interface::Name interface, Query::Type type)
        : sys::DataMessage(MessageType::DBServiceNotification), interface(interface), type(type)
    NotificationMessage::NotificationMessage(db::Interface::Name interface, Query::Type type, uint32_t recordId)
        : sys::DataMessage(MessageType::DBServiceNotification), interface(interface), type(type), recordId(recordId)
    {}

    bool NotificationMessage::dataModified()

M module-services/service-desktop/CMakeLists.txt => module-services/service-desktop/CMakeLists.txt +2 -0
@@ 11,6 11,7 @@ target_sources(
        DesktopEvent.cpp
        DeveloperModeMessage.cpp
        DesktopMessages.cpp
        OutboxNotifications.cpp
        ServiceDesktop.cpp
        WorkerDesktop.cpp
        USBSecurityModel.cpp


@@ 27,6 28,7 @@ target_sources(
        include/service-desktop/DesktopMessages.hpp
        include/service-desktop/DeveloperModeMessage.hpp
        include/service-desktop/Outbox.hpp
        include/service-desktop/OutboxNotifications.hpp
        include/service-desktop/ServiceDesktop.hpp
        include/service-desktop/USBSecurityModel.hpp
)

A module-services/service-desktop/OutboxNotifications.cpp => module-services/service-desktop/OutboxNotifications.cpp +66 -0
@@ 0,0 1,66 @@
// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <service-desktop/OutboxNotifications.hpp>

auto OutboxNotifications::getNotificationEntries() const -> std::vector<Outbox::NotificationEntry>
{
    return notificationEntries;
}

void OutboxNotifications::removeNotificationEntries(const std::vector<uint32_t> &uidsOfNotificationsToBeRemoved)
{
    for (auto const &entryUid : uidsOfNotificationsToBeRemoved) {
        notificationEntries.erase(
            std::remove_if(notificationEntries.begin(),
                           notificationEntries.end(),
                           [&](const Outbox::NotificationEntry &entry) { return entry.uid == entryUid; }),
            notificationEntries.end());
    }
}

void OutboxNotifications::clearNotifications()
{
    notificationEntries.clear();
    notificationCurrentUid = 0;
}

void OutboxNotifications::newNotificationHandler(db::NotificationMessage *notificationMessage)
{
    auto entryType = Outbox::EntryType::INVALID;
    switch (notificationMessage->interface) {
    case db::Interface::Name::Contact:
        entryType = Outbox::EntryType::CONTACT;
        break;
    case db::Interface::Name::SMS:
        entryType = Outbox::EntryType::MESSAGE;
        break;
    case db::Interface::Name::SMSThread:
        entryType = Outbox::EntryType::THREAD;
        break;
    default:
        break;
    }

    auto entryChange = Outbox::EntryChange::INVALID;
    switch (notificationMessage->type) {
    case db::Query::Type::Create:
        entryChange = Outbox::EntryChange::CREATED;
        break;
    case db::Query::Type::Update:
        entryChange = Outbox::EntryChange::UPDATED;
        break;
    case db::Query::Type::Delete:
        entryChange = Outbox::EntryChange::DELETED;
        break;
    default:
        break;
    }

    if (entryType != Outbox::EntryType::INVALID && entryChange != Outbox::EntryChange::INVALID &&
        notificationMessage->recordId != 0) {
        Outbox::NotificationEntry newNotificationEntry = {
            notificationCurrentUid++, entryType, entryChange, notificationMessage->recordId};
        notificationEntries.emplace_back(newNotificationEntry);
    }
}
\ No newline at end of file

M module-services/service-desktop/ServiceDesktop.cpp => module-services/service-desktop/ServiceDesktop.cpp +35 -27
@@ 4,6 4,7 @@
#include "service-evtmgr/BatteryMessages.hpp"
#include "system/SystemReturnCodes.hpp"
#include <service-appmgr/messages/DOMRequest.hpp>
#include <service-db/DBNotificationMessage.hpp>
#include <service-desktop/DesktopMessages.hpp>
#include <service-desktop/ServiceDesktop.hpp>
#include <service-desktop/WorkerDesktop.hpp>


@@ 34,14 35,15 @@
ServiceDesktop::ServiceDesktop()
    : sys::Service(service::name::service_desktop, "", sdesktop::service_stack),
      btMsgHandler(std::make_unique<sdesktop::bluetooth::BluetoothMessagesHandler>(this)),
      notificationsClearTimer{
          sys::TimerFactory::createSingleShotTimer(this,
                                                   sdesktop::notificationsClearTimerName,
                                                   sdesktop::notificationsClearTimerDelayMs,
                                                   [this](sys::Timer & /*timer*/) { notificationEntries.clear(); })}
      connectionActiveTimer{sys::TimerFactory::createSingleShotTimer(
          this,
          sdesktop::connectionActiveTimerName,
          sdesktop::connectionActiveTimerDelayMs,
          [this](sys::Timer & /*timer*/) { outboxNotifications.clearNotifications(); })}
{
    LOG_INFO("[ServiceDesktop] Initializing");
    bus.channels.push_back(sys::BusChannel::PhoneLockChanges);
    bus.channels.push_back(sys::BusChannel::ServiceDBNotifications);
    bus.channels.push_back(sys::BusChannel::USBNotifications);
}



@@ 241,6 243,18 @@ sys::ReturnCodes ServiceDesktop::InitHandler()
        return btMsgHandler->handle(msgl);
    });

    connect(typeid(db::NotificationMessage), [&](sys::Message *msg) {
        if (!connectionActiveTimer.isActive()) {
            return sys::MessageNone{};
        }
        auto notificationMessage = dynamic_cast<db::NotificationMessage *>(msg);
        if (notificationMessage == nullptr) {
            return sys::MessageNone{};
        }
        outboxNotifications.newNotificationHandler(notificationMessage);
        return sys::MessageNone{};
    });

    if (auto resUsb = usbWorkerInit(); resUsb != sys::ReturnCodes::Success) {
        return resUsb;
    }


@@ 306,27 320,6 @@ void ServiceDesktop::prepareRestoreData(const std::filesystem::path &restoreLoca
    backupRestoreStatus.location  = purefs::dir::getBackupOSPath() / backupRestoreStatus.taskId;
}

auto ServiceDesktop::getNotificationEntries() const -> std::vector<Outbox::NotificationEntry>
{
    return notificationEntries;
}

void ServiceDesktop::removeNotificationEntries(const std::vector<int> &uidsOfNotificationsToBeRemoved)
{
    for (auto const &entryUid : uidsOfNotificationsToBeRemoved) {
        notificationEntries.erase(
            std::remove_if(notificationEntries.begin(),
                           notificationEntries.end(),
                           [&](const Outbox::NotificationEntry &entry) { return entry.uid == entryUid; }),
            notificationEntries.end());
    }
}

void ServiceDesktop::restartNotificationsClearTimer()
{
    notificationsClearTimer.restart(sdesktop::notificationsClearTimerDelayMs);
}

auto ServiceDesktop::usbWorkerInit() -> sys::ReturnCodes
{
    if (!initialized) {


@@ 335,7 328,7 @@ auto ServiceDesktop::usbWorkerInit() -> sys::ReturnCodes
        LOG_DEBUG("usbWorkerInit Serial Number: %s", serialNumber.c_str());

        desktopWorker = std::make_unique<WorkerDesktop>(
            this, std::bind(&ServiceDesktop::restartNotificationsClearTimer, this), *usbSecurityModel, serialNumber);
            this, std::bind(&ServiceDesktop::restartConnectionActiveTimer, this), *usbSecurityModel, serialNumber);

        initialized = desktopWorker->init(
            {{sdesktop::RECEIVE_QUEUE_BUFFER_NAME, sizeof(std::string *), sdesktop::cdc_queue_len},


@@ 364,3 357,18 @@ auto ServiceDesktop::usbWorkerDeinit() -> sys::ReturnCodes
    }
    return sys::ReturnCodes::Success;
}

auto ServiceDesktop::getNotificationEntries() const -> std::vector<Outbox::NotificationEntry>
{
    return outboxNotifications.getNotificationEntries();
}

void ServiceDesktop::removeNotificationEntries(const std::vector<uint32_t> &uidsOfNotificationsToBeRemoved)
{
    outboxNotifications.removeNotificationEntries(uidsOfNotificationsToBeRemoved);
}

void ServiceDesktop::restartConnectionActiveTimer()
{
    connectionActiveTimer.restart(sdesktop::connectionActiveTimerDelayMs);
}

M module-services/service-desktop/include/service-desktop/Outbox.hpp => module-services/service-desktop/include/service-desktop/Outbox.hpp +2 -2
@@ 23,9 23,9 @@ struct Outbox

    struct NotificationEntry
    {
        int uid                 = 0;
        uint32_t uid            = 0;
        EntryType entryType     = EntryType::INVALID;
        EntryChange entryChange = EntryChange::INVALID;
        int recordId            = 0;
        uint32_t recordId       = 0;
    };
};

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

#pragma once

#include <service-db/DBNotificationMessage.hpp>
#include <service-desktop/Outbox.hpp>

class OutboxNotifications
{
  public:
    void clearNotifications();
    void newNotificationHandler(db::NotificationMessage *notificationMessage);
    auto getNotificationEntries() const -> std::vector<Outbox::NotificationEntry>;
    void removeNotificationEntries(const std::vector<uint32_t> &);

  private:
    uint32_t notificationCurrentUid = 0;
    std::vector<Outbox::NotificationEntry> notificationEntries;
};

M module-services/service-desktop/include/service-desktop/ServiceDesktop.hpp => module-services/service-desktop/include/service-desktop/ServiceDesktop.hpp +8 -8
@@ 13,7 13,7 @@
#include "USBSecurityModel.hpp"
#include "system/SystemReturnCodes.hpp"
#include <service-desktop/BackupRestore.hpp>
#include <service-desktop/Outbox.hpp>
#include <service-desktop/OutboxNotifications.hpp>
#include <service-db/DBServiceName.hpp>

#include <bsp/usb/usb.hpp>


@@ 36,8 36,8 @@ namespace sdesktop
    inline constexpr auto cdc_queue_object_size     = 1024;
    inline constexpr auto irq_queue_object_size     = sizeof(bsp::USBDeviceStatus);
    inline constexpr auto file_transfer_timeout     = 5000;
    constexpr auto notificationsClearTimerName      = "notificationsClearTimer";
    constexpr auto notificationsClearTimerDelayMs   = std::chrono::milliseconds{1000 * 20};
    constexpr auto connectionActiveTimerName        = "connectionActiveTimer";
    constexpr auto connectionActiveTimerDelayMs     = std::chrono::milliseconds{1000 * 20};
    inline constexpr auto RECEIVE_QUEUE_BUFFER_NAME = "receiveQueueBuffer";
    inline constexpr auto SEND_QUEUE_BUFFER_NAME    = "sendQueueBuffer";
    inline constexpr auto IRQ_QUEUE_BUFFER_NAME     = "irqQueueBuffer";


@@ 82,11 82,10 @@ class ServiceDesktop : public sys::Service

    auto getSerialNumber() const -> std::string;
    auto getCaseColour() const -> std::string;
    auto getDeviceToken() -> std::string;

    auto getNotificationEntries() const -> std::vector<Outbox::NotificationEntry>;
    void removeNotificationEntries(const std::vector<int> &);
    void restartNotificationsClearTimer();
    auto getDeviceToken() -> std::string;
    void removeNotificationEntries(const std::vector<uint32_t> &);

  private:
    auto getDeviceUniqueId() const -> std::string;


@@ 99,8 98,9 @@ class ServiceDesktop : public sys::Service
    std::unique_ptr<sdesktop::USBSecurityModel> usbSecurityModel;
    std::unique_ptr<settings::Settings> settings;
    std::unique_ptr<sdesktop::bluetooth::BluetoothMessagesHandler> btMsgHandler;
    sys::TimerHandle notificationsClearTimer;
    std::vector<Outbox::NotificationEntry> notificationEntries;
    OutboxNotifications outboxNotifications;
    sys::TimerHandle connectionActiveTimer;
    void restartConnectionActiveTimer();

    static constexpr unsigned int DefaultLogFlushTimeoutInMs = 1000U;
    bool initialized                                         = false;

M products/PurePhone/services/db/ServiceDB.cpp => products/PurePhone/services/db/ServiceDB.cpp +6 -6
@@ 91,7 91,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        record->push_back(msg->record);
        LOG_DEBUG("Last ID %" PRIu32, msg->record.ID);
        responseMsg = std::make_shared<DBContactResponseMessage>(std::move(record), ret);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Create);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Create, msg->record.ID);
    } break;

    case MessageType::DBContactGetByID: {


@@ 151,7 151,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        DBContactMessage *msg = reinterpret_cast<DBContactMessage *>(msgl);
        auto ret              = contactRecordInterface->RemoveByID(msg->id);
        responseMsg           = std::make_shared<DBContactResponseMessage>(nullptr, ret);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Delete);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Delete, msg->id);
    } break;

    case MessageType::DBContactUpdate: {


@@ 159,7 159,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        DBContactMessage *msg = reinterpret_cast<DBContactMessage *>(msgl);
        auto ret              = contactRecordInterface->Update(msg->record);
        responseMsg           = std::make_shared<DBContactResponseMessage>(nullptr, ret);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Update);
        sendUpdateNotification(db::Interface::Name::Contact, db::Query::Type::Update, msg->record.ID);
    } break;

        /**


@@ 179,7 179,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        record->push_back(msg->record);
        LOG_INFO("Last ID %" PRIu32, msg->record.ID);
        responseMsg = std::make_shared<DBCalllogResponseMessage>(std::move(record), ret);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Create);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Create, msg->record.ID);
    } break;

    case MessageType::DBCalllogRemove: {


@@ 187,7 187,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        DBCalllogMessage *msg = reinterpret_cast<DBCalllogMessage *>(msgl);
        auto ret              = calllogRecordInterface->RemoveByID(msg->id);
        responseMsg           = std::make_shared<DBCalllogResponseMessage>(nullptr, ret);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Delete);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Delete, msg->id);
    } break;

    case MessageType::DBCalllogUpdate: {


@@ 195,7 195,7 @@ sys::MessagePointer ServiceDB::DataReceivedHandler(sys::DataMessage *msgl, sys::
        DBCalllogMessage *msg = reinterpret_cast<DBCalllogMessage *>(msgl);
        auto ret              = calllogRecordInterface->Update(msg->record);
        responseMsg           = std::make_shared<DBCalllogResponseMessage>(nullptr, ret);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Update);
        sendUpdateNotification(db::Interface::Name::Calllog, db::Query::Type::Update, msg->record.ID);
    } break;

    case MessageType::DBServiceBackup: {

M products/PurePhone/services/desktop/endpoints/outbox/OutboxHelper.cpp => products/PurePhone/services/desktop/endpoints/outbox/OutboxHelper.cpp +3 -3
@@ 11,10 11,10 @@ namespace sdesktop::endpoints
{
    auto OutboxHelper::toJson(const Outbox::NotificationEntry &entry) -> json11::Json
    {
        auto notificationEntry = json11::Json::object{{json::outbox::uid, entry.uid},
        auto notificationEntry = json11::Json::object{{json::outbox::uid, static_cast<int>(entry.uid)},
                                                      {json::outbox::type, static_cast<int>(entry.entryType)},
                                                      {json::outbox::change, static_cast<int>(entry.entryChange)},
                                                      {json::outbox::record_id, entry.recordId}};
                                                      {json::outbox::record_id, static_cast<int>(entry.recordId)}};
        return notificationEntry;
    }



@@ 67,7 67,7 @@ namespace sdesktop::endpoints
        }

        auto entriesToBeRemoved = context.getBody()[json::entries].array_items();
        std::vector<int> uidsOfEntriesToBeRemoved;
        std::vector<uint32_t> uidsOfEntriesToBeRemoved;
        uidsOfEntriesToBeRemoved.reserve(entriesToBeRemoved.size());
        for (const auto &entryUid : entriesToBeRemoved) {
            uidsOfEntriesToBeRemoved.emplace_back(entryUid.int_value());