pub struct Program<M: Model> { /* private fields */ }Expand description
The main program that runs your application
Implementations§
Source§impl<M: Model> Program<M>
impl<M: Model> Program<M>
Sourcepub fn with_options(model: M, options: ProgramOptions) -> Result<Self>
pub fn with_options(model: M, options: ProgramOptions) -> Result<Self>
Create a new program with custom options
Sourcepub fn with_filter<F>(self, filter: F) -> Self
pub fn with_filter<F>(self, filter: F) -> Self
Set a message filter function
Sourcepub fn with_priority_config(self, config: PriorityConfig) -> Self
pub fn with_priority_config(self, config: PriorityConfig) -> Self
Configure the priority event processor
Sourcepub fn event_stats(&self) -> EventStats
pub fn event_stats(&self) -> EventStats
Get current event processing statistics
Sourcepub fn event_stats_string(&self) -> String
pub fn event_stats_string(&self) -> String
Get a formatted string of event statistics (useful for debugging)
Sourcepub fn kill(&self)
pub fn kill(&self)
Force kill the program immediately
This method forcefully terminates the program without any cleanup.
Unlike quit() which sends a quit message through the event loop,
kill() immediately stops execution.
§Use Cases
- Emergency shutdown when the program is unresponsive
- Testing scenarios requiring immediate termination
- Signal handlers that need to stop the program immediately
§Example
// In a signal handler or emergency shutdown
program.kill();§Note
This bypasses normal cleanup procedures. Prefer quit() for graceful shutdown.
Sourcepub fn metrics(&self) -> AdvancedEventStats
pub fn metrics(&self) -> AdvancedEventStats
Get advanced performance metrics
Sourcepub fn resource_stats(&self) -> ResourceStats
pub fn resource_stats(&self) -> ResourceStats
Get resource usage statistics
Sourcepub fn metrics_json(&self) -> String
pub fn metrics_json(&self) -> String
Export metrics in JSON format
Sourcepub fn metrics_prometheus(&self) -> String
pub fn metrics_prometheus(&self) -> String
Export metrics in Prometheus format
Sourcepub fn metrics_text(&self) -> String
pub fn metrics_text(&self) -> String
Export metrics in plain text format
Sourcepub fn metrics_dashboard(&self) -> String
pub fn metrics_dashboard(&self) -> String
Display metrics dashboard (for debugging)
Sourcepub fn reset_metrics(&self)
pub fn reset_metrics(&self)
Reset all metrics
Sourcepub fn resize_queue(&self, new_size: usize) -> Result<()>
pub fn resize_queue(&self, new_size: usize) -> Result<()>
Dynamically resize the event queue
Sourcepub fn queue_capacity(&self) -> usize
pub fn queue_capacity(&self) -> usize
Get current queue capacity
Sourcepub fn enable_auto_scaling(&mut self, config: AutoScaleConfig) -> &mut Self
pub fn enable_auto_scaling(&mut self, config: AutoScaleConfig) -> &mut Self
Enable auto-scaling with the specified configuration
Sourcepub fn with_auto_scaling(self) -> Self
pub fn with_auto_scaling(self) -> Self
Enable auto-scaling with default configuration
Sourcepub fn disable_auto_scaling(&mut self) -> &mut Self
pub fn disable_auto_scaling(&mut self) -> &mut Self
Disable auto-scaling
Sourcepub fn sender(&self) -> Option<SyncSender<Event<M::Message>>>
pub fn sender(&self) -> Option<SyncSender<Event<M::Message>>>
Get a sender for injecting events from external sources
This allows external async tasks to send messages to the program’s event loop. The sender is thread-safe and can be cloned for use in multiple threads.
§Example
let mut program = Program::new(model)?;
let sender = program.sender();
std::thread::spawn(move || {
loop {
std::thread::sleep(Duration::from_secs(1));
let _ = sender.send(Event::User(Msg::Tick));
}
});
program.run()?;Sourcepub fn send_message(&self, msg: M::Message) -> Result<()>
pub fn send_message(&self, msg: M::Message) -> Result<()>
Sourcepub fn release_terminal(&mut self) -> Result<()>
pub fn release_terminal(&mut self) -> Result<()>
Release the terminal
Sourcepub fn restore_terminal(&mut self) -> Result<()>
pub fn restore_terminal(&mut self) -> Result<()>
Restore the terminal
Sourcepub fn init_async_bridge(&mut self) -> SyncSender<Event<M::Message>>
pub fn init_async_bridge(&mut self) -> SyncSender<Event<M::Message>>
Initialize the async message bridge for external event injection
This sets up channels for external systems to send messages into the program’s
event loop. Must be called before run() if you need external message injection.
§Use Cases
- WebSocket Integration: Forward messages from WebSocket connections
- File Watchers: Send events when files change
- Timers: Implement custom scheduling beyond tick/every
- Database Listeners: Forward change notifications
- IPC: Receive messages from other processes
- HTTP Responses: Send results from async HTTP requests
§Thread Safety
The returned sender can be cloned and shared across multiple threads safely. Messages are queued with a capacity of 100 by default.
§Example
use hojicha_runtime::{Program, Event};
use hojicha_core::{Model, Cmd};
#[derive(Clone, Debug)]
struct MyModel;
#[derive(Clone, Debug)]
enum MyMsg { Hello }
impl Model for MyModel {
type Message = MyMsg;
fn init(&mut self) -> Cmd<Self::Message> { Cmd::noop() }
fn update(&mut self, _msg: Event<Self::Message>) -> Cmd<Self::Message> { Cmd::noop() }
fn view(&self) -> String { "test".to_string() }
}
let mut program = Program::new(MyModel).unwrap();
let sender = program.init_async_bridge();
// Send an external event from another thread
sender.send(Event::User(MyMsg::Hello)).ok();Sourcepub fn subscribe<S>(&mut self, stream: S) -> Subscription
pub fn subscribe<S>(&mut self, stream: S) -> Subscription
Subscribe to an async stream of events
Connects any futures::Stream to your program’s event loop. Each item from
the stream is automatically wrapped in Event::User and sent to your model’s
update function.
§Use Cases
- WebSocket/SSE: Stream real-time messages
- File Watching: Monitor file system changes
- Periodic Tasks: Custom intervals and scheduling
- Database Changes: Listen to change streams
- Sensor Data: Process continuous data streams
§Cancellation
The returned Subscription handle allows graceful cancellation. The subscription
is also automatically cancelled when dropped.
§Examples
§Timer Stream
use tokio_stream::wrappers::IntervalStream;
use std::time::Duration;
let interval = tokio::time::interval(Duration::from_secs(1));
let stream = IntervalStream::new(interval)
.map(|_| Msg::Tick);
let subscription = program.subscribe(stream);§WebSocket Stream
let ws_stream = websocket.messages()
.filter_map(|msg| msg.ok())
.map(|msg| Msg::WebSocketMessage(msg));
let subscription = program.subscribe(ws_stream);§File Watcher Stream
let file_stream = watch_file("/path/to/file")
.map(|event| Msg::FileChanged(event));
let subscription = program.subscribe(file_stream);Sourcepub fn spawn_cancellable<F, Fut, T>(&self, f: F) -> AsyncHandle<T>where
F: FnOnce(CancellationToken) -> Fut,
Fut: Future<Output = T> + Send + 'static,
T: Send + 'static,
pub fn spawn_cancellable<F, Fut, T>(&self, f: F) -> AsyncHandle<T>where
F: FnOnce(CancellationToken) -> Fut,
Fut: Future<Output = T> + Send + 'static,
T: Send + 'static,
Spawn a cancellable async operation
Spawns a long-running async task with cooperative cancellation support.
The task receives a CancellationToken for checking cancellation status.
§Use Cases
- Background Processing: Data analysis, file processing
- Network Operations: Long polling, streaming downloads
- Periodic Tasks: Health checks, metrics collection
- Resource Monitoring: CPU/memory monitoring
- Cleanup Tasks: Temporary file cleanup, cache management
§Cancellation Pattern
Tasks should periodically check the cancellation token and exit gracefully
when cancelled. Use tokio::select! for responsive cancellation.
§Examples
§Background File Processing
let handle = program.spawn_cancellable(|token| async move {
for file in large_file_list {
if token.is_cancelled() {
return Err("Cancelled");
}
process_file(file).await?;
}
Ok("All files processed")
});§Long Polling
let handle = program.spawn_cancellable(|token| async move {
loop {
tokio::select! {
_ = token.cancelled() => {
break Ok("Polling cancelled");
}
result = poll_server() => {
handle_result(result)?;
}
}
}
});
// Cancel when user navigates away
if user_navigated_away {
handle.cancel().await;
}Sourcepub fn spawn_cancellable_cmd<F, Fut>(&mut self, f: F) -> AsyncHandle<()>where
F: FnOnce(CancellationToken, SyncSender<Event<M::Message>>) -> Fut,
Fut: Future<Output = ()> + Send + 'static,
M::Message: Send + 'static,
pub fn spawn_cancellable_cmd<F, Fut>(&mut self, f: F) -> AsyncHandle<()>where
F: FnOnce(CancellationToken, SyncSender<Event<M::Message>>) -> Fut,
Fut: Future<Output = ()> + Send + 'static,
M::Message: Send + 'static,
Spawn a cancellable async operation that sends messages
Similar to spawn_cancellable but specifically for operations that produce messages for the program.
§Example
let handle = program.spawn_cancellable_cmd(|token, sender| async move {
while !token.is_cancelled() {
let data = fetch_data().await;
let _ = sender.send(Event::User(Msg::DataReceived(data)));
tokio::time::sleep(Duration::from_secs(1)).await;
}
});Sourcepub fn subscribe_interval<F>(
&mut self,
interval: Duration,
callback: F,
) -> Subscription
pub fn subscribe_interval<F>( &mut self, interval: Duration, callback: F, ) -> Subscription
Sourcepub fn subscribe_with_error<S, T, E, F, G>(
&mut self,
stream: S,
on_item: F,
on_error: G,
) -> Subscription
pub fn subscribe_with_error<S, T, E, F, G>( &mut self, stream: S, on_item: F, on_error: G, ) -> Subscription
Sourcepub fn run_with_timeout(self, timeout: Duration) -> Result<()>
pub fn run_with_timeout(self, timeout: Duration) -> Result<()>
Run the program with a timeout (useful for testing)
The program will automatically exit after the specified duration. Returns Ok(()) if the timeout was reached or the program exited normally.