23#include <parcel/parcel.h>
44 return std::chrono::duration_cast<std::chrono::milliseconds>(
tp.time_since_epoch()).count();
47[[
nodiscard]]
inline std::chrono::system_clock::time_point
49 return std::chrono::system_clock::time_point{std::chrono::milliseconds{
ms}};
62 :
public parcel::BaseCell<EventEnvelope, std::shared_ptr<detail::EnvelopeCore>> {
63 using base_t = parcel::BaseCell<EventEnvelope, std::shared_ptr<detail::EnvelopeCore>>;
66 static constexpr std::string_view
kind_id =
"conduit:envelope";
73 requires std::derived_from<T, parcel::ICell>
74 explicit EventEnvelope(T payload) : base_t(std::make_shared<detail::EnvelopeCore>()) {
75 this->value->payload_cell = std::make_shared<T>(std::move(payload));
79 : base_t(std::make_shared<detail::EnvelopeCore>(std::move(core))) {
80 this->value->payload_cell = std::move(payload);
83 explicit EventEnvelope(std::shared_ptr<detail::EnvelopeCore> core) : base_t(std::move(core)) {}
87 [[nodiscard]]
const ulid::Ulid&
id() const noexcept {
88 return this->value->id;
91 [[nodiscard]] std::string_view
name() const noexcept {
92 if (!this->value || !this->value->payload_cell) {
95 const std::string_view k = this->value->payload_cell->kind();
104 return this->value->flags;
107 return this->value->metadata;
110 return this->value->timestamps;
114 return this->value->correlation_id;
116 [[nodiscard]]
const std::optional<ulid::Ulid>&
causation_id() const noexcept {
117 return this->value->causation_id;
121 return this->value->payload_cell;
126 template <
typename T>
127 [[nodiscard]] std::shared_ptr<const T>
payload_as() const noexcept {
128 if (!this->value || !this->value->payload_cell) {
131 return std::dynamic_pointer_cast<const T>(this->value->payload_cell);
138 return this->value->timestamps;
141 return this->value->metadata;
144 return this->value->flags;
147 [[nodiscard]] std::shared_ptr<detail::EnvelopeCore>
core_ptr() const noexcept {
151 [[nodiscard]]
bool valid() const noexcept {
152 return this->value !=
nullptr && this->value->payload_cell !=
nullptr;
158 return std::string{
name()};
161 [[nodiscard]] parcel::json_t
to_json()
const override;
163 static parcel::cell_t
from_json(parcel::json_t
const& j, parcel::ParcelRegistry
const& reg);
165 [[nodiscard]] std::partial_ordering
compare(parcel::ICell
const& other)
const override {
166 if (
const auto kc = this->kind() <=> other.kind(); kc != 0) {
171 return std::partial_ordering::unordered;
175 static const auto d =
176 std::make_shared<parcel::SimpleCellTypeDescriptor<EventEnvelope>>(parcel::DisplayInfo{
177 .name =
"EventEnvelope",
178 .description =
"Conduit event envelope (custom wire layout).",
195 if (!this->value || !this->value->payload_cell) {
201 parcel::json_t v_obj = parcel::json_t::object();
202 v_obj[
"id"] =
id.string();
203 v_obj[
"name"] = std::string{
name()};
205 parcel::json_t flags_arr = parcel::json_t::array();
206 for (
const auto& f :
flags) {
207 flags_arr.push_back(std::string{f.name});
209 v_obj[
"flags"] = std::move(flags_arr);
218 v_obj[
"metadata"] = md::to_json(
metadata);
220 parcel::json_t ts = parcel::json_t::object();
234 v_obj[
"timestamps"] = std::move(ts);
239 {parcel::ICell::KEY_KIND,
kind_id},
240 {parcel::ICell::KEY_VALUE, std::move(v_obj)},
242 this->inject_display_info(out);
247 parcel::ParcelRegistry
const& reg) {
248 if (!j.is_object()) {
249 throw parcel::InvalidJsonException(
"Expected JSON object for EventEnvelope",
252 const auto it_k = j.find(parcel::ICell::KEY_KIND);
253 if (it_k == j.end() || !it_k->is_string()) {
254 throw parcel::InvalidJsonException(
"EventEnvelope: missing/invalid 'k'",
257 if (it_k->get<std::string_view>() !=
kind_id) {
258 throw parcel::KindMismatchException(
"EventEnvelope: kind mismatch", std::string(
kind_id));
260 const auto it_v = j.find(parcel::ICell::KEY_VALUE);
261 if (it_v == j.end() || !it_v->is_object()) {
262 throw parcel::InvalidJsonException(
"EventEnvelope: missing/invalid 'v' (expected object)",
265 const auto& v = *it_v;
267 auto core = std::make_shared<detail::EnvelopeCore>();
269 if (!v.contains(
"id") || !v.at(
"id").is_string()) {
270 throw parcel::InvalidJsonException(
"EventEnvelope: missing/invalid 'id'",
273 const auto id_opt = ulid::Ulid::from_string(v.at(
"id").get<std::string>());
274 if (!id_opt.has_value()) {
275 throw parcel::InvalidJsonException(
"EventEnvelope: invalid ULID for 'id'",
280 if (v.contains(
"correlation_id")) {
281 const auto cid = ulid::Ulid::from_string(v.at(
"correlation_id").get<std::string>());
282 if (!cid.has_value()) {
283 throw parcel::InvalidJsonException(
"EventEnvelope: invalid ULID for 'correlation_id'",
286 core->correlation_id = *cid;
288 if (v.contains(
"causation_id")) {
289 const auto cid = ulid::Ulid::from_string(v.at(
"causation_id").get<std::string>());
290 if (!cid.has_value()) {
291 throw parcel::InvalidJsonException(
"EventEnvelope: invalid ULID for 'causation_id'",
294 core->causation_id = *cid;
297 if (v.contains(
"flags")) {
298 for (
const auto& fn : v.at(
"flags")) {
299 if (
auto ref = comms::GlobalFlagRegistry::instance().find(fn.get<std::string>())) {
300 core->flags.insert(*ref);
305 if (v.contains(
"metadata")) {
306 if (
const auto& md_json = v.at(
"metadata"); md_json.is_object()) {
307 md::from_json(md_json, core->metadata);
311 if (v.contains(
"timestamps")) {
312 const auto& ts = v.at(
"timestamps");
313 if (ts.contains(
"created_at")) {
314 core->timestamps.created_at =
317 if (ts.contains(
"published_at")) {
318 core->timestamps.published_at =
321 if (ts.contains(
"received_at")) {
322 core->timestamps.received_at =
325 if (ts.contains(
"delivered_at")) {
326 core->timestamps.delivered_at =
329 if (ts.contains(
"failed_at")) {
330 core->timestamps.failed_at =
335 if (!v.contains(
"payload")) {
336 throw parcel::InvalidJsonException(
"EventEnvelope: missing 'payload'",
339 core->payload_cell = reg.cell_from_json(v.at(
"payload"));
341 auto out = std::make_shared<EventEnvelope>(std::move(core));
342 base_t::absorb_display_info(j, out);
Polymorphic envelope cell.
Definition envelope.hpp:62
static parcel::cell_type_descriptor_t descriptor()
Definition envelope.hpp:174
EventEnvelope()
Definition envelope.hpp:68
bool valid() const noexcept
Definition envelope.hpp:151
const flags::FlagSet & flags() const noexcept
Definition envelope.hpp:103
flags::FlagSet & flags() noexcept
Definition envelope.hpp:143
EventEnvelope(std::shared_ptr< detail::EnvelopeCore > core)
Definition envelope.hpp:83
EventEnvelope(T payload)
Build an envelope around a typed payload event.
Definition envelope.hpp:74
const std::optional< ulid::Ulid > & correlation_id() const noexcept
Definition envelope.hpp:113
Metadata & metadata() noexcept
Definition envelope.hpp:140
std::shared_ptr< detail::EnvelopeCore > core_ptr() const noexcept
Definition envelope.hpp:147
const Timestamps & timestamps() const noexcept
Definition envelope.hpp:109
const parcel::cell_t & payload_cell() const noexcept
Definition envelope.hpp:120
parcel::json_t to_json() const override
Definition envelope.hpp:194
Timestamps & timestamps() noexcept
Definition envelope.hpp:137
static parcel::cell_t from_json(parcel::json_t const &j, parcel::ParcelRegistry const ®)
Definition envelope.hpp:246
static constexpr std::string_view kind_id
Definition envelope.hpp:66
std::string_view name() const noexcept
Definition envelope.hpp:91
std::partial_ordering compare(parcel::ICell const &other) const override
Definition envelope.hpp:165
const Metadata & metadata() const noexcept
Definition envelope.hpp:106
std::shared_ptr< const T > payload_as() const noexcept
Typed payload accessor: returns shared_ptr<const T> if the underlying payload is a T cell,...
Definition envelope.hpp:127
const std::optional< ulid::Ulid > & causation_id() const noexcept
Definition envelope.hpp:116
std::string to_string() const override
Definition envelope.hpp:157
const ulid::Ulid & id() const noexcept
Definition envelope.hpp:87
EventEnvelope(detail::EnvelopeCore core, parcel::cell_t payload)
Definition envelope.hpp:78
Raised by envelope/cell deserialization when the wire data is malformed.
Definition exception.hpp:56
Event<Self, Name> library base built on parcel::SelfStructCell.
Root exception hierarchy for the conduit library.
Conduit flag tags, built atop comms::Flag / comms::FlagSet.
flags::FlagSet collect_default_flags()
Definition event.hpp:86
std::chrono::system_clock::time_point from_ms_since_epoch(const std::int64_t ms) noexcept
Definition envelope.hpp:48
std::int64_t to_ms_since_epoch(const std::chrono::system_clock::time_point tp) noexcept
Definition envelope.hpp:43
comms::FlagSet FlagSet
Definition flags.hpp:32
Definition builder.hpp:22
md::Metadata Metadata
Envelope metadata: a typed JSON-shaped key/value tree.
Definition metadata.hpp:20
constexpr std::string_view event_kind_prefix
Wire-kind prefix shared by every conduit event type.
Definition event.hpp:21
Lifecycle timestamps tracked by the bus / middleware / transports.
Definition metadata.hpp:23
std::optional< std::chrono::system_clock::time_point > received_at
Definition metadata.hpp:26
std::optional< std::chrono::system_clock::time_point > published_at
Definition metadata.hpp:25
std::optional< std::chrono::system_clock::time_point > failed_at
Definition metadata.hpp:28
std::optional< std::chrono::system_clock::time_point > delivered_at
Definition metadata.hpp:27
std::chrono::system_clock::time_point created_at
Definition metadata.hpp:24
Internal core shared between envelope copies — accessors return references into this struct so transp...
Definition envelope.hpp:32
parcel::cell_t payload_cell
Definition envelope.hpp:39
std::optional< ulid::Ulid > correlation_id
Definition envelope.hpp:37
std::optional< ulid::Ulid > causation_id
Definition envelope.hpp:38
ulid::Ulid id
Definition envelope.hpp:33
flags::FlagSet flags
Definition envelope.hpp:34
Metadata metadata
Definition envelope.hpp:35
Timestamps timestamps
Definition envelope.hpp:36