From 9fdb5a5b6f6ed1023d0062712ccbc679a30bac44 Mon Sep 17 00:00:00 2001
From: "Christian R. G. Dreher" <c.dreher@kit.edu>
Date: Tue, 27 Jul 2021 14:45:20 +0200
Subject: [PATCH] refactor: Simplify/unify naming schemes. Implement general
 event handler.

---
 .../components/Navigator/Navigator.cpp        |  8 +-
 .../libraries/client/ComponentPlugin.cpp      |  6 +-
 .../libraries/client/ComponentPlugin.h        |  5 +-
 .../Navigation/libraries/client/Navigator.cpp | 62 +++++++------
 .../Navigation/libraries/client/Navigator.h   | 65 +++++++++-----
 .../services/EventSubscriptionInterface.h     | 27 +++++-
 .../client/services/MemorySubscriber.cpp      | 43 +++++++++
 .../client/services/MemorySubscriber.h        | 20 +++--
 .../client/services/SimpleEventHandler.cpp    | 90 +++++++++++++++++--
 .../client/services/SimpleEventHandler.h      | 31 +++++--
 .../Navigation/libraries/core/CMakeLists.txt  |  1 +
 source/Navigation/libraries/core/events.h     | 49 ++++++++++
 .../libraries/server/CMakeLists.txt           |  2 +
 .../Navigation/libraries/server/Navigator.cpp |  2 +-
 .../Navigation/libraries/server/Navigator.h   | 63 ++++++-------
 .../EventPublishingInterface.h                | 62 ++++++-------
 .../event_publishing/MemoryPublisher.cpp      | 43 +++++++++
 .../server/event_publishing/MemoryPublisher.h | 20 +++--
 .../libraries/server/test/serverTest.cpp      | 11 +--
 19 files changed, 441 insertions(+), 169 deletions(-)
 create mode 100644 source/Navigation/libraries/core/events.h
 create mode 100644 source/Navigation/libraries/server/event_publishing/MemoryPublisher.cpp

diff --git a/source/Navigation/components/Navigator/Navigator.cpp b/source/Navigation/components/Navigator/Navigator.cpp
index 06d38423..67d6819b 100644
--- a/source/Navigation/components/Navigator/Navigator.cpp
+++ b/source/Navigation/components/Navigator/Navigator.cpp
@@ -171,17 +171,15 @@ armarx::nav::components::Navigator::createConfig(const aron::data::AronDictPtr&
 
     server::NavigationStack stack = fac::NavigationStackFactory::create(stackConfig, scene);
 
-    server::GeneralConfig generalConfig;
-
     memoryIntrospectors.emplace_back(
         std::make_unique<server::MemoryIntrospector>(writerGlobPlan, callerId));
 
     navigators.emplace(std::piecewise_construct,
                        std::forward_as_tuple(callerId),
-                       std::forward_as_tuple(server::NavigatorConfig{.stack = std::move(stack),
+                       std::forward_as_tuple(server::Navigator::Config{.stack = std::move(stack),
                                                .scene = &scene,
-                                               .general = generalConfig},
-                       server::Services{.executor = &executor.value(),
+                                               .general = server::Navigator::Config::General{}},
+                       server::Navigator::InjectedServices{.executor = &executor.value(),
                                         .publisher = &publisher,
                                         .introspector = &(introspector.value())}));
 }
diff --git a/source/Navigation/libraries/client/ComponentPlugin.cpp b/source/Navigation/libraries/client/ComponentPlugin.cpp
index 8805b0d2..c817b740 100644
--- a/source/Navigation/libraries/client/ComponentPlugin.cpp
+++ b/source/Navigation/libraries/client/ComponentPlugin.cpp
@@ -36,13 +36,13 @@ armarx::nav::client::ComponentPlugin::preOnConnectComponent()
 
     ARMARX_TRACE;
     const std::string componentName = parent().getName();
-    IceNavigator& srv = parent<armarx::nav::client::ComponentPluginUser>().navigatorService;
+    IceNavigator& srv = parent<armarx::nav::client::ComponentPluginUser>().iceNavigator;
     srv.setNavigatorComponent(navigatorPrx);
 }
 
 // ComponentPluginUser
 
-armarx::nav::client::ComponentPluginUser::ComponentPluginUser() : navigator{navigatorService}
+armarx::nav::client::ComponentPluginUser::ComponentPluginUser() : navigator{navigatorServices}
 {
     ARMARX_TRACE;
     addPlugin(plugin);
@@ -60,7 +60,7 @@ armarx::nav::client::ComponentPluginUser::configureNavigator(
     const client::NavigationStackConfig& stackConfig,
     const std::string& configId)
 {
-    navigatorService.createConfig(stackConfig, configId);
+    iceNavigator.createConfig(stackConfig, configId);
 }
 
 armarx::nav::client::ComponentPluginUser::~ComponentPluginUser() = default;
diff --git a/source/Navigation/libraries/client/ComponentPlugin.h b/source/Navigation/libraries/client/ComponentPlugin.h
index 6124d474..da4be5de 100644
--- a/source/Navigation/libraries/client/ComponentPlugin.h
+++ b/source/Navigation/libraries/client/ComponentPlugin.h
@@ -8,6 +8,7 @@
 #include <Navigation/components/Navigator/NavigatorInterface.h>
 #include <Navigation/libraries/client/Navigator.h>
 #include <Navigation/libraries/client/services/IceNavigator.h>
+#include <Navigation/libraries/client/services/MemorySubscriber.h>
 
 namespace armarx::nav::client
 {
@@ -53,7 +54,9 @@ namespace armarx::nav::client
         friend class ComponentPlugin;
 
     private:
-        IceNavigator navigatorService;
+        IceNavigator iceNavigator;
+        MemorySubscriber memorySubscriber;
+        Navigator::InjectedServices navigatorServices{.navigator = &iceNavigator, .subscriber = &memorySubscriber};
 
         ComponentPlugin* plugin = nullptr;
     };
diff --git a/source/Navigation/libraries/client/Navigator.cpp b/source/Navigation/libraries/client/Navigator.cpp
index e503fa95..fae701c9 100644
--- a/source/Navigation/libraries/client/Navigator.cpp
+++ b/source/Navigation/libraries/client/Navigator.cpp
@@ -3,10 +3,18 @@
 #include "ArmarXCore/core/exceptions/local/ExpressionException.h"
 
 
-armarx::nav::client::Navigator::Navigator(core::NavigatorInterface& navigator) :
-    navigator{&navigator}
+armarx::nav::client::Navigator::Navigator(const InjectedServices& services) :
+    srv{services}
 {
-    // pass
+    ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
+    ARMARX_CHECK_NOT_NULL(srv.subscriber) << "Subscriber service must not be null!";
+
+    auto stopped_callback = [this](const auto& e) { stopped(StopEvent(e)); };
+
+    srv.subscriber->onGoalReached(stopped_callback);
+    srv.subscriber->onSafetyStopTriggered(stopped_callback);
+    srv.subscriber->onUserAbortTriggered(stopped_callback);
+    srv.subscriber->onInternalError(stopped_callback);
 }
 
 
@@ -21,8 +29,7 @@ void
 armarx::nav::client::Navigator::moveTo(const std::vector<core::Pose>& waypoints,
                                        core::NavigationFrame frame)
 {
-    ARMARX_CHECK_NOT_NULL(navigator);
-    navigator->moveTo(waypoints, frame);
+    srv.navigator->moveTo(waypoints, frame);
 }
 
 
@@ -30,45 +37,41 @@ void
 armarx::nav::client::Navigator::moveTowards(const core::Direction& direction,
                                             core::NavigationFrame frame)
 {
-    ARMARX_CHECK_NOT_NULL(navigator);
-    navigator->moveTowards(direction, frame);
+    srv.navigator->moveTowards(direction, frame);
 }
 
 
 void
 armarx::nav::client::Navigator::pause()
 {
-    ARMARX_CHECK_NOT_NULL(navigator);
-    navigator->pause();
+    srv.navigator->pause();
 }
 
 
 void
 armarx::nav::client::Navigator::resume()
 {
-    ARMARX_CHECK_NOT_NULL(navigator);
-    navigator->resume();
+    srv.navigator->resume();
 }
 
 
 void
 armarx::nav::client::Navigator::stop()
 {
-    ARMARX_CHECK_NOT_NULL(navigator);
-    navigator->stop();
+    srv.navigator->stop();
 }
 
 
 void
 armarx::nav::client::Navigator::onGoalReached(const std::function<void(void)>& callback)
 {
-    onGoalReached([&callback](const server::GoalReachedEvent&) { callback(); });
+    onGoalReached([&callback](const core::GoalReachedEvent&) { callback(); });
 }
 
 
 void
 armarx::nav::client::Navigator::onGoalReached(
-    const std::function<void(const server::GoalReachedEvent&)>& callback)
+    const std::function<void(const core::GoalReachedEvent&)>& callback)
 {
 }
 
@@ -79,21 +82,24 @@ armarx::nav::client::Navigator::onWaypointReached(const std::function<void(int)>
 }
 
 
-// TODO: Remove after fixing waitForGoalReached
-#include <chrono>
-#include <thread>
-
 armarx::nav::client::StopEvent
 armarx::nav::client::Navigator::waitForStop()
 {
-    // TODO: Actually implement this.
-    bool stopped = false;
-    do
-    {
-        std::this_thread::sleep_for(std::chrono::milliseconds{10});
-        stopped = navigator->isStopped();
-    } while (not stopped);
+    std::unique_lock l{stoppedInfo.m};
+    stoppedInfo.cv.wait(l, [&i = stoppedInfo]{ return i.event.has_value(); });
+
+    StopEvent e = stoppedInfo.event.value();
+    stoppedInfo.event.reset();
+    return e;
+}
+
 
-    StopEvent se = server::GoalReachedEvent{.pose = core::Pose::Identity()};
-    return se;
+void
+armarx::nav::client::Navigator::stopped(const StopEvent& e)
+{
+    {
+        std::scoped_lock l{stoppedInfo.m};
+        stoppedInfo.event = e;
+    }
+    stoppedInfo.cv.notify_all();
 }
diff --git a/source/Navigation/libraries/client/Navigator.h b/source/Navigation/libraries/client/Navigator.h
index 53617e72..07472bb9 100644
--- a/source/Navigation/libraries/client/Navigator.h
+++ b/source/Navigation/libraries/client/Navigator.h
@@ -23,7 +23,10 @@
 #pragma once
 
 // STD/STL
+#include <condition_variable>
 #include <functional>
+#include <mutex>
+#include <optional>
 #include <string>
 #include <variant>
 #include <vector>
@@ -31,7 +34,8 @@
 // Navigation
 #include <Navigation/libraries/core/NavigatorInterface.h>
 #include <Navigation/libraries/core/types.h>
-#include <Navigation/libraries/server/event_publishing/EventPublishingInterface.h>
+#include <Navigation/libraries/core/events.h>
+#include <Navigation/libraries/client/services/EventSubscriptionInterface.h>
 
 namespace armarx::nav::client
 {
@@ -48,49 +52,49 @@ namespace armarx::nav::client
         bool
         isGoalReachedEvent() const
         {
-            return std::holds_alternative<server::GoalReachedEvent>(event);
+            return std::holds_alternative<core::GoalReachedEvent>(event);
         }
 
-        server::GoalReachedEvent&
+        core::GoalReachedEvent&
         toGoalReachedEvent()
         {
-            return std::get<server::GoalReachedEvent>(event);
+            return std::get<core::GoalReachedEvent>(event);
         }
 
         bool
         isSafetyStopTriggeredEvent() const
         {
-            return std::holds_alternative<server::SafetyStopTriggeredEvent>(event);
+            return std::holds_alternative<core::SafetyStopTriggeredEvent>(event);
         }
 
-        server::SafetyStopTriggeredEvent&
+        core::SafetyStopTriggeredEvent&
         toSafetyStopTriggeredEvent()
         {
-            return std::get<server::SafetyStopTriggeredEvent>(event);
+            return std::get<core::SafetyStopTriggeredEvent>(event);
         }
 
         bool
         isUserAbortTriggeredEvent() const
         {
-            return std::holds_alternative<server::UserAbortTriggeredEvent>(event);
+            return std::holds_alternative<core::UserAbortTriggeredEvent>(event);
         }
 
-        server::UserAbortTriggeredEvent&
+        core::UserAbortTriggeredEvent&
         toUserAbortTriggeredEvent()
         {
-            return std::get<server::UserAbortTriggeredEvent>(event);
+            return std::get<core::UserAbortTriggeredEvent>(event);
         }
 
         bool
         isInternalErrorEvent() const
         {
-            return std::holds_alternative<server::InternalErrorEvent>(event);
+            return std::holds_alternative<core::InternalErrorEvent>(event);
         }
 
-        server::InternalErrorEvent&
+        core::InternalErrorEvent&
         toInternalErrorEvent()
         {
-            return std::get<server::InternalErrorEvent>(event);
+            return std::get<core::InternalErrorEvent>(event);
         }
 
         operator bool() const
@@ -99,10 +103,10 @@ namespace armarx::nav::client
         }
 
     private:
-        using StopEventVar = std::variant<server::GoalReachedEvent,
-                                          server::SafetyStopTriggeredEvent,
-                                          server::UserAbortTriggeredEvent,
-                                          server::InternalErrorEvent>;
+        using StopEventVar = std::variant<core::GoalReachedEvent,
+                                          core::SafetyStopTriggeredEvent,
+                                          core::UserAbortTriggeredEvent,
+                                          core::InternalErrorEvent>;
         StopEventVar event;
     };
 
@@ -111,7 +115,15 @@ namespace armarx::nav::client
     {
 
     public:
-        Navigator(core::NavigatorInterface& navigator);
+
+        struct InjectedServices
+        {
+            core::NavigatorInterface* navigator;
+            EventSubscriptionInterface* subscriber;
+        };
+
+    public:
+        Navigator(const InjectedServices& services);
 
         void moveTo(const core::Pose& pose, core::NavigationFrame frame);
 
@@ -127,7 +139,7 @@ namespace armarx::nav::client
 
         void onGoalReached(const std::function<void(void)>& callback);
 
-        void onGoalReached(const std::function<void(const server::GoalReachedEvent&)>& callback);
+        void onGoalReached(const std::function<void(const core::GoalReachedEvent&)>& callback);
 
         void onWaypointReached(const std::function<void(int)>& callback);
 
@@ -135,12 +147,17 @@ namespace armarx::nav::client
 
     protected:
     private:
-        core::NavigatorInterface* navigator;
 
-        struct
-        {
-            std::vector<std::function<void(void)>> goalReached;
-        } callbacks;
+        void stopped(const StopEvent&);
+
+        struct {
+            std::mutex m;
+            std::condition_variable cv;
+            std::optional<StopEvent> event;
+        } stoppedInfo;
+
+        InjectedServices srv;
+
     };
 
 } // namespace armarx::nav::client
diff --git a/source/Navigation/libraries/client/services/EventSubscriptionInterface.h b/source/Navigation/libraries/client/services/EventSubscriptionInterface.h
index ab74fbb8..12879895 100644
--- a/source/Navigation/libraries/client/services/EventSubscriptionInterface.h
+++ b/source/Navigation/libraries/client/services/EventSubscriptionInterface.h
@@ -1,18 +1,39 @@
 #pragma once
 
-#include <Navigation/libraries/server/event_publishing/EventPublishingInterface.h>
+
+// STD/STL
+#include <functional>
+
+// Navigation
+#include <Navigation/libraries/core/events.h>
+
 
 namespace armarx::nav::client
 {
 
+    using OnGoalReachedCallback = std::function<void(const core::GoalReachedEvent&)>;
+    using OnWaypointReachedCallback = std::function<void(const core::WaypointReachedEvent&)>;
+    using OnSafetyThrottlingTriggeredCallback = std::function<void(const core::SafetyThrottlingTriggeredEvent&)>;
+    using OnSafetyStopTriggeredCallback = std::function<void(const core::SafetyStopTriggeredEvent&)>;
+    using OnUserAbortTriggeredCallback = std::function<void(const core::UserAbortTriggeredEvent&)>;
+    using OnInternalErrorCallback = std::function<void(const core::InternalErrorEvent&)>;
+
     class EventSubscriptionInterface
     {
 
     public:
 
-        virtual void onGoalReached(const server::GoalReachedEvent&) = 0;
+        virtual void onGoalReached(const OnGoalReachedCallback& callback) = 0;
+
+        virtual void onWaypointReached(const OnWaypointReachedCallback& callback) = 0;
+
+        virtual void onSafetyThrottlingTriggered(const OnSafetyThrottlingTriggeredCallback& callback) = 0;
+
+        virtual void onSafetyStopTriggered(const OnSafetyStopTriggeredCallback& callback) = 0;
+
+        virtual void onUserAbortTriggered(const OnUserAbortTriggeredCallback& callback) = 0;
 
-        virtual void onWaypointReached(const server::WaypointReachedEvent&) = 0;
+        virtual void onInternalError(const OnInternalErrorCallback& callback) = 0;
 
         // Non-API.
     public:
diff --git a/source/Navigation/libraries/client/services/MemorySubscriber.cpp b/source/Navigation/libraries/client/services/MemorySubscriber.cpp
index e69de29b..c7ff5ebd 100644
--- a/source/Navigation/libraries/client/services/MemorySubscriber.cpp
+++ b/source/Navigation/libraries/client/services/MemorySubscriber.cpp
@@ -0,0 +1,43 @@
+#include <Navigation/libraries/client/services/MemorySubscriber.h>
+
+
+void
+armarx::nav::client::MemorySubscriber::onGoalReached(const OnGoalReachedCallback& callback)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::client::MemorySubscriber::onWaypointReached(const OnWaypointReachedCallback& callback)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::client::MemorySubscriber::onSafetyThrottlingTriggered(const OnSafetyThrottlingTriggeredCallback& callback)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::client::MemorySubscriber::onSafetyStopTriggered(const OnSafetyStopTriggeredCallback& callback)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::client::MemorySubscriber::onUserAbortTriggered(const OnUserAbortTriggeredCallback& callback)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::client::MemorySubscriber::onInternalError(const OnInternalErrorCallback& callback)
+{
+    // TODO: Implement.
+}
diff --git a/source/Navigation/libraries/client/services/MemorySubscriber.h b/source/Navigation/libraries/client/services/MemorySubscriber.h
index c8431ac7..1a9a6357 100644
--- a/source/Navigation/libraries/client/services/MemorySubscriber.h
+++ b/source/Navigation/libraries/client/services/MemorySubscriber.h
@@ -1,7 +1,9 @@
 #pragma once
 
+
 #include <Navigation/libraries/client/services/EventSubscriptionInterface.h>
 
+
 namespace armarx::nav::client
 {
 
@@ -10,15 +12,17 @@ namespace armarx::nav::client
 
     public:
 
-        void onGoalReached(const server::GoalReachedEvent&) override
-        {
-            // TODO: Implement.
-        }
+        void onGoalReached(const OnGoalReachedCallback& callback) override;
+
+        void onWaypointReached(const OnWaypointReachedCallback& callback) override;
+
+        void onSafetyThrottlingTriggered(const OnSafetyThrottlingTriggeredCallback& callback) override;
+
+        void onSafetyStopTriggered(const OnSafetyStopTriggeredCallback& callback) override;
+
+        void onUserAbortTriggered(const OnUserAbortTriggeredCallback& callback) override;
 
-        void onWaypointReached(const server::WaypointReachedEvent&) override
-        {
-            // TODO: Implement.
-        }
+        void onInternalError(const OnInternalErrorCallback& callback) override;
 
         // Non-API.
     public:
diff --git a/source/Navigation/libraries/client/services/SimpleEventHandler.cpp b/source/Navigation/libraries/client/services/SimpleEventHandler.cpp
index a5311804..dcb21d0d 100644
--- a/source/Navigation/libraries/client/services/SimpleEventHandler.cpp
+++ b/source/Navigation/libraries/client/services/SimpleEventHandler.cpp
@@ -2,28 +2,102 @@
 
 
 void
-armarx::nav::client::SimpleEventHandler::onGoalReached(const server::GoalReachedEvent&)
+armarx::nav::client::SimpleEventHandler::onGoalReached(const OnGoalReachedCallback& callback)
 {
-    // TODO: Implement.
+    subscriptions.goalReachedCallbacks.push_back(callback);
 }
 
 
 void
-armarx::nav::client::SimpleEventHandler::onWaypointReached(const server::WaypointReachedEvent&)
+armarx::nav::client::SimpleEventHandler::onWaypointReached(const OnWaypointReachedCallback& callback)
 {
-    // TODO: Implement.
+    subscriptions.waypointReachedCallbacks.push_back(callback);
 }
 
 
 void
-armarx::nav::client::SimpleEventHandler::goalReached(const server::GoalReachedEvent&)
+armarx::nav::client::SimpleEventHandler::onSafetyThrottlingTriggered(const OnSafetyThrottlingTriggeredCallback& callback)
 {
-    // TODO: Implement.
+    subscriptions.safetyThrottlingTriggeredCallbacks.push_back(callback);
 }
 
 
 void
-armarx::nav::client::SimpleEventHandler::waypointReached(const server::WaypointReachedEvent&)
+armarx::nav::client::SimpleEventHandler::onSafetyStopTriggered(const OnSafetyStopTriggeredCallback& callback)
 {
-    // TODO: Implement.
+    subscriptions.safetyStopTriggeredCallbacks.push_back(callback);
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::onUserAbortTriggered(const OnUserAbortTriggeredCallback& callback)
+{
+    subscriptions.userAbortTriggeredCallbacks.push_back(callback);
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::onInternalError(const OnInternalErrorCallback& callback)
+{
+    subscriptions.internalErrorCallbacks.push_back(callback);
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::goalReached(const core::GoalReachedEvent& event)
+{
+    for (const auto& callback : subscriptions.goalReachedCallbacks)
+    {
+        callback(event);
+    }
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::waypointReached(const core::WaypointReachedEvent& event)
+{
+    for (const auto& callback : subscriptions.waypointReachedCallbacks)
+    {
+        callback(event);
+    }
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::safetyThrottlingTriggered(const core::SafetyThrottlingTriggeredEvent& event)
+{
+    for (const auto& callback : subscriptions.safetyThrottlingTriggeredCallbacks)
+    {
+        callback(event);
+    }
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::safetyStopTriggered(const core::SafetyStopTriggeredEvent& event)
+{
+    for (const auto& callback : subscriptions.safetyStopTriggeredCallbacks)
+    {
+        callback(event);
+    }
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::userAbortTriggered(const core::UserAbortTriggeredEvent& event)
+{
+    for (const auto& callback : subscriptions.userAbortTriggeredCallbacks)
+    {
+        callback(event);
+    }
+}
+
+
+void
+armarx::nav::client::SimpleEventHandler::internalError(const core::InternalErrorEvent& event)
+{
+    for (const auto& callback : subscriptions.internalErrorCallbacks)
+    {
+        callback(event);
+    }
 }
diff --git a/source/Navigation/libraries/client/services/SimpleEventHandler.h b/source/Navigation/libraries/client/services/SimpleEventHandler.h
index dc700f2a..3e52a36e 100644
--- a/source/Navigation/libraries/client/services/SimpleEventHandler.h
+++ b/source/Navigation/libraries/client/services/SimpleEventHandler.h
@@ -1,8 +1,10 @@
 #pragma once
 
+
 #include <Navigation/libraries/client/services/EventSubscriptionInterface.h>
 #include <Navigation/libraries/server/event_publishing/EventPublishingInterface.h>
 
+
 namespace armarx::nav::client
 {
 
@@ -11,20 +13,35 @@ namespace armarx::nav::client
             virtual public server::EventPublishingInterface
     {
 
-        // EventSubscriptionInterface interface
+        // EventSubscriptionInterface
     public:
-        void onGoalReached(const server::GoalReachedEvent&) override;
-        void onWaypointReached(const server::WaypointReachedEvent&) override;
 
-        // EventPublishingInterface interface
+        void onGoalReached(const OnGoalReachedCallback& callback) override;
+        void onWaypointReached(const OnWaypointReachedCallback& callback) override;
+        void onSafetyThrottlingTriggered(const OnSafetyThrottlingTriggeredCallback& callback) override;
+        void onSafetyStopTriggered(const OnSafetyStopTriggeredCallback& callback) override;
+        void onUserAbortTriggered(const OnUserAbortTriggeredCallback& callback) override;
+        void onInternalError(const OnInternalErrorCallback& callback) override;
+
+        // EventPublishingInterface
     public:
-        void goalReached(const server::GoalReachedEvent&) override;
-        void waypointReached(const server::WaypointReachedEvent&) override;
+
+        void goalReached(const core::GoalReachedEvent& event) override;
+        void waypointReached(const core::WaypointReachedEvent& event) override;
+        void safetyThrottlingTriggered(const core::SafetyThrottlingTriggeredEvent& event) override;
+        void safetyStopTriggered(const core::SafetyStopTriggeredEvent& event) override;
+        void userAbortTriggered(const core::UserAbortTriggeredEvent& event) override;
+        void internalError(const core::InternalErrorEvent& event) override;
 
     private:
 
         struct {
-            bool todo;
+            std::vector<OnGoalReachedCallback> goalReachedCallbacks;
+            std::vector<OnWaypointReachedCallback> waypointReachedCallbacks;
+            std::vector<OnSafetyThrottlingTriggeredCallback> safetyThrottlingTriggeredCallbacks;
+            std::vector<OnSafetyStopTriggeredCallback> safetyStopTriggeredCallbacks;
+            std::vector<OnUserAbortTriggeredCallback> userAbortTriggeredCallbacks;
+            std::vector<OnInternalErrorCallback> internalErrorCallbacks;
         } subscriptions;
 
     };
diff --git a/source/Navigation/libraries/core/CMakeLists.txt b/source/Navigation/libraries/core/CMakeLists.txt
index 5294b45f..e0e3b1bc 100644
--- a/source/Navigation/libraries/core/CMakeLists.txt
+++ b/source/Navigation/libraries/core/CMakeLists.txt
@@ -20,6 +20,7 @@ armarx_add_library(
         aron_conversions.cpp
     HEADERS
         types.h
+        events.h
         NavigatorInterface.h
         MemoryReferencedElement.h
         # scenes
diff --git a/source/Navigation/libraries/core/events.h b/source/Navigation/libraries/core/events.h
new file mode 100644
index 00000000..29797d34
--- /dev/null
+++ b/source/Navigation/libraries/core/events.h
@@ -0,0 +1,49 @@
+#pragma once
+
+
+// STD/STL
+#include <string>
+
+// Navigation
+#include <Navigation/libraries/core/types.h>
+
+
+namespace armarx::nav::core
+{
+
+    struct GoalReachedEvent
+    {
+        core::Pose pose;
+    };
+
+    struct WaypointReachedEvent
+    {
+        core::Pose pose;
+        int waypointId;
+    };
+
+    struct SafetyThrottlingTriggeredEvent
+    {
+        core::Pose pose;
+        float throttlingFactor = 1.0;
+        // TODO: Direction where safety-critical obstacle is (or range or whatever...).
+    };
+
+    struct SafetyStopTriggeredEvent
+    {
+        core::Pose pose;
+        // TODO: Direction where safety-critical obstacle is (or range or whatever...).
+    };
+
+    struct UserAbortTriggeredEvent
+    {
+        core::Pose pose;
+    };
+
+    struct InternalErrorEvent
+    {
+        core::Pose pose;
+        std::string message;
+    };
+
+} // namespace armarx::nav::core
diff --git a/source/Navigation/libraries/server/CMakeLists.txt b/source/Navigation/libraries/server/CMakeLists.txt
index e8256122..321f8694 100644
--- a/source/Navigation/libraries/server/CMakeLists.txt
+++ b/source/Navigation/libraries/server/CMakeLists.txt
@@ -19,6 +19,8 @@ armarx_add_library(
         ./StackResult.cpp
         # Executors.
         ./execution/PlatformUnitExecutor.cpp
+        # Event publishing.
+        ./event_publishing/MemoryPublisher.cpp
         # Introspection
         ./introspection/ArvizIntrospector.cpp
         ./introspection/MemoryIntrospector.cpp
diff --git a/source/Navigation/libraries/server/Navigator.cpp b/source/Navigation/libraries/server/Navigator.cpp
index cb67fcf1..57950493 100644
--- a/source/Navigation/libraries/server/Navigator.cpp
+++ b/source/Navigation/libraries/server/Navigator.cpp
@@ -25,7 +25,7 @@ namespace armarx::nav::server
         }
     }
 
-    Navigator::Navigator(const NavigatorConfig& config, const Services& services) : config{config}, srv{services}
+    Navigator::Navigator(const Config& config, const InjectedServices& services) : config{config}, srv{services}
     {
         ARMARX_CHECK_NOT_NULL(config.scene) << "The scene must be set!";
         ARMARX_CHECK_NOT_NULL(services.executor) << "The executor service must be set!";
diff --git a/source/Navigation/libraries/server/Navigator.h b/source/Navigation/libraries/server/Navigator.h
index 0c601b28..915bcb49 100644
--- a/source/Navigation/libraries/server/Navigator.h
+++ b/source/Navigation/libraries/server/Navigator.h
@@ -48,39 +48,42 @@
 namespace armarx::nav::server
 {
 
-    struct GeneralConfig
-    {
-        struct
-        {
-            // TODO: Use chrono?
-            int localPlanningUpdatePeriod{10};         // [ms]
-            int trajectoryControllerUpdatePeriod{100}; // [ms]
-            int safetyControllerUpdatePeriod{100};     // [ms]
-            int introspectorUpdatePeriod{10};          // [ms]
-            int executorUpdatePeriod{100};             // [ms]
-            int monitorUpdatePeriod{20};               // [ms]
-        } tasks;
-    };
-
-    struct NavigatorConfig
+    class Navigator : virtual public core::NavigatorInterface
     {
-        server::NavigationStack stack;
-        core::Scene* const scene;
-        GeneralConfig general;
-    };
 
-    struct Services
-    {
-        ExecutorInterface* executor;
-        EventPublishingInterface* publisher;
-        IntrospectorInterface* introspector = nullptr;
-    };
+    public:
 
-    class Navigator : virtual public core::NavigatorInterface
-    {
+        struct Config
+        {
+            struct General
+            {
+                struct
+                {
+                    // TODO: Use chrono?
+                    int localPlanningUpdatePeriod{10};         // [ms]
+                    int trajectoryControllerUpdatePeriod{100}; // [ms]
+                    int safetyControllerUpdatePeriod{100};     // [ms]
+                    int introspectorUpdatePeriod{10};          // [ms]
+                    int executorUpdatePeriod{100};             // [ms]
+                    int monitorUpdatePeriod{20};               // [ms]
+                } tasks;
+            };
+
+            server::NavigationStack stack;
+            core::Scene* const scene;
+            General general;
+        };
+
+        struct InjectedServices
+        {
+            ExecutorInterface* executor;
+            EventPublishingInterface* publisher;
+            IntrospectorInterface* introspector = nullptr;
+        };
 
     public:
-        Navigator(const NavigatorConfig& config, const Services& services);
+
+        Navigator(const Config& config, const InjectedServices& services);
 
         void moveTo(const std::vector<core::Pose>& waypoints,
                     core::NavigationFrame navigationFrame) override;
@@ -121,9 +124,9 @@ namespace armarx::nav::server
 
         void stopAllThreads();
 
-        NavigatorConfig config;
+        Config config;
 
-        Services srv;
+        InjectedServices srv;
 
         std::atomic_bool executorEnabled = true;
 
diff --git a/source/Navigation/libraries/server/event_publishing/EventPublishingInterface.h b/source/Navigation/libraries/server/event_publishing/EventPublishingInterface.h
index b34774b5..b0e6f9cf 100644
--- a/source/Navigation/libraries/server/event_publishing/EventPublishingInterface.h
+++ b/source/Navigation/libraries/server/event_publishing/EventPublishingInterface.h
@@ -1,43 +1,11 @@
 #pragma once
 
-#include <Navigation/libraries/core/types.h>
 
-namespace armarx::nav::server
-{
-
-    struct GoalReachedEvent
-    {
-        core::Pose pose;
-    };
-
-    struct WaypointReachedEvent
-    {
-        int waypointId;
-        core::Pose pose;
-    };
+#include <Navigation/libraries/core/events.h>
 
-    struct SafetyThrottlingTriggeredEvent
-    {
-        core::Pose pose;
-        float throttlingFactor = 1.0;
-        // TODO: Direction where safety-critical obstacle is (or range or whatever...).
-    };
-
-    struct SafetyStopTriggeredEvent
-    {
-        core::Pose pose;
-        // TODO: Direction where safety-critical obstacle is (or range or whatever...).
-    };
-
-    struct UserAbortTriggeredEvent
-    {
-        core::Pose pose;
-    };
 
-    struct InternalErrorEvent
-    {
-        std::string message;
-    };
+namespace armarx::nav::server
+{
 
     /**
      * @brief A publisher the server navigator will use to notify others about events.
@@ -50,12 +18,32 @@ namespace armarx::nav::server
         /**
          * @brief Will be called whenever the navigator reached the goal.
          */
-        virtual void goalReached(const GoalReachedEvent&) = 0;
+        virtual void goalReached(const core::GoalReachedEvent& event) = 0;
 
         /**
          * @brief Will be called whenever the navigator reached a user-defined waypoint.
          */
-        virtual void waypointReached(const WaypointReachedEvent&) = 0;
+        virtual void waypointReached(const core::WaypointReachedEvent& event) = 0;
+
+        /**
+         * @brief Will be called whenever safety throttling is triggered to a certain degree (configurable).
+         */
+        virtual void safetyThrottlingTriggered(const core::SafetyThrottlingTriggeredEvent& event) = 0;
+
+        /**
+         * @brief Will be called whenever a safety stop is triggered.
+         */
+        virtual void safetyStopTriggered(const core::SafetyStopTriggeredEvent& event) = 0;
+
+        /**
+         * @brief Will be called whenever the user aborts the current navigation.
+         */
+        virtual void userAbortTriggered(const core::UserAbortTriggeredEvent& event) = 0;
+
+        /**
+         * @brief Will be called whenever an internal error occurs.
+         */
+        virtual void internalError(const core::InternalErrorEvent& event) = 0;
 
         // Non-API.
     public:
diff --git a/source/Navigation/libraries/server/event_publishing/MemoryPublisher.cpp b/source/Navigation/libraries/server/event_publishing/MemoryPublisher.cpp
new file mode 100644
index 00000000..710edcaf
--- /dev/null
+++ b/source/Navigation/libraries/server/event_publishing/MemoryPublisher.cpp
@@ -0,0 +1,43 @@
+#include <Navigation/libraries/server/event_publishing/MemoryPublisher.h>
+
+
+void
+armarx::nav::server::MemoryPublisher::goalReached(const core::GoalReachedEvent& event)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::server::MemoryPublisher::waypointReached(const core::WaypointReachedEvent& event)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::server::MemoryPublisher::safetyThrottlingTriggered(const core::SafetyThrottlingTriggeredEvent& event)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::server::MemoryPublisher::safetyStopTriggered(const core::SafetyStopTriggeredEvent& event)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::server::MemoryPublisher::userAbortTriggered(const core::UserAbortTriggeredEvent& event)
+{
+    // TODO: Implement.
+}
+
+
+void
+armarx::nav::server::MemoryPublisher::internalError(const core::InternalErrorEvent& event)
+{
+    // TODO: Implement.
+}
diff --git a/source/Navigation/libraries/server/event_publishing/MemoryPublisher.h b/source/Navigation/libraries/server/event_publishing/MemoryPublisher.h
index b139b9e7..7c199d76 100644
--- a/source/Navigation/libraries/server/event_publishing/MemoryPublisher.h
+++ b/source/Navigation/libraries/server/event_publishing/MemoryPublisher.h
@@ -10,15 +10,17 @@ namespace armarx::nav::server
 
     public:
 
-        void goalReached(const GoalReachedEvent&) override
-        {
-            // TODO: Implement.
-        }
-
-        void waypointReached(const WaypointReachedEvent&) override
-        {
-            // TODO: Implement.
-        }
+        void goalReached(const core::GoalReachedEvent& event) override;
+
+        void waypointReached(const core::WaypointReachedEvent& event) override;
+
+        void safetyThrottlingTriggered(const core::SafetyThrottlingTriggeredEvent& event) override;
+
+        void safetyStopTriggered(const core::SafetyStopTriggeredEvent& event) override;
+
+        void userAbortTriggered(const core::UserAbortTriggeredEvent& event) override;
+
+        void internalError(const core::InternalErrorEvent& event) override;
 
         // Non-API.
     public:
diff --git a/source/Navigation/libraries/server/test/serverTest.cpp b/source/Navigation/libraries/server/test/serverTest.cpp
index 74cde839..f3977f26 100644
--- a/source/Navigation/libraries/server/test/serverTest.cpp
+++ b/source/Navigation/libraries/server/test/serverTest.cpp
@@ -65,11 +65,12 @@ BOOST_AUTO_TEST_CASE(testNavigator)
     server::DummyExecutor executor{scene.robot, server::DummyExecutor::Params()};
     client::SimpleEventHandler eventHandler;
 
-    server::GeneralConfig generalConfig;
-
-    server::Navigator navigator(server::NavigatorConfig{
-        .stack = stack, .scene = &scene, .general = generalConfig},
-                                server::Services{
+    server::Navigator navigator(server::Navigator::Config{
+                                    .stack = stack,
+                                    .scene = &scene,
+                                    .general = server::Navigator::Config::General{}
+                                },
+                                server::Navigator::InjectedServices{
                                     .executor = &executor,
                                     .publisher = &eventHandler
                                 });
-- 
GitLab