diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..25ed932 --- /dev/null +++ b/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: Google +IndentWidth: 4 \ No newline at end of file diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..7180be6 --- /dev/null +++ b/.clangd @@ -0,0 +1,3 @@ +CompileFlags: + #C++20 + Add: [-std=c++20] \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..684b757 --- /dev/null +++ b/.gitignore @@ -0,0 +1,59 @@ +# CMake generated files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +Makefile +*.cmake +compile_commands.json + +# Build directories +build/ +cmake-build-*/ +out/ +bin/ +lib/ + +# C++ build artifacts +*.o +*.obj +*.exe +*.dll +*.so +*.dylib +*.a +*.lib + +# IDE and editor files +.vscode/settings.json +*.swp +*.swo +*~ +.idea/ +*.sublime-project +*.sublime-workspace + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Temporary files +*.tmp +*.temp +*.log + +# Package files +*.deb +*.rpm +*.tar.gz +*.zip + +# cache +.cache + +# binary +sub_notifs \ No newline at end of file diff --git a/subscriber-notifs/CMakeLists.txt b/subscriber-notifs/CMakeLists.txt index a67303f..672188e 100644 --- a/subscriber-notifs/CMakeLists.txt +++ b/subscriber-notifs/CMakeLists.txt @@ -4,11 +4,11 @@ project(subscriber-notifs VERSION 1.0) set(CMAKE_CXX_STANDARD 20) file(GLOB_RECURSE SRC_FILES "src/*.cpp") -file(GLOB_RECURSE HEADER_FILES "src/*.h" "src/*.hpp") +file(GLOB_RECURSE HEADER_FILES "include/*.hpp") add_executable(sub_notifs ${SRC_FILES} ${HEADER_FILES}) -target_include_directories(sub_notifs PRIVATE ${HEADER_FILES}) +target_include_directories(sub_notifs PRIVATE include ) # from: https://cmake.org/cmake/help/latest/module/FindThreads.html find_package(Threads REQUIRED) diff --git a/subscriber-notifs/include/app/inventory_manager.hpp b/subscriber-notifs/include/app/inventory_manager.hpp new file mode 100644 index 0000000..9584b71 --- /dev/null +++ b/subscriber-notifs/include/app/inventory_manager.hpp @@ -0,0 +1,20 @@ + +#pragma once + +#include +#include + +#include "core/subscribable.hpp" + +using ProductCount = int; +using ProductId = std::string; + +// inventory manager is not generic ( works with the specific types ProductId +// and ProductCount ) but the subscribable is generic +class InventoryManager : public Subscribable { + private: + std::unordered_map inventory_; + + public: + void setInventory(const ProductId& productId, ProductCount quantity); +}; \ No newline at end of file diff --git a/subscriber-notifs/include/app/services.hpp b/subscriber-notifs/include/app/services.hpp new file mode 100644 index 0000000..71f3331 --- /dev/null +++ b/subscriber-notifs/include/app/services.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "app/inventory_manager.hpp" +#include "core/subscriber.hpp" + +class SmsService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; + +class EmailService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; + +class LogService : public Subscriber { + public: + void onNotification(const ProductId& productId, + const ProductCount& quantity) override; +}; \ No newline at end of file diff --git a/subscriber-notifs/include/core/subscribable.hpp b/subscriber-notifs/include/core/subscribable.hpp new file mode 100644 index 0000000..ad9a131 --- /dev/null +++ b/subscriber-notifs/include/core/subscribable.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "subscriber.hpp" + +template +class Subscribable { + using TSubscriber = Subscriber; + + private: + std::unordered_map> subscribersMap_; + + public: + void subscribe(const TEventId& eventId, TSubscriber* subscriber) { + subscribersMap_[eventId].push_back(subscriber); + } + + void unsubscribe(const TEventId& eventId, TSubscriber* subscriber) { + auto entry = subscribersMap_.find(eventId); + if (entry == subscribersMap_.end()) { + return; + } + + std::erase(entry->second, subscriber); + if (entry->second.empty()) { + subscribersMap_.erase(entry); + } + } + + void notify(const TEventId& eventId, const TEventInfo& eventInfo) { + auto entry = subscribersMap_.find(eventId); + if (entry == subscribersMap_.end()) { + return; + } + + for (TSubscriber* subscriber : entry->second) { + subscriber->onNotification(eventId, eventInfo); + } + } +}; \ No newline at end of file diff --git a/subscriber-notifs/include/core/subscriber.hpp b/subscriber-notifs/include/core/subscriber.hpp new file mode 100644 index 0000000..af02316 --- /dev/null +++ b/subscriber-notifs/include/core/subscriber.hpp @@ -0,0 +1,10 @@ +#pragma once + +template +class Subscriber { + public: + virtual void onNotification(const TEventId& eventId, + const TEventInfo& eventInfo) = 0; + + virtual ~Subscriber() = default; +}; \ No newline at end of file diff --git a/subscriber-notifs/src/app/inventory_manager.cpp b/subscriber-notifs/src/app/inventory_manager.cpp new file mode 100644 index 0000000..7962c68 --- /dev/null +++ b/subscriber-notifs/src/app/inventory_manager.cpp @@ -0,0 +1,7 @@ +#include "app/inventory_manager.hpp" + +void InventoryManager::setInventory(const ProductId& productId, + ProductCount quantity) { + inventory_[productId] = quantity; + this->notify(productId, quantity); +} \ No newline at end of file diff --git a/subscriber-notifs/src/app/services.cpp b/subscriber-notifs/src/app/services.cpp new file mode 100644 index 0000000..ead7301 --- /dev/null +++ b/subscriber-notifs/src/app/services.cpp @@ -0,0 +1,21 @@ +#include "app/services.hpp" + +#include + +void SmsService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "SMS Notification - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} + +void EmailService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "Email Notification - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} + +void LogService::onNotification(const ProductId& productId, + const ProductCount& quantity) { + std::cout << "Log Entry - Product: " << productId + << ", Quantity: " << quantity << std::endl; +} \ No newline at end of file diff --git a/subscriber-notifs/src/main.cpp b/subscriber-notifs/src/main.cpp new file mode 100644 index 0000000..65e7368 --- /dev/null +++ b/subscriber-notifs/src/main.cpp @@ -0,0 +1,19 @@ +#include "app/inventory_manager.hpp" +#include "app/services.hpp" + +int main() { + InventoryManager inventoryManager; + + SmsService smsService; + EmailService emailService; + LogService logService; + + inventoryManager.subscribe("ProductA", &smsService); + inventoryManager.subscribe("ProductB", &emailService); + inventoryManager.subscribe("ProductA", &logService); + + inventoryManager.setInventory("ProductA", 100); + inventoryManager.setInventory("ProductB", 200); + + return 0; +} \ No newline at end of file