initial commit
This commit is contained in:
166
src/app.rs
Normal file
166
src/app.rs
Normal file
@@ -0,0 +1,166 @@
|
||||
//! # Hero Supervisor Application
|
||||
//!
|
||||
//! Simplified supervisor application that wraps a built Supervisor instance.
|
||||
//! Use SupervisorBuilder to construct the supervisor with all configuration,
|
||||
//! then pass it to SupervisorApp for runtime management.
|
||||
|
||||
use crate::Supervisor;
|
||||
use crate::openrpc::start_openrpc_servers;
|
||||
use log::{info, error, debug};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
/// Main supervisor application
|
||||
pub struct SupervisorApp {
|
||||
pub supervisor: Supervisor,
|
||||
pub bind_address: String,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl SupervisorApp {
|
||||
/// Create a new supervisor application with a built supervisor
|
||||
pub fn new(supervisor: Supervisor, bind_address: String, port: u16) -> Self {
|
||||
Self {
|
||||
supervisor,
|
||||
bind_address,
|
||||
port,
|
||||
}
|
||||
}
|
||||
|
||||
/// Start the complete supervisor application
|
||||
/// This method handles the entire application lifecycle:
|
||||
/// - Starts all configured runners
|
||||
/// - Launches the OpenRPC server
|
||||
/// - Sets up graceful shutdown handling
|
||||
/// - Keeps the application running
|
||||
pub async fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
info!("Starting Hero Supervisor Application");
|
||||
|
||||
// Start all configured runners
|
||||
self.start_all().await?;
|
||||
|
||||
// Start OpenRPC server
|
||||
self.start_openrpc_server().await?;
|
||||
|
||||
// Set up graceful shutdown
|
||||
self.setup_graceful_shutdown().await;
|
||||
|
||||
// Keep the application running
|
||||
info!("Supervisor is running. Press Ctrl+C to shutdown.");
|
||||
self.run_main_loop().await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Start the OpenRPC server
|
||||
async fn start_openrpc_server(&self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
info!("Starting OpenRPC server...");
|
||||
|
||||
let supervisor_for_openrpc = Arc::new(Mutex::new(self.supervisor.clone()));
|
||||
let bind_address = self.bind_address.clone();
|
||||
let port = self.port;
|
||||
|
||||
// Start the OpenRPC server in a background task
|
||||
let server_handle = tokio::spawn(async move {
|
||||
if let Err(e) = start_openrpc_servers(supervisor_for_openrpc, &bind_address, port).await {
|
||||
error!("OpenRPC server error: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Give the server a moment to start
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
|
||||
info!("OpenRPC server started successfully");
|
||||
|
||||
// Store the handle for potential cleanup (we could add this to the struct if needed)
|
||||
std::mem::forget(server_handle); // For now, let it run in background
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set up graceful shutdown handling
|
||||
async fn setup_graceful_shutdown(&self) {
|
||||
tokio::spawn(async move {
|
||||
tokio::signal::ctrl_c().await.expect("Failed to listen for ctrl+c");
|
||||
info!("Received shutdown signal");
|
||||
std::process::exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
/// Main application loop
|
||||
async fn run_main_loop(&self) {
|
||||
// Keep the main thread alive
|
||||
loop {
|
||||
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Start all configured runners
|
||||
pub async fn start_all(&mut self) -> Result<(), Box<dyn std::error::Error>> {
|
||||
info!("Starting all runners");
|
||||
|
||||
let results = self.supervisor.start_all().await;
|
||||
let mut failed_count = 0;
|
||||
|
||||
for (runner_id, result) in results {
|
||||
match result {
|
||||
Ok(_) => info!("Runner {} started successfully", runner_id),
|
||||
Err(e) => {
|
||||
error!("Failed to start runner {}: {}", runner_id, e);
|
||||
failed_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if failed_count == 0 {
|
||||
info!("All runners started successfully");
|
||||
} else {
|
||||
error!("Failed to start {} runners", failed_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stop all configured runners
|
||||
pub async fn stop_all(&mut self, force: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
info!("Stopping all runners (force: {})", force);
|
||||
|
||||
let results = self.supervisor.stop_all(force).await;
|
||||
let mut failed_count = 0;
|
||||
|
||||
for (runner_id, result) in results {
|
||||
match result {
|
||||
Ok(_) => info!("Runner {} stopped successfully", runner_id),
|
||||
Err(e) => {
|
||||
error!("Failed to stop runner {}: {}", runner_id, e);
|
||||
failed_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if failed_count == 0 {
|
||||
info!("All runners stopped successfully");
|
||||
} else {
|
||||
error!("Failed to stop {} runners", failed_count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get status of all runners
|
||||
pub async fn get_status(&self) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {
|
||||
debug!("Getting status of all runners");
|
||||
|
||||
let statuses = self.supervisor.get_all_runner_status().await
|
||||
.map_err(|e| Box::new(e) as Box<dyn std::error::Error>)?;
|
||||
|
||||
let status_strings: Vec<(String, String)> = statuses
|
||||
.into_iter()
|
||||
.map(|(runner_id, status)| {
|
||||
let status_str = format!("{:?}", status);
|
||||
(runner_id, status_str)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(status_strings)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user