Files
AstralRinth/packages/app-lib/src/event/mod.rs
Josiah Glosson cf190d86d5 Update Rust dependencies (#4139)
* Update Rust version

* Update async-compression 0.4.25 -> 0.4.27

* Update async-tungstenite 0.29.1 -> 0.30.0

* Update bytemuck 1.23.0 -> 1.23.1

* Update clap 4.5.40 -> 4.5.43

* Update deadpool-redis 0.21.1 -> 0.22.0 and redis 0.31.0 -> 0.32.4

* Update enumset 1.1.6 -> 1.1.7

* Update hyper-util 0.1.14 -> 0.1.16

* Update indexmap 2.9.0 -> 2.10.0

* Update indicatif 0.17.11 -> 0.18.0

* Update jemalloc_pprof 0.7.0 -> 0.8.1

* Update lettre 0.11.17 -> 0.11.18

* Update meilisearch-sdk 0.28.0 -> 0.29.1

* Update notify 8.0.0 -> 8.2.0 and notify-debouncer-mini 0.6.0 -> 0.7.0

* Update quick-xml 0.37.5 -> 0.38.1

* Fix theseus lint

* Update reqwest 0.12.20 -> 0.12.22

* Cargo fmt in theseus

* Update rgb 0.8.50 -> 0.8.52

* Update sentry 0.41.0 -> 0.42.0 and sentry-actix 0.41.0 -> 0.42.0

* Update serde_json 1.0.140 -> 1.0.142

* Update serde_with 3.13.0 -> 3.14.0

* Update spdx 0.10.8 -> 0.10.9

* Update sysinfo 0.35.2 -> 0.36.1

* Update tauri suite

* Fix build by updating mappings

* Update tokio 1.45.1 -> 1.47.1 and tokio-util 0.7.15 -> 0.7.16

* Update tracing-actix-web 0.7.18 -> 0.7.19

* Update zip 4.2.0 -> 4.3.0

* Misc Cargo.lock updates

* Update Dockerfiles
2025-08-08 22:50:44 +00:00

283 lines
7.3 KiB
Rust

//! Theseus state management system
use ariadne::ids::UserId;
use ariadne::users::UserStatus;
use chrono::{DateTime, Utc};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, sync::Arc};
#[cfg(feature = "tauri")]
use tauri::Emitter;
use tokio::sync::OnceCell;
use uuid::Uuid;
pub mod emit;
// Global event state
// Stores the Tauri app handle and other event-related state variables
static EVENT_STATE: OnceCell<Arc<EventState>> = OnceCell::const_new();
pub struct EventState {
/// Tauri app
#[cfg(feature = "tauri")]
pub app: tauri::AppHandle,
pub loading_bars: DashMap<Uuid, LoadingBar>,
}
impl EventState {
#[cfg(feature = "tauri")]
pub async fn init(app: tauri::AppHandle) -> crate::Result<Arc<Self>> {
EVENT_STATE
.get_or_try_init(|| async {
Ok(Arc::new(Self {
app,
loading_bars: DashMap::new(),
}))
})
.await
.cloned()
}
#[cfg(not(feature = "tauri"))]
pub async fn init() -> crate::Result<Arc<Self>> {
EVENT_STATE
.get_or_try_init(|| async {
Ok(Arc::new(Self {
loading_bars: DashMap::new(),
}))
})
.await
.cloned()
}
pub fn get() -> crate::Result<Arc<Self>> {
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
}
// Values provided should not be used directly, as they are clones and are not guaranteed to be up-to-date
pub async fn list_progress_bars() -> crate::Result<DashMap<Uuid, LoadingBar>>
{
let value = Self::get()?;
Ok(value.loading_bars.clone())
}
#[cfg(feature = "tauri")]
pub async fn get_main_window() -> crate::Result<Option<tauri::WebviewWindow>>
{
use tauri::Manager;
let value = Self::get()?;
Ok(value.app.get_webview_window("main"))
}
}
#[derive(Serialize, Debug, Clone)]
pub struct LoadingBar {
// loading_bar_uuid not be used directly by external functions as it may not reflect the current state of the loading bar/hashmap
pub loading_bar_uuid: Uuid,
pub message: String,
pub total: f64,
pub current: f64,
#[serde(skip)]
pub last_sent: f64,
pub bar_type: LoadingBarType,
#[cfg(feature = "cli")]
#[serde(skip)]
pub cli_progress_bar: indicatif::ProgressBar,
}
#[derive(Serialize, Debug, Clone)]
pub struct LoadingBarId(Uuid);
// When Loading bar id is dropped, we should remove it from the hashmap
impl Drop for LoadingBarId {
fn drop(&mut self) {
let loader_uuid = self.0;
tokio::spawn(async move {
if let Ok(event_state) = EventState::get() {
#[cfg(any(feature = "tauri", feature = "cli"))]
if let Some((_, bar)) =
event_state.loading_bars.remove(&loader_uuid)
{
#[cfg(feature = "tauri")]
{
let loader_uuid = bar.loading_bar_uuid;
let event = bar.bar_type.clone();
let fraction = bar.current / bar.total;
let _ = event_state.app.emit(
"loading",
LoadingPayload {
fraction: None,
message: "Completed".to_string(),
event,
loader_uuid,
},
);
tracing::trace!(
"Exited at {fraction} for loading bar: {:?}",
loader_uuid
);
}
// Emit event to indicatif progress bar arc
#[cfg(feature = "cli")]
{
let cli_progress_bar = bar.cli_progress_bar;
cli_progress_bar.finish();
}
}
#[cfg(not(any(feature = "tauri", feature = "cli")))]
event_state.loading_bars.remove(&loader_uuid);
}
});
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum LoadingBarType {
LegacyDataMigration,
DirectoryMove {
old: PathBuf,
new: PathBuf,
},
JavaDownload {
version: u32,
},
PackFileDownload {
profile_path: String,
pack_name: String,
icon: Option<String>,
pack_version: String,
},
PackDownload {
profile_path: String,
pack_name: String,
icon: Option<PathBuf>,
pack_id: Option<String>,
pack_version: Option<String>,
},
MinecraftDownload {
profile_path: String,
profile_name: String,
},
ProfileUpdate {
profile_path: String,
profile_name: String,
},
ZipExtract {
profile_path: String,
profile_name: String,
},
ConfigChange {
new_path: PathBuf,
},
CopyProfile {
import_location: PathBuf,
profile_name: String,
},
CheckingForUpdates,
LauncherUpdate {
version: String,
current_version: String,
},
}
#[derive(Serialize, Clone)]
#[cfg(feature = "tauri")]
pub struct LoadingPayload {
pub event: LoadingBarType,
pub loader_uuid: Uuid,
pub fraction: Option<f64>, // by convention, if optional, it means the loading is done
pub message: String,
}
#[derive(Serialize, Clone)]
#[cfg(feature = "tauri")]
pub struct WarningPayload {
pub message: String,
}
#[derive(Serialize, Clone)]
#[serde(tag = "event")]
pub enum CommandPayload {
InstallMod {
id: String,
},
InstallVersion {
id: String,
},
InstallModpack {
id: String,
},
RunMRPack {
// run or install .mrpack
path: PathBuf,
},
}
#[derive(Serialize, Clone)]
#[cfg(feature = "tauri")]
pub struct ProcessPayload {
pub profile_path_id: String,
pub uuid: Uuid,
pub event: ProcessPayloadType,
pub message: String,
}
#[derive(Serialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum ProcessPayloadType {
Launched,
Finished,
}
#[derive(Serialize, Clone)]
#[cfg(feature = "tauri")]
pub struct ProfilePayload {
pub profile_path_id: String,
#[serde(flatten)]
pub event: ProfilePayloadType,
}
#[derive(Serialize, Clone)]
#[serde(tag = "event", rename_all = "snake_case")]
pub enum ProfilePayloadType {
Created,
Synced,
ServersUpdated,
WorldUpdated {
world: String,
},
ServerJoined {
host: String,
port: u16,
timestamp: DateTime<Utc>,
},
Edited,
Removed,
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "event")]
pub enum FriendPayload {
FriendRequest { from: UserId },
UserOffline { id: UserId },
StatusUpdate { user_status: UserStatus },
StatusSync,
}
#[derive(Debug, thiserror::Error)]
pub enum EventError {
#[error("Event state was not properly initialized")]
NotInitialized,
#[error("Non-existent loading bar of key: {0}")]
NoLoadingBar(Uuid),
#[cfg(feature = "tauri")]
#[error("Tauri error: {0}")]
TauriError(#[from] tauri::Error),
}