172 lines
4.5 KiB
Rust
172 lines
4.5 KiB
Rust
use models::agent_task::TaskStatus;
|
|
use serde::Serialize;
|
|
use std::sync::Arc;
|
|
|
|
/// Event payload published to WebSocket clients via Redis Pub/Sub.
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct TaskEvent {
|
|
pub task_id: i64,
|
|
pub project_id: uuid::Uuid,
|
|
pub parent_id: Option<i64>,
|
|
pub event: String,
|
|
pub message: Option<String>,
|
|
pub output: Option<String>,
|
|
pub error: Option<String>,
|
|
pub status: String,
|
|
}
|
|
|
|
impl TaskEvent {
|
|
pub fn started(task_id: i64, project_id: uuid::Uuid, parent_id: Option<i64>) -> Self {
|
|
Self {
|
|
task_id,
|
|
project_id,
|
|
parent_id,
|
|
event: "started".to_string(),
|
|
message: None,
|
|
output: None,
|
|
error: None,
|
|
status: TaskStatus::Running.to_string(),
|
|
}
|
|
}
|
|
|
|
pub fn progress(
|
|
task_id: i64,
|
|
project_id: uuid::Uuid,
|
|
parent_id: Option<i64>,
|
|
msg: String,
|
|
) -> Self {
|
|
Self {
|
|
task_id,
|
|
project_id,
|
|
parent_id,
|
|
event: "progress".to_string(),
|
|
message: Some(msg),
|
|
output: None,
|
|
error: None,
|
|
status: TaskStatus::Running.to_string(),
|
|
}
|
|
}
|
|
|
|
pub fn completed(
|
|
task_id: i64,
|
|
project_id: uuid::Uuid,
|
|
parent_id: Option<i64>,
|
|
output: String,
|
|
) -> Self {
|
|
Self {
|
|
task_id,
|
|
project_id,
|
|
parent_id,
|
|
event: "done".to_string(),
|
|
message: None,
|
|
output: Some(output),
|
|
error: None,
|
|
status: TaskStatus::Done.to_string(),
|
|
}
|
|
}
|
|
|
|
pub fn failed(
|
|
task_id: i64,
|
|
project_id: uuid::Uuid,
|
|
parent_id: Option<i64>,
|
|
error: String,
|
|
) -> Self {
|
|
Self {
|
|
task_id,
|
|
project_id,
|
|
parent_id,
|
|
event: "failed".to_string(),
|
|
message: None,
|
|
output: None,
|
|
error: Some(error),
|
|
status: TaskStatus::Failed.to_string(),
|
|
}
|
|
}
|
|
|
|
pub fn cancelled(task_id: i64, project_id: uuid::Uuid, parent_id: Option<i64>) -> Self {
|
|
Self {
|
|
task_id,
|
|
project_id,
|
|
parent_id,
|
|
event: "cancelled".to_string(),
|
|
message: None,
|
|
output: None,
|
|
error: None,
|
|
status: TaskStatus::Cancelled.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Helper trait for publishing task lifecycle events via Redis Pub/Sub.
|
|
///
|
|
/// Callers inject a suitable `publish_fn` at construction time via
|
|
/// `TaskEvents::new(...)`. If no publisher is supplied events are silently
|
|
/// dropped (graceful degradation on startup).
|
|
pub trait TaskEventPublisher: Send + Sync {
|
|
fn publish(&self, project_id: uuid::Uuid, event: TaskEvent);
|
|
}
|
|
|
|
/// No-op publisher used when no Redis Pub/Sub connection is available.
|
|
#[derive(Clone, Default)]
|
|
pub struct NoOpPublisher;
|
|
|
|
impl TaskEventPublisher for NoOpPublisher {
|
|
fn publish(&self, _: uuid::Uuid, _: TaskEvent) {}
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct TaskEvents {
|
|
publisher: Arc<dyn TaskEventPublisher>,
|
|
}
|
|
|
|
impl TaskEvents {
|
|
pub fn new(publisher: impl TaskEventPublisher + 'static) -> Self {
|
|
Self {
|
|
publisher: Arc::new(publisher),
|
|
}
|
|
}
|
|
|
|
pub fn noop() -> Self {
|
|
Self::new(NoOpPublisher)
|
|
}
|
|
|
|
fn emit(&self, task: &models::agent_task::Model, event: TaskEvent) {
|
|
self.publisher.publish(task.project_uuid, event);
|
|
}
|
|
|
|
pub fn emit_started(&self, task: &models::agent_task::Model) {
|
|
self.emit(
|
|
task,
|
|
TaskEvent::started(task.id, task.project_uuid, task.parent_id),
|
|
);
|
|
}
|
|
|
|
pub fn emit_progress(&self, task: &models::agent_task::Model, msg: String) {
|
|
self.emit(
|
|
task,
|
|
TaskEvent::progress(task.id, task.project_uuid, task.parent_id, msg),
|
|
);
|
|
}
|
|
|
|
pub fn emit_completed(&self, task: &models::agent_task::Model, output: String) {
|
|
self.emit(
|
|
task,
|
|
TaskEvent::completed(task.id, task.project_uuid, task.parent_id, output),
|
|
);
|
|
}
|
|
|
|
pub fn emit_failed(&self, task: &models::agent_task::Model, error: String) {
|
|
self.emit(
|
|
task,
|
|
TaskEvent::failed(task.id, task.project_uuid, task.parent_id, error),
|
|
);
|
|
}
|
|
|
|
pub fn emit_cancelled(&self, task: &models::agent_task::Model) {
|
|
self.emit(
|
|
task,
|
|
TaskEvent::cancelled(task.id, task.project_uuid, task.parent_id),
|
|
);
|
|
}
|
|
}
|