use std::sync::Arc;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use tokio::sync::broadcast;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Subsystem {
Workflow,
Auth,
Secrets,
System,
}
impl Subsystem {
pub fn as_str(&self) -> &'static str {
match self {
Subsystem::Workflow => "workflow",
Subsystem::Auth => "auth",
Subsystem::Secrets => "secrets",
Subsystem::System => "system",
}
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Subsystem {
match s {
"workflow" => Subsystem::Workflow,
"auth" => Subsystem::Auth,
"secrets" => Subsystem::Secrets,
_ => Subsystem::System,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Event {
pub id: i64,
pub ts: f64,
pub namespace: String,
pub subsystem: Subsystem,
pub kind: String,
pub payload: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct NewEvent<'a> {
pub namespace: &'a str,
pub subsystem: Subsystem,
pub kind: &'a str,
pub payload: serde_json::Value,
}
#[derive(Debug, Clone, Default)]
pub struct EventFilter {
pub subsystems: Vec<Subsystem>,
pub kinds: Vec<String>,
pub workflow_id: Option<String>,
}
impl EventFilter {
pub fn matches(&self, e: &Event) -> bool {
if !self.subsystems.is_empty() && !self.subsystems.contains(&e.subsystem) {
return false;
}
if !self.kinds.is_empty() && !self.kinds.iter().any(|k| k == &e.kind) {
return false;
}
if let Some(ref wf_id) = self.workflow_id
&& e.payload.get("workflow_id").and_then(|v| v.as_str()) != Some(wf_id)
{
return false;
}
true
}
}
#[derive(Debug, thiserror::Error)]
#[error("cursor {after} is older than retention window (oldest id: {oldest})")]
pub struct CursorGoneError {
pub after: i64,
pub oldest: i64,
}
#[async_trait::async_trait]
pub trait EngineEventBus: Send + Sync + 'static {
async fn publish_committed(&self, ev: NewEvent<'_>) -> Result<i64>;
async fn read_since(
&self,
namespace: &str,
after: Option<i64>,
filter: &EventFilter,
limit: u32,
) -> std::result::Result<Vec<Event>, CursorGoneError>;
fn subscribe(&self, namespace: &str) -> broadcast::Receiver<Arc<Event>>;
async fn prune(&self, before_ts: f64) -> Result<u64>;
async fn oldest_id(&self, namespace: &str) -> Result<Option<i64>>;
}