///|
/// MoonEvent is a small event bus and message abstraction layer.
pub(all) enum DispatchControl {
Continue
Stop
} derive(Eq, Debug)
///|
pub(all) enum HandlerStatus {
Handled
Ignored
Failed(String)
} derive(Eq, Debug)
///|
pub(all) struct Event {
name : String
topic : String
payload : String
tags : Array[String]
priority : Int
correlation_id : String
} derive(Eq, Debug)
///|
pub(all) struct HandlerReport {
handler : String
status : HandlerStatus
note : String
} derive(Eq, Debug)
///|
pub(all) struct DispatchReport {
event : Event
delivered : Int
ignored : Int
failed : Int
stopped : Bool
reports : Array[HandlerReport]
} derive(Eq, Debug)
///|
pub(all) struct Subscription {
id : Int
name : String
topic : String
tag : String
min_priority : Int
once : Bool
active : Bool
} derive(Eq, Debug)
///|
pub fn Event::new(
name : String,
topic? : String = "",
payload? : String = "",
tags? : Array[String] = [],
priority? : Int = 0,
correlation_id? : String = "",
) -> Event {
{ name, topic, payload, tags, priority, correlation_id }
}
///|
pub fn Subscription::new(
id : Int,
name : String,
topic? : String = "",
tag? : String = "",
min_priority? : Int = 0,
once? : Bool = false,
) -> Subscription {
{ id, name, topic, tag, min_priority, once, active: true }
}
///|
pub fn Event::has_tag(self : Event, tag : String) -> Bool {
self.tags.contains(tag)
}
///|
pub fn Event::matches_topic(self : Event, topic : String) -> Bool {
topic_matches(topic, self.topic)
}
///|
pub fn Event::summary(self : Event) -> String {
self.name + "@" + self.topic + "#" + self.correlation_id
}
///|
pub fn Subscription::matches(self : Subscription, event : Event) -> Bool {
if !self.active {
false
} else if !topic_matches(self.topic, event.topic) {
false
} else if self.tag != "" && !event.has_tag(self.tag) {
false
} else {
event.priority >= self.min_priority
}
}
///|
pub fn HandlerReport::ok(
handler : String,
note? : String = "",
) -> HandlerReport {
{ handler, status: Handled, note }
}
///|
pub fn HandlerReport::ignored(
handler : String,
note? : String = "",
) -> HandlerReport {
{ handler, status: Ignored, note }
}
///|
pub fn HandlerReport::failed(
handler : String,
reason : String,
) -> HandlerReport {
{ handler, status: Failed(reason), note: reason }
}
///|
fn count_failed(reports : Array[HandlerReport]) -> Int {
let mut total = 0
for report in reports {
match report.status {
Failed(_) => total = total + 1
_ => ()
}
}
total
}
///|
fn count_ignored(reports : Array[HandlerReport]) -> Int {
let mut total = 0
for report in reports {
match report.status {
Ignored => total = total + 1
_ => ()
}
}
total
}
///|
pub fn DispatchReport::from_reports(
event : Event,
reports : Array[HandlerReport],
stopped? : Bool = false,
) -> DispatchReport {
let failed = count_failed(reports)
let ignored = count_ignored(reports)
{
event,
delivered: reports.length() - failed - ignored,
ignored,
failed,
stopped,
reports,
}
}
///|
pub fn DispatchReport::is_ok(self : DispatchReport) -> Bool {
self.failed == 0
}
///|
pub fn dispatch(
event : Event,
subscriptions : Array[Subscription],
) -> DispatchReport {
let reports : Array[HandlerReport] = []
let mut stopped = false
for sub in subscriptions {
if stopped {
()
} else if sub.matches(event) {
reports.push(HandlerReport::ok(sub.name, note="matched"))
if sub.once {
stopped = true
}
} else {
reports.push(HandlerReport::ignored(sub.name, note="filtered"))
}
}
DispatchReport::from_reports(event, reports, stopped~)
}
///|
pub fn publish_name(
name : String,
subscriptions : Array[Subscription],
) -> DispatchReport {
dispatch(Event::new(name), subscriptions)
}
///|
pub fn filter_by_topic(
subscriptions : Array[Subscription],
topic : String,
) -> Array[Subscription] {
let out : Array[Subscription] = []
for sub in subscriptions {
if sub.topic == topic {
out.push(sub)
}
}
out
}
///|
pub fn active_count(subscriptions : Array[Subscription]) -> Int {
let mut total = 0
for sub in subscriptions {
if sub.active {
total = total + 1
}
}
total
}