Files
herocoordinator/src/main.rs
2025-08-28 14:53:08 +02:00

129 lines
3.7 KiB
Rust

use clap::Parser;
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
#[derive(Debug, Clone, Parser)]
#[command(
name = "herocoordinator",
version,
about = "Hero Coordinator CLI",
long_about = None
)]
struct Cli {
#[arg(
long = "mycelium-ip",
short = 'i',
env = "MYCELIUM_IP",
default_value = "127.0.0.1",
help = "IP address where Mycelium JSON-RPC is listening (default: 127.0.0.1)"
)]
mycelium_ip: IpAddr,
#[arg(
long = "mycelium-port",
short = 'p',
env = "MYCELIUM_PORT",
default_value_t = 9651u16,
help = "Port for Mycelium JSON-RPC (default: 9651)"
)]
mycelium_port: u16,
#[arg(
long = "redis-addr",
short = 'r',
env = "REDIS_ADDR",
default_value = "127.0.0.1:6379",
help = "Socket address of Redis instance (default: 127.0.0.1:6379)"
)]
redis_addr: SocketAddr,
#[arg(
long = "api-http-ip",
env = "API_HTTP_IP",
default_value = "127.0.0.1",
help = "Bind IP for HTTP JSON-RPC server (default: 127.0.0.1)"
)]
api_http_ip: IpAddr,
#[arg(
long = "api-http-port",
env = "API_HTTP_PORT",
default_value_t = 9652u16,
help = "Bind port for HTTP JSON-RPC server (default: 9652)"
)]
api_http_port: u16,
#[arg(
long = "api-ws-ip",
env = "API_WS_IP",
default_value = "127.0.0.1",
help = "Bind IP for WebSocket JSON-RPC server (default: 127.0.0.1)"
)]
api_ws_ip: IpAddr,
#[arg(
long = "api-ws-port",
env = "API_WS_PORT",
default_value_t = 9653u16,
help = "Bind port for WebSocket JSON-RPC server (default: 9653)"
)]
api_ws_port: u16,
}
#[tokio::main]
async fn main() {
let cli = Cli::parse();
let http_addr = SocketAddr::new(cli.api_http_ip, cli.api_http_port);
let ws_addr = SocketAddr::new(cli.api_ws_ip, cli.api_ws_port);
// Initialize Redis driver
let redis = herocoordinator::storage::RedisDriver::new(cli.redis_addr.to_string())
.await
.expect("Failed to connect to Redis");
// Initialize Service
let service = herocoordinator::service::AppService::new(redis);
let service_for_router = service.clone();
// Shared application state
let state = Arc::new(herocoordinator::rpc::AppState::new(service));
// Start router workers (auto-discovered contexts)
{
let base_url = format!("http://{}:{}", cli.mycelium_ip, cli.mycelium_port);
let cfg = herocoordinator::router::RouterConfig {
context_ids: Vec::new(), // ignored by start_router_auto
concurrency: 32,
base_url,
topic: "supervisor.rpc".to_string(),
transport_poll_interval_secs: 2,
transport_poll_timeout_secs: 300,
};
let _auto_handle = herocoordinator::router::start_router_auto(service_for_router, cfg);
}
// Build RPC modules for both servers
let http_module = herocoordinator::rpc::build_module(state.clone());
let ws_module = herocoordinator::rpc::build_module(state.clone());
println!(
"Starting JSON-RPC servers: HTTP http://{} | WS ws://{} | redis_addr={}",
http_addr, ws_addr, cli.redis_addr
);
// Start servers
let _http_handle = herocoordinator::rpc::start_http(http_addr, http_module)
.await
.expect("Failed to start HTTP server");
let _ws_handle = herocoordinator::rpc::start_ws(ws_addr, ws_module)
.await
.expect("Failed to start WS server");
// Wait for Ctrl+C to terminate
if let Err(e) = tokio::signal::ctrl_c().await {
eprintln!("Failed to listen for shutdown signal: {e}");
}
println!("Shutdown signal received, exiting.");
}