lighty_event/lib.rs
1// Copyright (c) 2025 Hamadi
2// Licensed under the MIT License
3
4//! Event system for LightyLauncher
5//!
6//! Simple broadcast-based event system that allows emitting events from the library
7//! and subscribing to them from user code.
8//!
9//! # Example
10//!
11//! ```no_run
12//! use lighty_event::{EventBus, Event, LaunchEvent, EventReceiveError};
13//!
14//! #[tokio::main]
15//! async fn main() {
16//! let event_bus = EventBus::new(100);
17//! let mut receiver = event_bus.subscribe();
18//!
19//! // Spawn a listener with error handling
20//! tokio::spawn(async move {
21//! loop {
22//! match receiver.next().await {
23//! Ok(event) => {
24//! match event {
25//! Event::Launch(LaunchEvent::InstallProgress { bytes }) => {
26//! println!("Downloaded {} bytes", bytes);
27//! }
28//! _ => {}
29//! }
30//! }
31//! Err(EventReceiveError::BusDropped) => {
32//! println!("Event bus closed");
33//! break;
34//! }
35//! Err(EventReceiveError::Lagged { skipped }) => {
36//! eprintln!("Receiver lagged, missed {} events", skipped);
37//! }
38//! }
39//! }
40//! });
41//!
42//! // Use the launcher with event_bus...
43//! }
44//! ```
45
46use serde::{Deserialize, Serialize};
47use tokio::sync::broadcast;
48
49// Re-export event modules
50mod errors;
51pub mod module;
52
53pub use errors::{
54 EventReceiveError, EventReceiveResult, EventSendError, EventSendResult,
55 EventTryReceiveError, EventTryReceiveResult,
56};
57pub use module::{AuthEvent, CoreEvent, JavaEvent, LaunchEvent, LoaderEvent};
58
59/// Event bus for broadcasting events to multiple listeners
60#[derive(Clone)]
61pub struct EventBus {
62 sender: broadcast::Sender<Event>,
63}
64
65impl EventBus {
66 /// Create a new EventBus with the specified buffer capacity
67 ///
68 /// # Arguments
69 /// - `capacity`: Maximum number of events to buffer. If this limit is exceeded
70 /// and receivers are slow, the oldest events will be dropped.
71 ///
72 /// # Recommended values
73 /// - 100-1000 for most use cases
74 /// - Higher values if you have very slow receivers
75 pub fn new(capacity: usize) -> Self {
76 let (sender, _) = broadcast::channel(capacity);
77 Self { sender }
78 }
79
80 /// Subscribe to events
81 ///
82 /// Returns an EventReceiver that will receive all future events emitted
83 /// after this call.
84 pub fn subscribe(&self) -> EventReceiver {
85 EventReceiver {
86 receiver: self.sender.subscribe(),
87 }
88 }
89
90 /// Emit an event to all subscribers
91 ///
92 /// If there are no active subscribers, the event is silently dropped.
93 pub fn emit(&self, event: Event) {
94 let _ = self.sender.send(event);
95 }
96}
97
98/// Receiver for events from an EventBus
99pub struct EventReceiver {
100 receiver: broadcast::Receiver<Event>,
101}
102
103impl EventReceiver {
104 /// Wait for the next event (async blocking)
105 ///
106 /// Returns `Ok(Event)` when an event is received, or `Err(EventReceiveError)` if
107 /// the EventBus is dropped or the receiver has lagged behind.
108 ///
109 /// # Errors
110 /// - `EventReceiveError::BusDropped` - All event bus senders have been dropped
111 /// - `EventReceiveError::Lagged` - The receiver fell behind and missed some events
112 pub async fn next(&mut self) -> EventReceiveResult<Event> {
113 self.receiver.recv().await.map_err(Into::into)
114 }
115
116 /// Try to receive an event without blocking
117 ///
118 /// Returns `Ok(Event)` if an event is immediately available.
119 ///
120 /// # Errors
121 /// - `EventTryReceiveError::Empty` - No events available right now
122 /// - `EventTryReceiveError::BusDropped` - All event bus senders have been dropped
123 /// - `EventTryReceiveError::Lagged` - The receiver fell behind and missed some events
124 pub fn try_next(&mut self) -> EventTryReceiveResult<Event> {
125 self.receiver.try_recv().map_err(Into::into)
126 }
127}
128
129/// Root event enum containing all event types
130#[derive(Debug, Clone, Serialize, Deserialize)]
131#[serde(tag = "type", content = "data")]
132pub enum Event {
133 Auth(AuthEvent),
134 Java(JavaEvent),
135 Launch(LaunchEvent),
136 Loader(LoaderEvent),
137 Core(CoreEvent),
138}