Capabilities2 0.3.0
Loading...
Searching...
No Matches
event_node.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <map>
4#include <memory>
5#include <string>
6#include <vector>
7
8#include <rclcpp/rclcpp.hpp>
9
12
13#include <capabilities2_msgs/msg/capability.hpp>
14#include <capabilities2_msgs/msg/capability_event_code.hpp>
15#include <capabilities2_msgs/msg/capability_connection.hpp>
16
18{
26{
27private:
35 struct EventPipe
36 {
37 // connection type
38 capabilities2_msgs::msg::CapabilityEventCode type;
39
40 // connection target
41 capabilities2_msgs::msg::Capability target;
42
43 // event callback with signature: (capability, parameters, bond_id)
45 };
46
47public:
48 EventNode(std::shared_ptr<EventBase> event_emitter = nullptr)
49 : id_(UUIDGenerator::gen_uuid_str()), source_(), event_emitter_(event_emitter), connections_()
50 {
51 }
52
53 virtual ~EventNode() = default;
54
64 void emit_event(const std::string& bond_id, const std::string& instance_id, const uint8_t& event_type,
66 {
67 // check if event emitter is set
68 if (!event_emitter_)
69 {
70 // No event emitter configured - silently skip
71 // This allows runners to work without event system if needed
72 return;
73 }
74
75 // check each connection
76 for (const auto& [conn_id, connection] : connections_)
77 {
78 // extract bond_id from connection_id (format: "bond_id/instance_id/target_instance_id")
79 size_t first_pos = conn_id.find('/');
80 size_t second_pos = conn_id.find('/', first_pos + 1);
81
82 std::string conn_bond_id = (first_pos != std::string::npos) ? conn_id.substr(0, first_pos) : conn_id;
83 std::string conn_instance_id =
84 (second_pos != std::string::npos) ? conn_id.substr(first_pos + 1, second_pos - first_pos - 1) : "";
85
86 // get targets for this event type and id namespace
87 if (connection.type.code == event_type && bond_id == conn_bond_id && instance_id == conn_instance_id)
88 {
89 // parameterise target capability with parameters from the trigger
90 auto old_parameters = capabilities2_events::EventParameters(connection.target);
91
92 // extend or replace parameters of the target capability if any non empty parameters are provided
93 if (!parameters.is_empty())
94 for (auto& option : parameters.options)
95 old_parameters.set_value(option.key, option.get_value(), option.type);
96
97 // create a new target capability message with updated parameters to emit with the event
98 auto target_with_params = old_parameters.toMsg();
99
100 // copy capability and provider from original target as parameters only contains the options
101 target_with_params.capability = connection.target.capability;
102 target_with_params.provider = connection.target.provider;
103 target_with_params.instance_id = connection.target.instance_id;
104
105 // emit event via event api
106 // NOTE: callback invocation is handled by event api
107 // this allows the nodes to be decoupled
108 // nodes just keep track of connections
109 // modifying execution of other nodes is not owned by this class
110 // this lets the execution flow be made thread-safe
111 // in the scope where the thread is owned
112 event_emitter_->emit(conn_id, event_type, source_, target_with_params, connection.callback);
113 }
114 }
115 }
116
117protected:
123 void set_source(const capabilities2_msgs::msg::Capability& src)
124 {
125 source_ = src;
126 }
127
135 void set_event_emitter(std::shared_ptr<EventBase> event_emitter)
136 {
137 event_emitter_ = event_emitter;
138 }
139
154 void add_connection(const std::string& connection_id, const capabilities2_msgs::msg::CapabilityEventCode& type,
155 const capabilities2_msgs::msg::Capability& target, EventBase::event_callback_t event_cb)
156 {
157 // validate connection id
158 if (connections_.find(connection_id) != connections_.end())
159 {
160 throw event_exception("connection with id: " + connection_id + " already exists");
161 }
162
163 // set up an event pipe
164 EventPipe conn;
165 conn.type = type;
166 conn.target = target;
167 conn.callback = event_cb;
168
169 // add connection
170 connections_[connection_id] = conn;
171
172 if (event_emitter_)
173 {
174 // emit connected event
175 event_emitter_->on_connected(source_.capability, target.capability);
176 }
177 }
178
184 void remove_connection(const std::string& connection_id)
185 {
186 // remove connection
187 auto it = connections_.find(connection_id);
188 if (it == connections_.end())
189 {
190 throw event_exception("connection with id: " + connection_id + " does not exist");
191 }
192 auto target = it->second.target;
193 connections_.erase(connection_id);
194
195 // emit disconnected event
196 if (event_emitter_)
197 {
198 event_emitter_->on_disconnected(source_.capability, target.capability);
199 }
200 }
201
202 // helper members
203
208 {
209 connections_.clear();
210 }
211
217 std::vector<capabilities2_msgs::msg::CapabilityConnection> list_connections() const
218 {
219 std::vector<capabilities2_msgs::msg::CapabilityConnection> conns;
220
221 for (const auto& [conn_id, connection] : connections_)
222 {
223 capabilities2_msgs::msg::CapabilityConnection c;
224 c.type = connection.type;
225 c.source = source_;
226 c.target = connection.target;
227 conns.push_back(c);
228 }
229
230 return conns;
231 }
232
240 bool has_connection(const std::string& connection_id) const
241 {
242 return connections_.find(connection_id) != connections_.end();
243 }
244
250 size_t connection_count() const
251 {
252 return connections_.size();
253 }
254
260 const std::string& get_id() const
261 {
262 return id_;
263 }
264
270 const capabilities2_msgs::msg::Capability& get_source() const
271 {
272 return source_;
273 }
274
279 {
280 return event_emitter_ != nullptr;
281 }
282
283private:
284 // unique id of the event node
285 // using uuid string
286 std::string id_;
287
288 // source capability of this event node
289 capabilities2_msgs::msg::Capability source_;
290
291 // event emitter used to emit events
292 // store as member to avoid passing around
293 std::shared_ptr<EventBase> event_emitter_;
294
295 // connections from this event node to target capabilities
296 // Key: connection_id (format: "bond_id/trigger_id")
297 // Value: EventPipe with type, target, callback
298 std::map<std::string, EventPipe> connections_;
299};
300} // namespace capabilities2_events
std::function< void(const access_id_t &, const capability_str_t &, const target_instance_id_t &, parameter_t)> event_callback_t
Definition event_base.hpp:49
an event node is a source of an event
Definition event_node.hpp:26
const capabilities2_msgs::msg::Capability & get_source() const
source capability of this event node
Definition event_node.hpp:270
std::shared_ptr< EventBase > event_emitter_
Definition event_node.hpp:293
void set_source(const capabilities2_msgs::msg::Capability &src)
Set the source object.
Definition event_node.hpp:123
const std::string & get_id() const
unique id of this event node
Definition event_node.hpp:260
std::vector< capabilities2_msgs::msg::CapabilityConnection > list_connections() const
List all connections from this event node.
Definition event_node.hpp:217
void remove_connection(const std::string &connection_id)
Remove a connection by its id.
Definition event_node.hpp:184
void clear_connections()
clear all connections from this event node
Definition event_node.hpp:207
std::string id_
Definition event_node.hpp:286
EventNode(std::shared_ptr< EventBase > event_emitter=nullptr)
Definition event_node.hpp:48
size_t connection_count() const
current connection count
Definition event_node.hpp:250
void set_event_emitter(std::shared_ptr< EventBase > event_emitter)
event emitter for this event node
Definition event_node.hpp:135
bool has_connection(const std::string &connection_id) const
Check if a connection exists.
Definition event_node.hpp:240
void add_connection(const std::string &connection_id, const capabilities2_msgs::msg::CapabilityEventCode &type, const capabilities2_msgs::msg::Capability &target, EventBase::event_callback_t event_cb)
make EventNode::add_connection public method on runner api.
Definition event_node.hpp:154
capabilities2_msgs::msg::Capability source_
Definition event_node.hpp:289
bool is_event_emitter_set() const
event emitter is set on this node
Definition event_node.hpp:278
std::map< std::string, EventPipe > connections_
Definition event_node.hpp:298
void emit_event(const std::string &bond_id, const std::string &instance_id, const uint8_t &event_type, capabilities2_events::EventParameters parameters=capabilities2_events::EventParameters())
emit an event from this event node to all matching connections
Definition event_node.hpp:64
Definition uuid_generator.hpp:8
Definition event_base.hpp:14
event pipe structure
Definition event_node.hpp:36
EventBase::event_callback_t callback
Definition event_node.hpp:44
capabilities2_msgs::msg::CapabilityEventCode type
Definition event_node.hpp:38
capabilities2_msgs::msg::Capability target
Definition event_node.hpp:41
capability options for a capability runner given by interface and provider
Definition event_parameters.hpp:167
event exception
Definition event_base.hpp:22