Better events (Rust side)

This commit is contained in:
Brandon Thomas committed 2025-05-28 23:53:13 -04:00
1 parent 9cf87cda5b
commit e75e5624ed
13 files changed
+187 -53

No files matched your search

+13 -4
View File
@@ -1,6 +1,15 @@
{
"files.exclude": {
"**/*~": true,
"frontend_old/**": true
}
"files.exclude": {
"**/*~": true,
".sqlx/**": true,
"_elasticsearch/**": true,
"_sql/**": true,
"frontend_old/**": true,
"includes/**": true,
"target/**": true,
"test_data/**": true,
"tmp/**": true,
"virtualenv/**": true,
"windows_dlls/**": true,
}
}
@@ -0,0 +1,50 @@
use crate::core::events::sendable_event_error::SendableEventError;
use log::info;
use serde::Serialize;
use tauri::{AppHandle, Emitter};
// Tagged enums here are waaay too "Rustic"
// #[derive(Clone, Serialize)]
// #[serde(rename_all = "camelCase", rename_all_fields = "camelCase", tag = "event", content = "data")]
// pub enum BasicEvent<T: Serialize> {
// Success(T),
// Failure(T),
// }
#[derive(Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum BasicEventStatus {
Success,
Failure,
}
/// Wrap the event with "status" and "data" fields.
#[derive(Clone, Serialize)]
#[serde(rename_all = "snake_case")]
struct BasicEventWrapper<T: Serialize> {
status: BasicEventStatus,
data: T,
}
pub trait BasicSendableEvent : Serialize {
/// This is the name of the event that the frontend subscribes to.
const FRONTEND_EVENT_NAME: &'static str;
/// This is the status of the event: Success, Failure, etc.
const EVENT_STATUS: BasicEventStatus;
/// Default implementation of send().
/// This serializes and sends the event to the frontend.
fn send(&self, app: &AppHandle) -> Result<(), SendableEventError> {
info!("Sending event to frontend: {}", Self::FRONTEND_EVENT_NAME);
let wrapped = BasicEventWrapper {
status: Self::EVENT_STATUS,
data: self.clone(),
};
let result = app.emit(Self::FRONTEND_EVENT_NAME, wrapped);
if let Err(err) = result {
return Err(SendableEventError::from(err));
}
Ok(())
}
}
@@ -0,0 +1,18 @@
use serde::Serialize;
#[derive(Debug, Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GenerationServiceName {
Sora,
Fal,
}
#[derive(Debug, Copy, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum GenerationAction {
GenerateImage,
GenerateVideo,
RemoveBackground,
#[serde(rename = "image_to_3d")]
ImageTo3d,
}
@@ -0,0 +1,15 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceName};
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationCompleteEvent {
pub service: GenerationServiceName,
pub action: GenerationAction,
}
impl BasicSendableEvent for GenerationCompleteEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-complete-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Success;
}
@@ -0,0 +1,18 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceName};
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationEnqueueFailureEvent {
pub service: GenerationServiceName,
pub action: GenerationAction,
/// User-facing reason for the failure, if available.
pub reason: Option<String>,
}
impl BasicSendableEvent for GenerationEnqueueFailureEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-enqueue-failure-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Failure;
}
@@ -0,0 +1,15 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceName};
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationEnqueueSuccessEvent {
pub service: GenerationServiceName,
pub action: GenerationAction,
}
impl BasicSendableEvent for GenerationEnqueueSuccessEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-enqueue-success-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Success;
}
@@ -0,0 +1,18 @@
use crate::core::events::basic_sendable_event_trait::{BasicEventStatus, BasicSendableEvent};
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceName};
use serde_derive::Serialize;
#[derive(Serialize)]
#[serde(rename_all = "snake_case")]
pub struct GenerationFailedEvent {
pub service: GenerationServiceName,
pub action: GenerationAction,
/// User-facing reason for the failure, if available.
pub reason: Option<String>,
}
impl BasicSendableEvent for GenerationFailedEvent {
const FRONTEND_EVENT_NAME: &'static str = "generation-failed-event";
const EVENT_STATUS: BasicEventStatus = BasicEventStatus::Failure;
}
@@ -0,0 +1,5 @@
pub mod common;
pub mod generation_enqueue_failure_event;
pub mod generation_enqueue_success_event;
pub mod generation_complete_event;
pub mod generation_failed_event;
@@ -1,3 +1,4 @@
pub mod notification_event;
pub mod basic_sendable_event_trait;
pub mod generation_events;
pub mod sendable_event_error;
pub mod sendable_event_trait;
@@ -1,45 +0,0 @@
use serde::Serialize;
#[derive(Clone, Copy, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationModelType {
ImageSegmentation,
TextEncoder,
TextTokenizer,
Unet,
Vae,
Json,
ClipEncoder,
FluxModel,
}
#[derive(Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum NotificationEvent<'a> {
ModelDownloadStarted {
model_name: &'a str,
model_type: NotificationModelType,
},
ModelDownloadProgress {
model_name: &'a str,
model_type: NotificationModelType,
currently_downloaded_bytes: usize,
total_file_bytes: usize,
},
ModelDownloadComplete {
model_name: &'a str,
model_type: NotificationModelType,
},
ModelLoading {
model_name: String,
model_type: NotificationModelType,
},
ModelInference {
model_name: String,
model_type: NotificationModelType,
},
ModelInferenceComplete {
model_name: String,
model_type: NotificationModelType,
},
}
@@ -1,15 +1,17 @@
use log::info;
use crate::core::events::sendable_event_error::SendableEventError;
use log::info;
use serde::Serialize;
use tauri::{AppHandle, Emitter};
/// Implement this on a Serializable object to be able to send it as an event to the frontend.
#[deprecated(note = "Use BasicSendableEvent instead as it wraps the event with status and data fields.")]
pub trait SendableEvent : Serialize {
/// This is the name of the event that the frontend subscribes to.
const FRONTEND_EVENT_NAME: &'static str;
/// Default implementation of send().
/// This serializes and sends the event to the frontend.
#[deprecated(note = "Use BasicSendableEvent instead as it wraps the event with status and data fields.")]
fn send(&self, app: &AppHandle) -> Result<(), SendableEventError> {
info!("Sending event to frontend: {}", Self::FRONTEND_EVENT_NAME);
let result = app.emit(Self::FRONTEND_EVENT_NAME, self);
@@ -1,4 +1,3 @@
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
use crate::core::utils::download_url_to_temp_dir::download_url_to_temp_dir;
@@ -1,5 +1,8 @@
use crate::core::commands::response::failure_response_wrapper::{CommandErrorResponseWrapper, CommandErrorStatus};
use crate::core::commands::response::shorthand::Response;
use crate::core::events::basic_sendable_event_trait::BasicSendableEvent;
use crate::core::events::generation_events::common::{GenerationAction, GenerationServiceName};
use crate::core::events::generation_events::generation_enqueue_success_event::GenerationEnqueueSuccessEvent;
use crate::core::events::sendable_event_trait::SendableEvent;
use crate::core::state::data_dir::app_data_root::AppDataRoot;
use crate::core::state::data_dir::trait_data_subdir::DataSubdir;
@@ -38,6 +41,7 @@ use storyteller_client::media_files::get_media_file::get_media_file;
use storyteller_client::utils::api_host::ApiHost;
use tauri::{AppHandle, Emitter, Manager, State};
use tokens::tokens::media_files::MediaFileToken;
use crate::core::events::generation_events::generation_enqueue_failure_event::GenerationEnqueueFailureEvent;
const SORA_IMAGE_UPLOAD_TIMEOUT: Duration = Duration::from_millis(1000 * 30); // 30 seconds
@@ -122,13 +126,26 @@ pub async fn sora_image_remix_command(
Err(err) => {
error!("error: {:?}", err);
// TODO(bt,2025-05-28): Remove old event types
let event = SoraImageEnqueueFailureEvent {};
let result = event.send(&app);
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
let event = GenerationEnqueueFailureEvent {
service: GenerationServiceName::Sora,
action: GenerationAction::GenerateImage,
reason: None,
};
let result = event.send(&app);
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
let mut status = CommandErrorStatus::ServerError;
let mut error_type = SoraImageRemixErrorType::ServerError;
let mut error_message = "A server error occurred. Please try again. If it continues, please tell our staff about the problem.";
@@ -160,6 +177,7 @@ pub async fn sora_image_remix_command(
})
}
Ok(_) => {
// TODO(bt,2025-05-28): Remove old event types
let event = SoraImageEnqueueSuccessEvent {};
let result = event.send(&app);
@@ -167,6 +185,17 @@ pub async fn sora_image_remix_command(
error!("Failed to emit event: {:?}", err);
}
let event = GenerationEnqueueSuccessEvent {
service: GenerationServiceName::Sora,
action: GenerationAction::GenerateImage,
};
let result = event.send(&app);
if let Err(err) = result {
error!("Failed to emit event: {:?}", err);
}
Ok(().into())
}
}