use std::fmt;
use chrono::prelude::*;
use uuid::Uuid;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum BusEvent {
HostStarted(String),
HostStopped(String),
ActorStarting { actor: String, host: String },
ActorStarted { actor: String, host: String },
ActorStopped { actor: String, host: String },
ActorUpdating { actor: String, host: String },
ActorUpdateComplete {
actor: String,
success: bool,
host: String,
},
ProviderLoaded {
capid: String,
instance_name: String,
host: String,
},
ProviderRemoved {
capid: String,
instance_name: String,
host: String,
},
ActorBindingCreated {
host: String,
actor: String,
capid: String,
instance_name: String,
},
ActorBindingRemoved {
host: String,
actor: String,
capid: String,
instance_name: String,
},
ActorBecameHealthy { actor: String, host: String },
ActorBecameUnhealthy { actor: String, host: String },
}
const EVENT_TYPE_PREFIX: &str = "wasmbus.events";
impl BusEvent {
pub fn event_type(&self) -> String {
use BusEvent::*;
let suffix = match self {
HostStarted(_) => "host_started",
HostStopped(_) => "host_stopped",
ActorStarting { .. } => "actor_starting",
ActorStarted { .. } => "actor_started",
ActorStopped { .. } => "actor_stopped",
ActorUpdating { .. } => "actor_updating",
ActorUpdateComplete { .. } => "actor_update_complete",
ProviderLoaded { .. } => "provider_loaded",
ProviderRemoved { .. } => "provider_removed",
ActorBindingCreated { .. } => "actor_binding_created",
ActorBindingRemoved { .. } => "actor_binding_removed",
ActorBecameHealthy { .. } => "actor_became_healthy",
ActorBecameUnhealthy { .. } => "actor_became_unhealthy",
};
format!("{}.{}", EVENT_TYPE_PREFIX, suffix)
}
pub fn subject(&self) -> String {
use BusEvent::*;
match self {
HostStarted(h) => h.to_string(),
HostStopped(h) => h.to_string(),
ActorStarting { actor, .. }
| ActorStarted { actor, .. }
| ActorStopped { actor, .. }
| ActorUpdating { actor, .. }
| ActorUpdateComplete { actor, .. } => actor.to_string(),
ProviderLoaded {
capid,
instance_name,
..
}
| ProviderRemoved {
capid,
instance_name,
..
} => format!("{}.{}", capid, instance_name),
ActorBindingCreated {
actor,
capid,
instance_name,
..
}
| ActorBindingRemoved {
actor,
capid,
instance_name,
..
} => format!("{}.{}.{}", actor, capid, instance_name),
ActorBecameHealthy { actor, .. } | ActorBecameUnhealthy { actor, .. } => {
actor.to_string()
}
}
}
}
impl fmt::Display for BusEvent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use BusEvent::*;
match self {
HostStarted(h) => write!(f, "[{}] Host started", h),
HostStopped(h) => write!(f, "[{}] Host stopped", h),
ActorStarting { actor, host } => write!(f, "[{}] Actor {} starting", host, actor),
ActorStarted { actor, host } => write!(f, "[{}] Actor {} started", host, actor),
ActorStopped { actor, host } => write!(f, "[{}] Actor {} stopped", host, actor),
ActorUpdating { actor, host } => write!(f, "[{}] Actor {} updating", host, actor),
ActorUpdateComplete {
actor,
host,
success,
} => write!(
f,
"[{}] Actor {} update {}",
host,
actor,
if *success { "succeeded" } else { "failed" }
),
ProviderLoaded {
capid,
instance_name,
host,
} => write!(f, "[{}] Provider {},{} loaded", host, capid, instance_name),
ProviderRemoved {
capid,
host,
instance_name,
} => write!(f, "[{}] Provider {},{} removed", host, capid, instance_name),
ActorBindingCreated {
actor,
capid,
instance_name,
host,
} => write!(
f,
"[{}] Actor {} bound to {},{}",
host, actor, capid, instance_name
),
ActorBindingRemoved {
actor,
capid,
instance_name,
host,
} => write!(
f,
"[{}] Actor {} un-bound from {},{}",
host, actor, capid, instance_name
),
ActorBecameHealthy { host, actor } => {
write!(f, "[{}] Actor {} became healthy", host, actor)
}
ActorBecameUnhealthy { host, actor } => {
write!(f, "[{}] Actor {} became unhealthy", host, actor)
}
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct CloudEvent {
#[serde(rename = "specversion")]
pub cloud_events_version: String,
#[serde(rename = "type")]
pub event_type: String,
#[serde(rename = "typeversion")]
pub event_type_version: String,
pub source: String,
#[serde(rename = "id")]
pub event_id: String,
#[serde(rename = "time")]
pub event_time: DateTime<Utc>,
#[serde(rename = "datacontenttype")]
pub content_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub subject: Option<String>,
pub data: String,
}
impl From<BusEvent> for CloudEvent {
fn from(event: BusEvent) -> CloudEvent {
let raw_data = serde_json::to_string(&event).unwrap();
CloudEvent {
cloud_events_version: "1.0".to_string(),
event_type: event.event_type(),
event_type_version: "0.1".to_string(),
source: "https://wascc.dev/lattice/events".to_string(),
subject: Some(event.subject()),
event_id: Uuid::new_v4().to_hyphenated().to_string(),
event_time: Utc::now(),
content_type: "application/json".to_string(),
data: raw_data,
}
}
}