Mads
Multi-Agent Distributed System
Loading...
Searching...
No Matches
agent.hpp
Go to the documentation of this file.
1/*
2 _ _ _
3 / \ __ _ ___ _ __ | |_ ___| | __ _ ___ ___
4 / _ \ / _` |/ _ \ '_ \| __| / __| |/ _` / __/ __|
5 / ___ \ (_| | __/ | | | |_ | (__| | (_| \__ \__ \
6 /_/ \_\__, |\___|_| |_|\__| \___|_|\__,_|___/___/
7 |___/
8
9Base class for all agents. This class is used to define the basic
10functionalities provided by all agents. Each agent subclass must implement the
11pure virtual functions defined in this class (currently none)
12
13Author(s): Paolo Bosetti
14*/
15
16#ifndef AGENT_HPP
17#define AGENT_HPP
18
19#if defined _WIN32 && !defined NOMINMAX
20#define NOMINMAX
21#endif
22
23#include "mads.hpp"
24#include <nlohmann/json.hpp>
25#ifdef _WIN32
26#include <winsock2.h>
27#else
28#include <unistd.h>
29#endif
30#ifndef _MSC_VER
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wunknown-attributes"
33#endif
34#include <toml++/toml.hpp>
35#ifndef _MSC_VER
36#pragma GCC diagnostic pop
37#endif
38#include <iostream>
39#include <regex>
40#include <string>
41#include <string_view>
42#include <thread>
43#include <future>
44#include <zmq.hpp>
45#include <zmq_addon.hpp>
46#include <mutex>
47#include <condition_variable>
48#include <optional>
49#include <span>
50#include <atomic>
51#include <memory>
52#include "clock_offset.hpp"
53#include "curve.hpp"
54#include "exec_path.hpp"
55#include "socket_monitor.hpp"
56#include "topic_match.hpp"
57
58#ifndef HOST_NAME_MAX
59#define HOST_NAME_MAX 255
60#endif
61
62#ifndef MADS_AGENT_NO_INFO
63#include <rang.hpp>
64using namespace rang;
65#endif
66
67namespace Mads {
68
69template<typename T> struct SharedLatest {
70 std::mutex mtx;
71 std::condition_variable cv;
72 std::optional<T> value;
73};
74
88public:
89 LazyPayload() = default;
90 static LazyPayload from_text(std::string text) {
92 p._text = std::move(text);
93 return p;
94 }
95 static LazyPayload from_doc(nlohmann::json doc) {
97 p._doc = std::move(doc);
98 return p;
99 }
101 const std::string &text() const {
102 if (!_text)
103 _text = _doc ? _doc->dump() : std::string();
104 return *_text;
105 }
107 const nlohmann::json &doc() const {
108 if (!_doc) {
109 if (_text && !_text->empty())
110 _doc = nlohmann::json::parse(*_text);
111 else
112 _doc = nlohmann::json();
113 }
114 return *_doc;
115 }
116
117private:
118 mutable std::optional<std::string> _text;
119 mutable std::optional<nlohmann::json> _doc;
120};
121
140
141class Agent; // forward declaration
142
157std::unique_ptr<Agent> start_agent(std::string name, std::string settings_uri,
158 std::map<std::string, std::string> crypto_settings = {});
159
190class Agent {
191
192/*
193 ____ _ _ _
194 / ___|| |_ __ _| |_(_) ___
195 \___ \| __/ _` | __| |/ __|
196 ___) | || (_| | |_| | (__
197 |____/ \__\__,_|\__|_|\___|
198
199*/
200
201private:
210 void setup_curve_on(zmq::socket_t &socket);
211
230 std::tuple<std::string, std::string, double>
231 query_broker(std::string uri, std::string name,
232 int timeout = DEFAULT_SETTINGS_TIMEOUT_MS);
233
234public:
235/*
236 _ _ __ _
237 | | (_)/ _| ___ ___ _ _ ___| | ___
238 | | | | |_ / _ \/ __| | | |/ __| |/ _ \
239 | |___| | _| __/ (__| |_| | (__| | __/
240 |_____|_|_| \___|\___|\__, |\___|_|\___|
241 |___/
242*/
243
252 Agent(std::string name, std::string settings_uri);
253
254
271 void init(std::string name, std::string settings_uri, bool crypto = false, std::filesystem::path const &key_dir = "", bool install_watchdog = true);
272
273
283 void init(bool crypto = false, bool install_watchdog = true);
284
303 void fetch_settings(bool crypto = false);
304
321
322 // Destructor
323 virtual ~Agent();
324
332 void install_loop_watchdog(uint8_t max_count = 3);
333
334
335/*
336 ____ _ _ _
337 / ___| ___| |_| |_(_)_ __ __ _ ___
338 \___ \ / _ \ __| __| | '_ \ / _` / __|
339 ___) | __/ |_| |_| | | | | (_| \__ \
340 |____/ \___|\__|\__|_|_| |_|\__, |___/
341 |___/
342*/
343
351 virtual void load_settings();
352
353
360 void save_settings(const std::string path = SETTINGS_PATH);
361
362
367 nlohmann::json get_settings();
368
369
370#ifndef MADS_AGENT_NO_INFO
380 virtual void info(std::ostream &out = std::cout);
381#endif
382
383
384/*
385 ____ _ _
386 / ___|___ _ __ _ __ ___ ___| |_(_) ___ _ __
387 | | / _ \| '_ \| '_ \ / _ \/ __| __| |/ _ \| '_ \
388 | |__| (_) | | | | | | | __/ (__| |_| | (_) | | | |
389 \____\___/|_| |_|_| |_|\___|\___|\__|_|\___/|_| |_|
390
391*/
392
411 void connect(std::chrono::milliseconds delay = std::chrono::milliseconds(250));
412
429 bool wait_for_connection(std::chrono::milliseconds timeout);
430
450
455
456
464 void shutdown();
465
466
475 void set_cross(bool cross);
476
477
492 void enable_remote_control(bool threaded = false);
493
497
498
508 void register_event(const event_type event = event_type::marker,
509 const nlohmann::json &info = nlohmann::json(),
510 const std::string &info_name = "info");
511
512
519 void publish(nlohmann::json payload, std::string topic = "");
520
521
530 void publish(const char *payload, size_t len,
531 nlohmann::json meta = nlohmann::json{{"format", "raw"}},
532 std::string topic = "");
533
534
543 void publish(const std::vector<unsigned char> &payload,
544 nlohmann::json meta = nlohmann::json{{"format", "raw"}},
545 std::string topic = "");
546
547
558 message_type receive(bool dont_block = false);
559
586 bool receive_raw_message(std::string &topic, std::vector<std::string> &parts,
587 bool dont_block = false);
588
604 void publish_raw_message(const std::string &topic,
605 const std::vector<std::string> &parts);
606
607
608 /*
609 _
610 | | ___ ___ _ __
611 | | / _ \ / _ \| '_ \
612 | |__| (_) | (_) | |_) |
613 |_____\___/ \___/| .__/
614 |_|
615 */
616
643 using loop_fun_t = std::function<std::chrono::nanoseconds()>;
644 void loop(loop_fun_t const &lambda,
645 std::chrono::nanoseconds duration);
646
647
660 void loop(loop_fun_t const &lambda);
661
662
680 void enable_high_res_loop(bool on = true,
681 std::chrono::nanoseconds spin_margin =
682 std::chrono::microseconds(200));
683
687 bool high_res_loop() const;
688
689
697 void remote_control(std::string payload_str);
698
699
700 /*
701 _
702 / \ ___ ___ ___ ___ ___ ___ _ __ ___
703 / _ \ / __/ __/ _ \/ __/ __|/ _ \| '__/ __|
704 / ___ \ (_| (_| __/\__ \__ \ (_) | | \__ \
705 /_/ \_\___\___\___||___/___/\___/|_| |___/
706
707 */
708
714 void set_agent_id(std::string id);
715
716
717
723 std::string get_agent_id();
724
730 void set_sub_endpoint(std::string endpoint) { _sub_endpoint = endpoint; }
731
737 std::string sub_endpoint() const { return _sub_endpoint; }
738
744 void set_pub_endpoint(std::string endpoint) { _pub_endpoint = endpoint; }
745
751 std::string pub_endpoint() const { return _pub_endpoint; }
752
758 void set_pub_topic(std::string topic);
759
765 std::string pub_topic() const { return _pub_topic; }
766
772 void set_sub_topic(std::vector<std::string> topics) { _sub_topic = topics; }
773
779 std::vector<std::string> sub_topic() const { return _sub_topic; }
780
781
787 std::map<std::string, std::string> status();
788
789
795 std::string name();
796
797
804 std::tuple<std::string, std::string> last_message();
805
806
817 std::tuple<std::string, nlohmann::json> last_json();
818
819
825 std::string last_topic();
826
827
834 std::tuple<std::string, std::string, std::vector<unsigned char>> last_blob();
835
836
847 std::tuple<std::string_view, std::string_view,
848 std::span<const unsigned char>>
850
851
858 size_t dropped_messages() const;
859
860
866 bool settings_are_local() const;
867
868
875
876
883
884
893
901 void set_settings_timeout(std::chrono::milliseconds to);
902
903
910
911
920
928 void set_receive_timeout(std::chrono::milliseconds to);
929
930
936 bool restart();
937
948 std::shared_ptr<Mads::Runtime> runtime() const { return _runtime; }
949
959 bool running() const { return keep_running(); }
960
971 void set_runtime(std::shared_ptr<Mads::Runtime> runtime);
972
973
982 std::filesystem::path attachment_path();
983
984
990 bool is_crypto();
991
992
999
1000
1006 std::unique_ptr<CurveAuth> *curve_auth();
1007
1008
1014 std::filesystem::path key_dir();
1015
1016
1022 void set_key_dir(const std::filesystem::path &path);
1023
1024 std::string settings_uri();
1025
1026
1027 [[deprecated("conflate is disabled; use set_delivery(Delivery::LastKnownValue)")]]
1029 [[deprecated("conflate is disabled; use delivery()")]]
1030 bool conflate();
1031
1041 void set_high_watermark(int i = 1000);
1043
1051 void set_delivery(Delivery d);
1052
1056 Delivery delivery() const;
1057
1067 void set_wire_format(WireFormat fmt);
1068
1072 WireFormat wire_format() const;
1073
1083 void set_compression(Compression c);
1084
1088 Compression compression() const;
1089
1098
1099
1100 /*
1101 ____ _ _ ___ __ __ _
1102 / ___| | ___ ___| | __ / _ \ / _|/ _|___ ___| |_
1103 | | | |/ _ \ / __| |/ /| | | | |_| |_/ __|/ _ \ __|
1104 | |___| | (_) | (__| < | |_| | _| _\__ \ __/ |_
1105 \____|_|\___/ \___|_|\_\ \___/|_| |_| |___/\___|\__|
1106
1107 */
1108
1127 int timeout_ms = 1000);
1128
1146 std::vector<Mads::ClockPeerObservation> broadcast_clock_probe(
1147 std::chrono::milliseconds window = std::chrono::milliseconds(300));
1148
1157
1164 std::string clock_domain() const;
1165
1166 double timecode_fps = MADS_FPS;
1168 std::string server_key_name = "broker";
1169 std::string client_key_name = "client";
1170
1171 /*
1172 ____ _ _
1173 | _ \ _ __(_)_ ____ _| |_ ___
1174 | |_) | '__| \ \ / / _` | __/ _ \
1175 | __/| | | |\ V / (_| | || __/
1176 |_| |_| |_| \_/ \__,_|\__\___|
1177
1178 */
1179
1180protected:
1187 bool keep_running() const {
1188 return _runtime->running() && !_stopping.load();
1189 }
1190
1196 void connect_pub(std::chrono::milliseconds delay = std::chrono::milliseconds(0));
1197
1198
1204
1205
1214 bool receive_raw(zmq::multipart_t &message, bool dont_block = false);
1215
1226 bool _topic_matches_subscription(const std::string &topic) const;
1227
1228 static std::tuple<std::string, std::string, std::string> split_URL(const std::string &url);
1229
1239
1247
1254
1258 bool _clock_wants_sync() const;
1259
1271
1277
1282 void _handle_clocksync_message(const nlohmann::json &msg);
1283
1287
1293 uint8_t hops);
1294
1299 std::string _clock_agent_identity() const;
1300
1301 // Member variables
1302 std::string _hostname;
1303 std::string _name;
1304 std::string _settings_uri;
1305 std::string _raw_settings;
1306 toml::table _config;
1308 std::string _pub_topic;
1309 std::string _agent_id;
1310 std::vector<std::string> _sub_topic;
1311 // Subset of _sub_topic containing a '+'/'#' wildcard token (P2), computed
1312 // once by connect_sub(). Empty for every agent using only literal
1313 // sub_topic entries, which keeps the receive-time filter a single cheap
1314 // emptiness check in that -- the common -- case, adding no overhead.
1315 std::vector<std::string> _wildcard_sub_topic;
1316 zmq::context_t _context;
1317 zmq::socket_t _publisher;
1318 zmq::socket_t _subscriber;
1319 // Attached before each socket's connect()/bind() (ZMQ_DEVELOPMENT.md
1320 // §2.1); stopped in shutdown() before the sockets are closed.
1323 // A single LazyPayload per message is shared between _last_message and
1324 // _status so the lazy text/object caches are shared and never duplicated.
1325 std::map<std::string, std::shared_ptr<LazyPayload>> _status;
1326 std::tuple<std::string, std::shared_ptr<LazyPayload>> _last_message;
1327 std::tuple<std::string, std::string, std::vector<unsigned char>> _last_blob;
1328 mutable std::mutex _message_state_mutex;
1329 bool _cross = false;
1330 bool _connected = false;
1331 int _receive_timeout = DEFAULT_RECEIVE_TIMEOUT_MS;
1333 bool _init_done = false;
1334 bool _settings_fetched = false;
1335 bool _restart = false;
1336 std::shared_ptr<Mads::Runtime> _runtime = std::make_shared<Mads::Runtime>();
1337 // Per-agent stop request: set by shutdown()/disconnect(), cleared by
1338 // connect(). Keeps an individual agent's teardown from stopping the other
1339 // agents that share its Runtime.
1340 std::atomic<bool> _stopping{false};
1342 std::chrono::nanoseconds _time_step = std::chrono::nanoseconds(0);
1343 bool _high_res_loop = false;
1344 std::chrono::nanoseconds _spin_margin = std::chrono::microseconds(200);
1345 double _timecode_offset = 0.0;
1346 std::filesystem::path _attachment_path;
1347 bool _crypto = false;
1348 bool _conflate = false;
1349 std::unique_ptr<CurveAuth> _curve_auth = nullptr;
1350 std::filesystem::path _key_dir;
1351 bool _last_value_only = false;
1352 bool _shutdown_done = false;
1354 // The agent's one socket thread (ZMQ_DEVELOPMENT.md §4.1). It always polls
1355 // both socket monitors' PAIR sockets -- which used to cost a thread each --
1356 // and additionally owns _subscriber exclusively whenever LKV delivery
1357 // and/or threaded remote control need it consumed off the application
1358 // thread. A single thread rather than one per feature: two threads calling
1359 // recv() on the same (non-thread-safe) ZMQ socket is undefined behaviour,
1360 // and with LKV and threaded remote control both enabled it also meant a
1361 // message landed on whichever thread's recv() call won the race.
1362 std::thread _io_thread;
1363 // Whether _io_thread polls _subscriber at all. Set by connect_sub() only
1364 // once the socket is fully subscribed, and read by _io_thread, so it must
1365 // be atomic even though it never changes after that.
1366 std::atomic<bool> _io_reads_subscriber{false};
1367 std::thread _watchdog_thread;
1368 // Delayed startup-event publisher: owned (not detached) so shutdown() can
1369 // wake it via _event_cv and join it before the sockets close.
1371 std::mutex _event_mtx;
1372 std::condition_variable _event_cv;
1373 // ZMQ sockets are not thread-safe; the event thread publishes concurrently
1374 // with the owner thread, so sends on _publisher are serialized.
1375 std::mutex _publish_mutex;
1376 std::atomic<bool> _watchdog_stop{false};
1377 bool _rc_owns_socket = false;
1378 WireFormat _wire_format = WireFormat::Json;
1379 Compression _compression = Compression::Auto;
1380 std::atomic<size_t> _dropped_messages{0};
1381 nlohmann::json _settings_json; // cached JSON projection of settings
1382
1383 // ---- Clock offset (see clock_offset.hpp) --------------------------
1388 bool _clock_correction = false;
1389 // Per-clock-domain adoption (§2 of the design): every agent, regardless
1390 // of its own clock_source, records what it hears so clock_offset() can
1391 // return the domain's winner rather than only this agent's own
1392 // measurement.
1393 Mads::ClockConsensus _clock_consensus{std::chrono::seconds(30)};
1394 // This agent's own last measurement (source Broker or Peer), guarded
1395 // separately from _clock_consensus's own internal mutex since it is
1396 // read/written by measure_clock_offset()/_run_peer_measurement() (the
1397 // clock thread or init()) and read by clock_offset() (any thread).
1398 mutable std::mutex _clock_mtx;
1400 uint64_t _clock_seq = 0;
1401 std::thread _clock_thread;
1402 // Pending broadcast_clock_probe() collection state: the send instant (for
1403 // local_elapsed_us) and the pongs gathered so far. Single-flight by
1404 // design (see broadcast_clock_probe()'s doc comment).
1405 mutable std::mutex _clocksync_mtx;
1406 std::chrono::steady_clock::time_point _clocksync_probe_sent_at{};
1407 std::vector<Mads::ClockPeerObservation> _clocksync_pongs;
1409 // Per-initiator rate limit for this agent's own ping responses (§4.1 of
1410 // the design): guarded by _clocksync_mtx too.
1411 std::map<std::string, std::chrono::steady_clock::time_point>
1413
1414public:
1415 bool dummy = false;
1416};
1417
1418} // namespace Mads
1419
1420#endif // AGENT_HPP
void set_wire_format(WireFormat fmt)
Select the on-the-wire payload encoding used when publishing.
bool restart()
Returns wheter a restart has been requested.
std::mutex _publish_mutex
Definition agent.hpp:1375
toml::table _config
Definition agent.hpp:1306
std::thread _watchdog_thread
Definition agent.hpp:1367
std::string name()
Returns the name of the agent.
std::mutex _clocksync_mtx
Definition agent.hpp:1405
virtual ~Agent()
bool _clock_correction
Definition agent.hpp:1388
Mads::LinkState link_state() const
The current state of this agent's link to the broker: up or down, why (last_handshake – e....
std::map< std::string, std::chrono::steady_clock::time_point > _clocksync_last_reply
Definition agent.hpp:1412
std::filesystem::path attachment_path()
Returns the path to the attachment file.
Mads::ClockOffsetResult clock_offset() const
This agent's currently adopted clock offset: the clock domain's consensus winner (Mads::ClockConsensu...
void set_compression(Compression c)
Select the payload compression policy for outgoing messages.
bool _init_done
Definition agent.hpp:1333
uint64_t _clock_seq
Definition agent.hpp:1400
std::string _pub_endpoint
Definition agent.hpp:1307
void enable_threaded_remote_control()
Definition agent.hpp:494
bool add_default_section()
Adds a default section for this agent if the fetched settings have none.
void shutdown()
Performs a coordinated shutdown of the agent.
int _clock_interval_ms
Definition agent.hpp:1386
void _announce_clock_offset(const Mads::ClockOffsetResult &r)
void set_sub_topic(std::vector< std::string > topics)
Sets the subscribe topics.
Definition agent.hpp:772
std::thread _startup_event_thread
Definition agent.hpp:1370
std::string pub_endpoint() const
Get the publish endpoint URL.
Definition agent.hpp:751
std::filesystem::path _attachment_path
Definition agent.hpp:1346
std::string clock_domain() const
This process's clock-domain identity (Mads::detail::clock_domain_id(): boot_id on Linux,...
std::vector< std::string > sub_topic() const
Gets the subscribe topics.
Definition agent.hpp:779
std::string get_agent_id()
Get the agent ID.
void init(bool crypto=false, bool install_watchdog=true)
Initializes the agent.
Mads::ClockOffsetResult measure_clock_offset(size_t samples=5, int timeout_ms=1000)
Runs samples four-timestamp exchanges against the broker's settings endpoint and adopts the result as...
bool is_crypto()
Returns whether CURVE encryption is enabled.
Agent(std::string name, std::string settings_uri)
Constructs an Agent object with the given name and settings path. If the settings path is a URI,...
Mads::SocketMonitor _sub_monitor
Definition agent.hpp:1322
std::string _raw_settings
Definition agent.hpp:1305
void loop(loop_fun_t const &lambda)
Enters the main loop of the agent. It also sets a signal handler for SIGNINT, which will set the runn...
bool conflate()
double _timecode_offset
Definition agent.hpp:1345
std::string _name
Definition agent.hpp:1303
void set_pub_endpoint(std::string endpoint)
Set the publish endpoint URL.
Definition agent.hpp:744
std::string client_key_name
Definition agent.hpp:1169
std::string settings_uri()
std::atomic< size_t > _dropped_messages
Definition agent.hpp:1380
std::vector< std::string > _sub_topic
Definition agent.hpp:1310
bool _clock_sync_responder
Definition agent.hpp:1385
void set_runtime(std::shared_ptr< Mads::Runtime > runtime)
Attach the agent to a different Runtime.
void connect(std::chrono::milliseconds delay=std::chrono::milliseconds(250))
Connects the agent to the publish and subscribe endpoints.
Mads::ClockOffsetResult _own_clock_measurement
Definition agent.hpp:1399
bool _crypto
Definition agent.hpp:1347
void set_receive_timeout(std::chrono::milliseconds to)
Sets the value of timeout in receiving messages. Set to 0 for no timeout.
bool _shutdown_done
Definition agent.hpp:1352
int high_watermark()
void set_delivery(Delivery d)
Select subscriber delivery semantics.
std::filesystem::path key_dir()
Returns the path to the etc directory.
std::tuple< std::string, nlohmann::json > last_json()
Returns the last received message as a parsed JSON object.
std::condition_variable _event_cv
Definition agent.hpp:1372
std::chrono::nanoseconds _spin_margin
Definition agent.hpp:1344
void save_settings(const std::string path=SETTINGS_PATH)
Save settings read from broker to file.
int _receive_timeout
Definition agent.hpp:1331
void publish(const std::vector< unsigned char > &payload, nlohmann::json meta=nlohmann::json{{"format", "raw"}}, std::string topic="")
Publishes a message with the given binary blob payload.
std::unique_ptr< CurveAuth > * curve_auth()
Returns a pointer to the CurveAuth object.
void publish_raw_message(const std::string &topic, const std::vector< std::string > &parts)
Publishes a raw multi-part message with no JSON encoding, no automatic field-stamping (agent_id/hostn...
bool _clock_wants_sync() const
void init(std::string name, std::string settings_uri, bool crypto=false, std::filesystem::path const &key_dir="", bool install_watchdog=true)
Initializes the agent.
std::tuple< std::string_view, std::string_view, std::span< const unsigned char > > last_blob_view() const
Zero-copy view of the last received blob.
bool receive_raw(zmq::multipart_t &message, bool dont_block=false)
Internal use wrapping the receive step both for normal operations and for LastKnown Value (LKV) seman...
SharedLatest< zmq::multipart_t > _latest_message
Definition agent.hpp:1353
void set_settings_timeout(std::chrono::milliseconds to)
Sets the value of timeout in loading settings from URI. Set to for no timeout.
bool _connected
Definition agent.hpp:1330
bool _topic_matches_subscription(const std::string &topic) const
MQTT-style wildcard filter (P2): true if topic is accepted by at least one entry of _sub_topic – lite...
Mads::ClockOffsetResult _stamp_clock_result(Mads::ClockOffsetResult r, Mads::ClockSource source, uint8_t hops)
std::thread _io_thread
Definition agent.hpp:1362
std::vector< Mads::ClockPeerObservation > broadcast_clock_probe(std::chrono::milliseconds window=std::chrono::milliseconds(300))
Broadcasts a clock-sync ping on CLOCKSYNC_TOPIC and collects every responder's pong that arrives with...
void set_pub_topic(std::string topic)
Sets the publish topic.
void enable_remote_control(bool threaded=false)
Enables remote control for the agent.
bool _conflate
Definition agent.hpp:1348
bool wait_for_connection(std::chrono::milliseconds timeout)
Blocks until the publisher socket's connection is confirmed by a real ZMQ_EVENT_CONNECTED/ZMQ_EVENT_H...
virtual void info(std::ostream &out=std::cout)
Prints information about the agent.
void set_cross(bool cross)
Sets the cross flag.
size_t dropped_messages() const
Number of messages dropped because they were malformed or could not be decoded (bad part count,...
bool _high_res_loop
Definition agent.hpp:1343
std::function< std::chrono::nanoseconds()> loop_fun_t
Enters the main loop of the agent. It also sets a signal handler for SIGNINT, which will set the runn...
Definition agent.hpp:643
std::mutex _clock_mtx
Definition agent.hpp:1398
void remote_control(std::string payload_str)
Handles remote control commands.
int receive_timeout()
Returns the value of timeout in receiving messages.
Mads::SocketMonitor _pub_monitor
Definition agent.hpp:1321
std::vector< Mads::ClockPeerObservation > _clocksync_pongs
Definition agent.hpp:1407
std::string _settings_uri
Definition agent.hpp:1304
std::atomic< bool > _watchdog_stop
Definition agent.hpp:1376
std::atomic< bool > _io_reads_subscriber
Definition agent.hpp:1366
void set_conflate(bool conflate)
void enable_high_res_loop(bool on=true, std::chrono::nanoseconds spin_margin=std::chrono::microseconds(200))
Opt into (or out of) high-resolution loop pacing.
nlohmann::json _settings_json
Definition agent.hpp:1381
void _handle_clocksync_message(const nlohmann::json &msg)
static void install_signal_handlers()
Install SIGINT/SIGTERM handlers that request a clean shutdown.
std::string _hostname
Definition agent.hpp:1302
std::map< std::string, std::string > status()
Returns the status of the system.
uint64_t _clocksync_probe_seq
Definition agent.hpp:1408
void set_high_watermark(int i=1000)
Set the high watermark (ZMQ receive queue bound).
zmq::socket_t _subscriber
Definition agent.hpp:1318
void publish(const char *payload, size_t len, nlohmann::json meta=nlohmann::json{{"format", "raw"}}, std::string topic="")
Publishes a message with the given binary blob payload.
bool is_connected()
Detects if agent is connected.
void loop(loop_fun_t const &lambda, std::chrono::nanoseconds duration)
std::shared_ptr< Mads::Runtime > _runtime
Definition agent.hpp:1336
std::tuple< std::string, std::shared_ptr< LazyPayload > > _last_message
Definition agent.hpp:1326
void set_agent_id(std::string id)
Set the agent ID field.
std::string sub_endpoint() const
Get the subscribe endpoint URL.
Definition agent.hpp:737
std::string _pub_topic
Definition agent.hpp:1308
void _configure_clock_sync()
Parses the [agents]/[<name>] clock_* settings during init() and appends CLOCKSYNC_TOPIC to _sub_topic...
int _clock_announce_ms
Definition agent.hpp:1387
WireFormat _wire_format
Definition agent.hpp:1378
message_type receive(bool dont_block=false)
Receives a message from the subscribe socket.
Mads::ClockSource _clock_source
Definition agent.hpp:1384
double timecode_fps
Definition agent.hpp:1166
void _run_peer_measurement()
std::mutex _message_state_mutex
Definition agent.hpp:1328
std::chrono::nanoseconds _time_step
Definition agent.hpp:1342
void _start_clock_thread()
Brings up _clock_thread if it is not already running: announces this agent's adopted clock offset on ...
bool high_res_loop() const
Returns whether high-resolution loop pacing is enabled.
std::filesystem::path _key_dir
Definition agent.hpp:1350
std::mutex _event_mtx
Definition agent.hpp:1371
bool _settings_fetched
Definition agent.hpp:1334
nlohmann::json get_settings()
Get all settings as JSON.
bool running() const
True while this agent's loops should keep going.
Definition agent.hpp:959
static std::tuple< std::string, std::string, std::string > split_URL(const std::string &url)
int settings_timeout()
Returns the value of timeout in loading settings from URI.
bool settings_are_local() const
Detects if settings are local or loaded from URI.
void fetch_settings(bool crypto=false)
Acquires settings (and any broker-served attachment) without binding the agent to a settings section.
void _start_io_thread()
Brings up _io_thread if it is not already running. Called from whichever of connect_pub()/connect_sub...
std::string pub_topic() const
Gets the publish topic.
Definition agent.hpp:765
bool keep_running() const
True while this agent's loops should keep going.
Definition agent.hpp:1187
void install_loop_watchdog(uint8_t max_count=3)
Install a watch thread to ensure exit from loops.
void set_sub_endpoint(std::string endpoint)
Set the subscribe endpoint URL.
Definition agent.hpp:730
void set_settings_timeout(int to)
Sets the value of timeout in loading settings from URI. Set to for no timeout.
zmq::socket_t _publisher
Definition agent.hpp:1317
std::tuple< std::string, std::string, std::vector< unsigned char > > last_blob()
Returns the last received blob by the agent.
std::shared_ptr< Mads::Runtime > runtime() const
The Runtime that owns this agent's run state.
Definition agent.hpp:948
Delivery delivery() const
Current delivery semantics.
bool _cross
Definition agent.hpp:1329
void _apply_socket_options()
Resolves the plain libzmq transport-tuning knobs (ZMQ_DEVELOPMENT.md §1.4: TCP keepalive,...
std::map< std::string, std::shared_ptr< LazyPayload > > _status
Definition agent.hpp:1325
std::atomic< bool > _stopping
Definition agent.hpp:1340
void setup_crypto(Mads::auth_verbose verbose=auth_verbose::off)
Set the use of CURVE encryption and enables authentication.
std::string server_key_name
Definition agent.hpp:1168
void set_key_dir(const std::filesystem::path &path)
Sets the path to the etc directory.
int _settings_timeout
Definition agent.hpp:1332
Compression compression() const
The compression policy used for outgoing messages.
std::tuple< std::string, std::string > last_message()
Returns the last received message by the agent.
void connect_pub(std::chrono::milliseconds delay=std::chrono::milliseconds(0))
Connects the agent to the publish endpoint.
void publish(nlohmann::json payload, std::string topic="")
Publishes a message with the given JSON payload.
zmq::context_t _context
Definition agent.hpp:1316
void register_event(const event_type event=event_type::marker, const nlohmann::json &info=nlohmann::json(), const std::string &info_name="info")
Registers an event.
WireFormat wire_format() const
The wire format used for outgoing messages.
Compression _compression
Definition agent.hpp:1379
bool _rc_owns_socket
Definition agent.hpp:1377
bool _remote_controlled
Definition agent.hpp:1341
bool receive_raw_message(std::string &topic, std::vector< std::string > &parts, bool dont_block=false)
Receives a message without any JSON/blob (de)serialization (P3).
std::thread _clock_thread
Definition agent.hpp:1401
std::vector< std::string > _wildcard_sub_topic
Definition agent.hpp:1315
virtual void load_settings()
Additional settings to be loaded. Virtual function to be implemented by the derived class.
void set_receive_timeout(int to)
Sets the value of timeout in receiving messages. Set to 0 for no timeout.
void connect_sub()
Connects the agent to the subscribe endpoint and subscribes to the topics.
Mads::ClockConsensus _clock_consensus
Definition agent.hpp:1393
std::string _clock_agent_identity() const
std::string _agent_id
Definition agent.hpp:1309
std::unique_ptr< CurveAuth > _curve_auth
Definition agent.hpp:1349
std::string _sub_endpoint
Definition agent.hpp:1307
std::chrono::steady_clock::time_point _clocksync_probe_sent_at
Definition agent.hpp:1406
std::tuple< std::string, std::string, std::vector< unsigned char > > _last_blob
Definition agent.hpp:1327
bool _restart
Definition agent.hpp:1335
std::string last_topic()
Returns the topic of the last received message by the agent.
bool _last_value_only
Definition agent.hpp:1351
void disconnect()
Disconnects the agent from the publish and subscribe endpoints.
Per-clock-domain adoption of the smallest-delay measurement heard from any agent sharing that domain ...
A received message payload that lazily holds either its JSON text or its parsed nlohmann::json form,...
Definition agent.hpp:87
static LazyPayload from_doc(nlohmann::json doc)
Definition agent.hpp:95
LazyPayload()=default
const nlohmann::json & doc() const
Parsed object form (parses the cached text once if only text exists).
Definition agent.hpp:107
const std::string & text() const
JSON text form (dumps the cached object once if only the object exists).
Definition agent.hpp:101
static LazyPayload from_text(std::string text)
Definition agent.hpp:90
One monitor per monitored socket. start() must be called before the socket's connect()/bind(): libzmq...
Definition agent.hpp:67
ClockSource
Which mechanism produced a ClockOffsetResult.
auth_verbose
Definition curve.hpp:35
std::unique_ptr< Agent > start_agent(std::string name, std::string settings_uri, std::map< std::string, std::string > crypto_settings={})
Quick Agent initialization function.
Result of a clock-offset measurement: offset_us added to a clock in the measured domain yields broker...
One responder's answer to Agent::broadcast_clock_probe()'s ping (clock-offset source B,...
Definition agent.hpp:130
std::string responder_domain
Definition agent.hpp:134
std::string responder_hostname
Definition agent.hpp:133
ClockOffsetResult responder_adopted
Definition agent.hpp:138
std::string responder_name
Definition agent.hpp:132
std::string responder_agent_id
Definition agent.hpp:131
One four-timestamp exchange, all fields microseconds since the Unix epoch: t1/t4 read from the initia...
std::mutex mtx
Definition agent.hpp:70
std::condition_variable cv
Definition agent.hpp:71
std::optional< T > value
Definition agent.hpp:72