Mads
Multi-Agent Distributed System
Loading...
Searching...
No Matches
Mads Namespace Reference

Namespaces

namespace  detail
 
namespace  Doctor
 
namespace  Play
 
namespace  PluginMigrate
 
namespace  PluginSkill
 

Classes

class  Agent
 
class  AgentAppT
 Application-facing wrapper for Agent and Agent subclasses. More...
 
struct  AgentTopicInfo
 One mads.ini agent section's topics. More...
 
class  ARIMA
 
class  BagError
 Error thrown by BagWriter/BagReader for any I/O or format problem (bad magic, unsupported format_ver, unreadable/unwritable file, ...). More...
 
class  BagReader
 Reads a bag file written by BagWriter (or a compatible/truncated one), transparently using the trailing index when present and falling back to a linear scan otherwise. More...
 
struct  BagRecord
 
class  BagWriter
 Sequentially appends BagRecord entries to a bag file. More...
 
class  Bridge
 The Bridge class represents metadata for an agent. More...
 
class  ClockConsensus
 Per-clock-domain adoption of the smallest-delay measurement heard from any agent sharing that domain (§2.1 of the design): agents on one host announce their own measurements, and every agent applies this same deterministic rule – so they converge on one offset without an election. More...
 
class  ClockOffsetEstimator
 Accumulates ClockSamples and returns the classic NTP "best of N": the retained sample with the smallest round-trip delay, i.e. the one least polluted by queuing delay along the path. More...
 
struct  ClockOffsetResult
 Result of a clock-offset measurement: offset_us added to a clock in the measured domain yields broker-host time (broker_host_clock - domain_clock). source/hops/origin_agent_id/seq are Agent-level bookkeeping the estimator does not fill in – only estimate()'s own offset_us/delay_us/samples/valid are computed from the timestamps. More...
 
struct  ClockPeerObservation
 One responder's answer to Agent::broadcast_clock_probe()'s ping (clock-offset source B, see clock_offset.hpp): the raw four-timestamp sample plus the responder's identity and its own currently adopted clock offset, which is what lets an initiator compose clock_offset(mine) = responder_adopted.offset_us + estimate(sample).offset_us rather than treating a peer exchange as an unrelated measurement. More...
 
struct  ClockSample
 One four-timestamp exchange, all fields microseconds since the Unix epoch: t1/t4 read from the initiator's clock, t2/t3 from the responder's. More...
 
class  CurveAuth
 
struct  CurveKeypair
 A CURVE keypair, both keys Z85-encoded (40 characters each). More...
 
class  Dealer
 
struct  DirectorConfig
 A fully parsed, validated, expanded director.toml. processes is already in a valid topological start order (every entry's after names appear earlier in the vector), so mads up can just iterate it in order. More...
 
struct  DirectorLoadOptions
 Caller-supplied overrides applied while the file is expanded. More...
 
class  Dummy
 
struct  EchoRenderOptions
 Rendering choices for format_echo_json()/format_echo_blob(), mirroring mads echo's CLI flags. More...
 
class  ExecutionTimeWindowStats
 Running window statistics for execution time samples. More...
 
class  GoBack
 
struct  GraphOptions
 Rendering knobs for topology_graph(). More...
 
struct  HostSkewStat
 Snapshot of one host's passive clock skew, as computed by HostSkewStats::snapshot() at a given instant. More...
 
class  HostSkewStats
 Thread-safe sliding-window tracker of per-host clock skew, fed by mads top's passive mode: for every received message, record (local_rx_time - payload's own timestamp field), both as epoch microseconds. No protocol at all – works against any existing MADS deployment, since timestamp/hostname are already stamped on every published message by Agent::publish(). More...
 
class  HttpsClient
 Portable HTTPS GET client with zero external dependencies. More...
 
class  Image
 The RFID class represents metadata for an agent. More...
 
struct  image_data_t
 
class  LazyPayload
 A received message payload that lazily holds either its JSON text or its parsed nlohmann::json form, caching whichever is produced on first use. More...
 
struct  LinkState
 
class  Logger
 The Logger class is responsible for logging messages to a MongoDB instance. More...
 
class  Metadata
 The Metadata class represents metadata for an agent. More...
 
class  MongoFetch
 Replay reader over one or more MongoDB collections. More...
 
struct  ProbeCurveKeys
 Client-side CURVE credentials for a probe socket: the same key_dir/client/server naming convention every mads-* executable's –crypto/–keys_dir/–key_client/–key_broker flags configure (and that Mads::CurveAuth::setup_curve_client() reads). More...
 
struct  ProcessConfig
 One process instance, after scale expansion and template substitution. This is what mads up actually starts: one ProcessConfig per launched OS process. More...
 
struct  ReadySpec
 A parsed, validated ready = "..." value. More...
 
struct  RunResult
 
class  ServiceDiscovery
 
struct  SharedLatest
 
class  SocketMonitor
 One monitor per monitored socket. start() must be called before the socket's connect()/bind(): libzmq lets a connection through – and may fire its lifecycle events – while no monitor is attached yet, exactly the same race Mads::ZapAuth::start() avoids for the ZAP handler. More...
 
struct  TopicStat
 Snapshot of one topic's aggregated activity, as computed by TopicStats::snapshot() at a given instant. More...
 
class  TopicStats
 Thread-safe sliding-window aggregator of per-topic msg/s and bytes/s, fed by record() and read back via snapshot(). More...
 
struct  UpOptions
 
class  UpSupervisor
 Starts, supervises and tears down the processes described by an expanded Mads::DirectorConfig. Foreground-only by design (see NEW_FEATURES.md P5): one call to run() drives the whole lifecycle and blocks until teardown completes. More...
 
class  Watcher
 
class  Worker
 
class  ZapAuth
 In-process ZAP (ZeroMQ Authentication Protocol, RFC 27) handler. More...
 

Typedefs

using AgentApp = AgentAppT< Agent >
 
template<typename AgentT >
using AgentAppFor = AgentAppT< AgentT >
 
using json = nlohmann::json
 
using LiveSubscriptions = std::map< std::string, int >
 

Enumerations

enum class  CurveProbeResult { Connected , RejectedAuth , Timeout }
 
enum class  ClockSource { None = 0 , Broker = 1 , Peer = 2 }
 Which mechanism produced a ClockOffsetResult. More...
 
enum class  auth_verbose { off , on }
 
enum class  ReadyKind { Broker , Port , Log , Delay }
 Discriminates the four ready = "..." probe kinds. More...
 
enum class  LinkEvent {
  None , Connected , ConnectDelayed , ConnectRetried ,
  HandshakeSucceeded , HandshakeFailedAuth , HandshakeFailedProtocol , HandshakeFailedNoDetail ,
  Disconnected , AcceptFailed
}
 
enum class  LinkStatus { Unknown , Up , Down }
 
enum class  SubMatch { None , Exact , Prefix , Wildcard }
 
enum class  RunOutcome {
  Ok , Timeout , ReadyTimeout , StartFailed ,
  ProcessFailed
}
 

Functions

std::unique_ptr< Agentstart_agent (std::string name, std::string settings_uri, std::map< std::string, std::string > crypto_settings={})
 Quick Agent initialization function.
 
bool probe_broker (const std::string &uri, std::chrono::milliseconds timeout, const std::optional< ProbeCurveKeys > &curve=std::nullopt)
 Probes whether a MADS broker's settings endpoint is up and speaking the MADS wire protocol: connects a REQ socket to uri, sends [LIB_VERSION, "settings", <probe-name>] and waits up to timeout for any reply. Any protocol-shaped reply counts as success – this does not try to load or validate settings for a real agent, it only proves the broker is listening and answering. ZeroMQ's own TCP reconnect logic means a single bounded receive is enough to also cover "not up yet" within timeout.
 
bool probe_tcp_port (const std::string &host, int port, std::chrono::milliseconds timeout)
 Probes whether a local TCP port is accepting connections, retrying (short bounded attempts) until timeout elapses. Used by ready = "port:<n>".
 
CurveProbeResult probe_curve_handshake (const std::string &uri, const std::filesystem::path &key_dir, const std::string &client_key_name, const std::string &server_key_name, std::chrono::milliseconds timeout)
 Attempts a real CURVE handshake against uri, using the client and server keys Mads::CurveAuth::setup_curve_client() reads from key_dir (same file convention as mads doctor --crypto's key check). A Mads::SocketMonitor attached before connecting distinguishes a genuine ZMQ_EVENT_HANDSHAKE_FAILED_AUTH rejection from an unreachable broker or an unresponsive one, both of which previously looked identical – a timeout.
 
std::optional< std::map< std::string, int > > fetch_subscription_table (const std::string &sub_uri, std::chrono::milliseconds timeout, const std::optional< ProbeCurveKeys > &curve=std::nullopt)
 Reads one live subscription table off a broker that was started with [broker] subscription_table = true, by subscribing to the subscriptions topic exactly as any ordinary agent would.
 
ClockOffsetResult estimate (const ClockSample &s)
 NTP-style estimate from one four-timestamp exchange.
 
std::optional< std::chrono::milliseconds > parse_duration (const std::string &text)
 Parses a duration string like "500ms", "2s", "1.5s", "3m" into a std::chrono::milliseconds value. A bare number (no unit) is interpreted as seconds. Returns std::nullopt on malformed input (empty string, non-numeric magnitude, unknown unit, or a negative value).
 
std::optional< ReadySpecparse_ready_spec (const std::string &value, std::string *out_error)
 Parses a raw ready string into a ReadySpec. Exposed standalone (rather than only reachable through load_director_config()) so it has its own focused unit tests.
 
std::optional< DirectorConfigload_director_config (const std::string &path, std::string *out_error, std::vector< std::string > *out_warnings=nullptr, const DirectorLoadOptions &options={})
 Loads, validates, expands and orders a director.toml file.
 
std::string format_echo_json (const std::string &topic, const nlohmann::json &payload, size_t wire_size, const EchoRenderOptions &opts)
 Formats one received JSON message for mads echo stdout.
 
std::string format_echo_blob (const std::string &topic, const std::string &format, const unsigned char *data, size_t len, const EchoRenderOptions &opts)
 Formats one received blob message for mads echo stdout.
 
std::string base64_encode (const unsigned char *data, size_t len)
 Standard base64 encoding (RFC 4648, with = padding).
 
std::filesystem::path exec_path ()
 
std::string exec_dir (std::string relative="")
 
std::string prefix ()
 
GoBack goback (std::size_t lines, bool really=true)
 
bool topic_match (std::string_view pattern, std::string_view topic)
 Tests whether a concrete topic matches an MQTT-style pattern.
 
bool has_wildcard (std::string_view sub_entry)
 Tells whether a sub_topic entry is a wildcard pattern.
 
SubMatch subscription_match (std::string_view sub_entry, std::string_view topic)
 Single source of truth for "would an agent subscribing to `sub_entry` receive a message published on `topic`?".
 
bool subscription_matches (std::string_view sub_entry, std::string_view topic)
 Convenience predicate over subscription_match().
 
std::string literal_prefix (std::string_view pattern)
 Computes the longest literal (wildcard-free) prefix of a pattern.
 
bool is_implicitly_subscribed_topic (const std::string &topic)
 
std::string topology_graph (const std::map< std::string, AgentTopicInfo > &agents, const GraphOptions &options={})
 Builds Graphviz DOT text describing the declared pub/sub topology of a set of agent sections.
 
CurveKeypair generate_keypair ()
 Generate a fresh CURVE keypair.
 
std::string z85_encode (const std::string &data)
 Z85-encode a binary buffer.
 

Variables

constexpr uint32_t BAG_FORMAT_VERSION = 1
 
constexpr const char * kDefaultBrokerProbeUri = "tcp://localhost:9092"
 Default broker settings URI probed by a bare ready = "broker".
 

Typedef Documentation

◆ AgentApp

using Mads::AgentApp = typedef AgentAppT<Agent>

Definition at line 654 of file agent_app.hpp.

◆ AgentAppFor

template<typename AgentT >
using Mads::AgentAppFor = typedef AgentAppT<AgentT>

Definition at line 657 of file agent_app.hpp.

◆ json

using Mads::json = typedef nlohmann::json

Definition at line 18 of file service_discovery.hpp.

◆ LiveSubscriptions

using Mads::LiveSubscriptions = typedef std::map<std::string, int>

A live topic -> subscriber-count table as published by a broker running with [broker] subscription_table = true (see Mads::fetch_subscription_table()).

Keys are the prefixes agents actually passed to zmq_setsockopt(ZMQ_SUBSCRIBE), i.e. a declared sub_topic entry after Mads::literal_prefix() – so a wildcard entry appears under its literal prefix, never as the pattern. The table carries NO peer identity (ZMQ subscription frames have none), so it can only ever answer "is anyone subscribed to this prefix", never "which agent".

Definition at line 61 of file topology_graph.hpp.

Enumeration Type Documentation

◆ auth_verbose

enum class Mads::auth_verbose
strong
Enumerator
off 
on 

Definition at line 35 of file curve.hpp.

◆ ClockSource

enum class Mads::ClockSource
strong

Which mechanism produced a ClockOffsetResult.

Enumerator
None 
Broker 
Peer 

Definition at line 42 of file clock_offset.hpp.

◆ CurveProbeResult

enum class Mads::CurveProbeResult
strong

Outcome of a CURVE-handshake probe (ZMQ_DEVELOPMENT.md §2.1): what a socket monitor actually observed, distinguishing "the broker rejected this key" from "nothing answered at all" – a rejection previously surfaced as an identical bare timeout in both cases.

Enumerator
Connected 
RejectedAuth 
Timeout 

Definition at line 88 of file broker_probe.hpp.

◆ LinkEvent

enum class Mads::LinkEvent
strong

The connectivity events SocketMonitor exposes, condensed from libzmq's full ZMQ_EVENT_* set (zmq_socket_monitor(3)) down to what a caller acts on: is the link up, did the handshake fail, and if so why.

Enumerator
None 
Connected 
ConnectDelayed 
ConnectRetried 
HandshakeSucceeded 
HandshakeFailedAuth 
HandshakeFailedProtocol 
HandshakeFailedNoDetail 
Disconnected 
AcceptFailed 

A bound socket could not accept an inbound connection. Unlike every other event here this describes the listener, not a link: the peer it would have belonged to never got far enough to have one. The errno libzmq reported (EMFILE when the process is out of file descriptors) arrives with it, in LinkState::last_event_value.

Definition at line 31 of file socket_monitor.hpp.

◆ LinkStatus

enum class Mads::LinkStatus
strong

Whether the link is usable right now. Where LinkEvent is a point-in-time observation, this is the state those observations add up to – which is what a caller reporting "am I still talking to the broker?" actually needs.

Enumerator
Unknown 

no event has settled the question yet (also: inproc://, which libzmq does not report monitor events for at all)

Up 

the ZMTP handshake completed and has not been undone since

Down 

the peer went away, or the handshake was refused

Definition at line 53 of file socket_monitor.hpp.

◆ ReadyKind

enum class Mads::ReadyKind
strong

Discriminates the four ready = "..." probe kinds.

Enumerator
Broker 
Port 
Log 
Delay 

Definition at line 51 of file director_config.hpp.

◆ RunOutcome

enum class Mads::RunOutcome
strong
Enumerator
Ok 
Timeout 
ReadyTimeout 
StartFailed 
ProcessFailed 

Definition at line 62 of file up_supervisor.hpp.

◆ SubMatch

enum class Mads::SubMatch
strong

How one sub_topic entry matched a concrete published topic. See subscription_match(): the two literal outcomes exist because a literal entry is issued verbatim as a raw ZeroMQ SUBSCRIBE frame, which matches by byte prefix, so "sensors" genuinely receives "sensors/imu/raw" too.

Enumerator
None 

Not delivered.

Exact 

Literal entry equal to the topic.

Prefix 

Literal entry that is a strict byte prefix of the topic.

Wildcard 

Entry containing '+'/'#', matched per topic_match().

Definition at line 80 of file topic_match.hpp.

Function Documentation

◆ base64_encode()

std::string Mads::base64_encode ( const unsigned char *  data,
size_t  len 
)

Standard base64 encoding (RFC 4648, with = padding).

Exposed mainly so tests can decode format_echo_*'s --raw output without duplicating the alphabet; mads echo itself only ever encodes.

◆ estimate()

ClockOffsetResult Mads::estimate ( const ClockSample s)

NTP-style estimate from one four-timestamp exchange.

offset_us = ((t2-t1) + (t3-t4)) / 2 (assumes a symmetric path; an asymmetric one biases the estimate by half the asymmetry – this is a property of the algorithm, not a bug, and is why several samples and ClockOffsetEstimator::best() matter).

delay_us is (s.local_elapsed_us - (t3-t2)) when local_elapsed_us is non-zero, so a system_clock step or manual date change occurring during the exchange cannot produce a negative or absurd delay; it falls back to (t4-t1) - (t3-t2) otherwise.

Only offset_us/delay_us/samples(=1)/valid are set; source/hops/ origin_agent_id/seq are Agent-level bookkeeping filled in by the caller.

◆ exec_dir()

std::string Mads::exec_dir ( std::string  relative = "")
inline

Definition at line 62 of file exec_path.hpp.

References exec_path().

Referenced by Mads::AgentAppT< AgentT >::add_common_options(), and prefix().

◆ exec_path()

std::filesystem::path Mads::exec_path ( )
inline

Definition at line 46 of file exec_path.hpp.

Referenced by exec_dir().

◆ fetch_subscription_table()

std::optional< std::map< std::string, int > > Mads::fetch_subscription_table ( const std::string &  sub_uri,
std::chrono::milliseconds  timeout,
const std::optional< ProbeCurveKeys > &  curve = std::nullopt 
)

Reads one live subscription table off a broker that was started with [broker] subscription_table = true, by subscribing to the subscriptions topic exactly as any ordinary agent would.

The table is a topic -> live-subscriber-count map, built by the broker from its XPUB backend's own subscribe/unsubscribe notifications. It is deliberately anonymous: ZMQ subscription frames carry no peer identity, so this says how many sockets are subscribed to a prefix, never which agents they belong to. Keys are the prefixes actually passed to zmq_setsockopt(ZMQ_SUBSCRIBE), i.e. a declared sub_topic entry after Mads::literal_prefix() – a wildcard entry appears here as its literal prefix, not as the pattern.

The broker republishes the table about once a second, so timeout must comfortably exceed that to be reliable; 2000 ms or more is sensible.

Parameters
sub_urithe broker's backend (subscribe) endpoint, i.e. where agents connect their SUB sockets.
timeouthow long to wait for one table to arrive.
curveCURVE credentials to subscribe with; must be set when the broker runs with –crypto, exactly as for any other agent's SUB socket.
Returns
the decoded table, or nullopt if none arrived in time (broker down, subscription_table not enabled, or the wrong encryption mode for this broker). Never throws.

◆ format_echo_blob()

std::string Mads::format_echo_blob ( const std::string &  topic,
const std::string &  format,
const unsigned char *  data,
size_t  len,
const EchoRenderOptions opts 
)

Formats one received blob message for mads echo stdout.

Parameters
topicThe message's topic.
formatThe blob's declared format (e.g. "raw"), from its metadata; "raw" is used when the metadata did not specify one.
dataPointer to the blob bytes (may be null iff len == 0).
lenNumber of bytes in the blob.
optsRendering choices.
Returns
The complete, newline-terminated text to print.

◆ format_echo_json()

std::string Mads::format_echo_json ( const std::string &  topic,
const nlohmann::json &  payload,
size_t  wire_size,
const EchoRenderOptions opts 
)

Formats one received JSON message for mads echo stdout.

Parameters
topicThe message's topic.
payloadThe already-decoded JSON payload.
wire_sizeSize, in bytes, of the message as it arrived on the wire (independent of the pretty-printed width).
optsRendering choices.
Returns
The complete, newline-terminated text to print.

◆ generate_keypair()

CurveKeypair Mads::generate_keypair ( )

Generate a fresh CURVE keypair.

Replaces zmqpp::curve::generate_keypair(); cppzmq exposes no wrapper for zmq_curve_keypair(), so the C API is called directly (as doctor_checks.cpp already does for zmq_z85_decode).

Returns
The new keypair.
Exceptions
zmq::error_tif libzmq was built without CURVE support.

Referenced by zmqpp::curve::generate_keypair().

◆ goback()

GoBack Mads::goback ( std::size_t  lines,
bool  really = true 
)
inline

Definition at line 121 of file goback.hpp.

◆ has_wildcard()

bool Mads::has_wildcard ( std::string_view  sub_entry)

Tells whether a sub_topic entry is a wildcard pattern.

Deliberately as coarse as the runtime check it replaces: ANY occurrence of '+' or '#' anywhere in the string, not just a whole wildcard token. A entry like "a+b" therefore takes the wildcard path even though topic_match() matches its "a+b" token literally – keeping the two in step matters more than the (unreachable in practice) tightening, since Agent::connect_sub() and every consumer of subscription_match() must classify an entry the same way or the graph and the wire disagree.

Parameters
sub_entryOne sub_topic entry.
Returns
true if the entry must be handled as an MQTT-style pattern.

◆ is_implicitly_subscribed_topic()

bool Mads::is_implicitly_subscribed_topic ( const std::string &  topic)

Topics MADS subscribes to programmatically rather than through a declared sub_topic, plus the one this very query creates. They appear in a live table with nobody having declared them, and reporting them as undeclared subscribers would cry wolf on every single run:

◆ literal_prefix()

std::string Mads::literal_prefix ( std::string_view  pattern)

Computes the longest literal (wildcard-free) prefix of a pattern.

Meant to be issued as the raw ZeroMQ SUBSCRIBE frame for a wildcard pattern: it must be a byte-prefix of every topic topic_match() would accept for that pattern (a superset is fine – broader than needed, e.g. "sensors/+/x" -> "sensors/", and topic_match() narrows it back down on the receive side – but never a subset, or a real match gets silently dropped by ZMQ before topic_match() ever runs).

  • A pattern with no '+'/'#' has no wildcard to stop at, so the whole pattern is returned unchanged.
  • A pattern that starts with a wildcard token (e.g. "+/x") has no literal run at all, so the empty string is returned.
  • Otherwise, the result is every full topic level before the first wildcard token. If that wildcard token is '+', a trailing '/' is appended, since '+' always requires one more level to follow (e.g. "sensors/+/x" -> "sensors/"), which keeps the ZMQ-level subscribe tighter without excluding any real match. If it is '#', NO trailing '/' is appended: '#' also matches the literal path built so far with no further level required (MQTT's "also matches the parent topic itself" rule, e.g. pattern "sensors/#" matches topic "sensors"), so "sensors/#" -> "sensors", not "sensors/" – the latter would be a byte-prefix that excludes the bare topic "sensors" itself.
Parameters
patternSubscription pattern.
Returns
The literal prefix, suitable for zmq::sockopt::subscribe.

◆ load_director_config()

std::optional< DirectorConfig > Mads::load_director_config ( const std::string &  path,
std::string *  out_error,
std::vector< std::string > *  out_warnings = nullptr,
const DirectorLoadOptions options = {} 
)

Loads, validates, expands and orders a director.toml file.

Parameters
pathpath to the director.toml file.
out_errorset to a human-readable message on failure (malformed TOML, missing/invalid command, unknown after target, dependency cycle, invalid scale, duplicate process name, invalid ready value, etc).
out_warningsif non-null, appended with one human-readable message per ignored unknown key/section. This module never writes to stdout/stderr itself (it stays a pure function of its input); the caller (mads-up) decides how to display these.
optionsoverrides applied during expansion; see DirectorLoadOptions. Defaulted, so existing call sites are unaffected.
Returns
the config on success; std::nullopt on failure.

Unknown top-level keys/sections/tables and unknown keys inside a process table are ignored, never fatal – a deliberate design choice (see NEW_FEATURES.md's P5 "Parser ownership" decision), not a fidelity match to Director's own parser (which is stricter about non-table top-level entries; see the comment at the top of director_config.cpp).

◆ parse_duration()

std::optional< std::chrono::milliseconds > Mads::parse_duration ( const std::string &  text)

Parses a duration string like "500ms", "2s", "1.5s", "3m" into a std::chrono::milliseconds value. A bare number (no unit) is interpreted as seconds. Returns std::nullopt on malformed input (empty string, non-numeric magnitude, unknown unit, or a negative value).

Recognized units: "ms" (milliseconds), "s" (seconds), "m" (minutes). Used both by ready = "delay:<dur>" and by mads-up's CLI duration flags (–timeout, –grace), so it lives here rather than duplicated in up.cpp.

◆ parse_ready_spec()

std::optional< ReadySpec > Mads::parse_ready_spec ( const std::string &  value,
std::string *  out_error 
)

Parses a raw ready string into a ReadySpec. Exposed standalone (rather than only reachable through load_director_config()) so it has its own focused unit tests.

◆ prefix()

std::string Mads::prefix ( )
inline

Definition at line 71 of file exec_path.hpp.

References exec_dir().

◆ probe_broker()

bool Mads::probe_broker ( const std::string &  uri,
std::chrono::milliseconds  timeout,
const std::optional< ProbeCurveKeys > &  curve = std::nullopt 
)

Probes whether a MADS broker's settings endpoint is up and speaking the MADS wire protocol: connects a REQ socket to uri, sends [LIB_VERSION, "settings", <probe-name>] and waits up to timeout for any reply. Any protocol-shaped reply counts as success – this does not try to load or validate settings for a real agent, it only proves the broker is listening and answering. ZeroMQ's own TCP reconnect logic means a single bounded receive is enough to also cover "not up yet" within timeout.

Parameters
uribroker settings endpoint, e.g. "tcp://localhost:9092".
timeouttime budget to wait for a reachable broker.
curveCURVE credentials to probe with; must be set to reach a broker running with –crypto, and must be unset to reach one without it.
Returns
true if the broker replied within timeout, false otherwise (never throws – unreadable key files are reported as "no reply").

◆ probe_curve_handshake()

CurveProbeResult Mads::probe_curve_handshake ( const std::string &  uri,
const std::filesystem::path &  key_dir,
const std::string &  client_key_name,
const std::string &  server_key_name,
std::chrono::milliseconds  timeout 
)

Attempts a real CURVE handshake against uri, using the client and server keys Mads::CurveAuth::setup_curve_client() reads from key_dir (same file convention as mads doctor --crypto's key check). A Mads::SocketMonitor attached before connecting distinguishes a genuine ZMQ_EVENT_HANDSHAKE_FAILED_AUTH rejection from an unreachable broker or an unresponsive one, both of which previously looked identical – a timeout.

Parameters
uribroker endpoint to connect a CURVE client socket to (frontend, backend, or settings – any CURVE-secured socket works).
key_dirdirectory holding the client/server key files.
client_key_namebase name of the client's key files.
server_key_namebase name of the server's public key file.
timeouttime budget to wait for the handshake to resolve.
Returns
the observed outcome; never throws (a key-loading failure or any other exception is reported as Timeout).

◆ probe_tcp_port()

bool Mads::probe_tcp_port ( const std::string &  host,
int  port,
std::chrono::milliseconds  timeout 
)

Probes whether a local TCP port is accepting connections, retrying (short bounded attempts) until timeout elapses. Used by ready = "port:<n>".

Parameters
hosthostname or IP to probe; "localhost" and an empty string both mean 127.0.0.1.
portTCP port number.
timeouttime budget to wait for the port to start accepting.
Returns
true if a connection succeeded within timeout, false otherwise (never throws).

◆ start_agent()

std::unique_ptr< Agent > Mads::start_agent ( std::string  name,
std::string  settings_uri,
std::map< std::string, std::string >  crypto_settings = {} 
)

Quick Agent initialization function.

Parameters
nameAgent's name
settings_uriURI for the settings file (e.g. "/path/to/mads.ini" or "tcp://broker:5555")
crypto_settingsA map with crypto settings. If empty, crypto is disabled. If not empty, it must contain the following keys: key_dir, key_client, key_broker.
Returns
Agent A unique pointer to the initialized Agent object. The agent is already connected and ready to use.
Exceptions
AgentErrorif there is an error in the initialization (e.g. settings file
Examples
/home/runner/work/MADS/MADS/src/agent.hpp.

◆ subscription_match()

SubMatch Mads::subscription_match ( std::string_view  sub_entry,
std::string_view  topic 
)

Single source of truth for "would an agent subscribing to `sub_entry` receive a message published on `topic`?".

Reproduces both stages of the runtime subscribe path exactly (see Agent::connect_sub() / Agent::_topic_matches_subscription(), which are implemented on top of this function):

  • A literal entry (no '+'/'#') is passed straight to the ZMQ SUBSCRIBE option, whose matching rule is a raw byte prefix. Hence SubMatch::Prefix: entry "sensors" receives "sensors/imu/raw", and the subscribe-all convention sub_topic = [""] receives everything. NOTE this is not topic_match()'s rule – topic_match() is exact-literal and would reject both.
  • A wildcard entry subscribes literal_prefix() at the ZMQ layer and is then narrowed by topic_match() before delivery, so only a full MQTT-style match counts (SubMatch::Wildcard).
Parameters
sub_entryOne sub_topic entry (pattern or literal).
topicConcrete published topic.
Returns
How the entry matched, or SubMatch::None if it did not.

Referenced by subscription_matches().

◆ subscription_matches()

bool Mads::subscription_matches ( std::string_view  sub_entry,
std::string_view  topic 
)
inline

Convenience predicate over subscription_match().

Parameters
sub_entryOne sub_topic entry.
topicConcrete published topic.
Returns
true if the message would be delivered.

Definition at line 118 of file topic_match.hpp.

References None, and subscription_match().

◆ topic_match()

bool Mads::topic_match ( std::string_view  pattern,
std::string_view  topic 
)

Tests whether a concrete topic matches an MQTT-style pattern.

Parameters
patternSubscription pattern, e.g. "sensors/+/x" or "sensors/#".
topicConcrete topic to test, e.g. "sensors/acc/x".
Returns
true if topic matches pattern, per the grammar documented at the top of this file.

◆ topology_graph()

std::string Mads::topology_graph ( const std::map< std::string, AgentTopicInfo > &  agents,
const GraphOptions options = {} 
)

Builds Graphviz DOT text describing the declared pub/sub topology of a set of agent sections.

One record-shaped node per entry, colored by inferred role (source = declared pub_topic only -> darkred; filter = both -> darkgreen; sink = sub_topic only -> darkblue; neither -> no color attribute; the role is always read off the declared keys, so an implicit pub_topic never turns a sink green), with a dashed contour on any agent that has a dangling topic: a declared pub_topic nothing subscribes to, or a sub_topic entry nothing ever publishes to. Every dangling topic is also marked in the node's own label with a trailing [!], so which entry is dead is visible without cross-referencing the edges. An agent's own pub_topic matching its own sub_topic – a self-loop – counts as satisfied on both sides, matching real broker behavior.

One edge is drawn per matching (publisher, subscriber) section pair, where "matching" is Mads::subscription_match(), i.e. exactly what the agent would receive on the wire: literal sub_topic entries match by byte prefix (sensors receives sensors/imu/raw; "" receives everything) and wildcard entries match per MQTT rules. Because those looser matches are precisely what a topology graph is for, how the edge came to exist is encoded in it: solid for an exact match, dashed for a prefix catch, dotted for a wildcard, and any non-exact edge names the responsible pattern(s) in its label (topic over via pattern, ..., with the subscribe-all pattern shown as (all)). An edge published under an implicit pub_topic is additionally drawn in grey. Edges are only drawn between distinct sections (a self-match never produces a self-loop edge, though it still counts toward the dangling computation above).

Parameters
agentsMap of section name -> declared topics. A std::map is used (rather than unordered_map) so node/edge emission order is deterministic (alphabetical by section name), which keeps output diffable and unit tests exact-string-comparable.
optionsRendering knobs; see GraphOptions.
Returns
The complete digraph mads { ... } DOT text, newline-terminated.

◆ z85_encode()

std::string Mads::z85_encode ( const std::string &  data)

Z85-encode a binary buffer.

Parameters
dataThe bytes to encode; the length must be a multiple of 4.
Returns
The Z85 text, or an empty string if the input length is invalid.

Variable Documentation

◆ BAG_FORMAT_VERSION

constexpr uint32_t Mads::BAG_FORMAT_VERSION = 1
inlineconstexpr

Current on-disk format version written by BagWriter. BagReader accepts any format_ver <= this value.

Definition at line 92 of file bag.hpp.

◆ kDefaultBrokerProbeUri

constexpr const char* Mads::kDefaultBrokerProbeUri = "tcp://localhost:9092"
constexpr

Default broker settings URI probed by a bare ready = "broker".

Definition at line 72 of file director_config.hpp.