leaf/examples/ws_manager_demo.rs
2025-08-05 15:02:23 +02:00

179 lines
6.2 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! WebSocket Manager Demo
//!
//! This example demonstrates how to use the WsManager to connect to multiple
//! WebSocket servers, authenticate, and execute scripts on connected clients.
//!
//! # Prerequisites
//!
//! 1. Start one or more Hero WebSocket servers:
//! ```bash
//! # Terminal 1
//! cd hero/interfaces/websocket/server
//! cargo run --example circle_auth_demo -- --port 3030
//!
//! # Terminal 2 (optional)
//! cargo run --example circle_auth_demo -- --port 3031
//! ```
//!
//! 2. Run this example:
//! ```bash
//! cd framework
//! cargo run --example ws_manager_demo
//! ```
use framework::WsManager;
use log::{info, warn, error};
use std::time::Duration;
use tokio::time::sleep;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
info!("🚀 Starting WebSocket Manager Demo");
// Example private key (in real usage, load from secure storage)
let private_key = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
// Create a manager with multiple servers
let manager = WsManager::builder()
.private_key(private_key.to_string())
.add_server_url("ws://localhost:3030".to_string())
.add_server_url("ws://localhost:3031".to_string())
.build();
info!("📡 Connecting to WebSocket servers...");
// Connect to all configured servers
match manager.connect().await {
Ok(()) => info!("✅ Successfully initiated connections"),
Err(e) => {
error!("❌ Failed to connect: {}", e);
return Err(e.into());
}
}
// Give connections time to establish
sleep(Duration::from_secs(2)).await;
// Check connection status
info!("🔍 Checking connection status...");
let statuses = manager.get_all_connection_statuses();
for (url, status) in &statuses {
info!(" {} -> {}", url, status);
}
// Demonstrate script execution on a specific server
info!("🎯 Executing script on specific server...");
let script = r#"
console.log("Hello from WebSocket Manager!");
return "Script executed successfully";
"#;
if let Some(future) = manager.with_client("ws://localhost:3030", |client| {
info!(" 📤 Sending script to ws://localhost:3030");
client.play(script.to_string())
}) {
let result = future.await;
match result {
Ok(output) => info!(" ✅ Script output: {}", output),
Err(e) => warn!(" ⚠️ Script error: {}", e),
}
} else {
warn!(" ❌ Server ws://localhost:3030 is not connected");
}
// Demonstrate operations on all connected clients
info!("🌐 Executing operations on all connected clients...");
let ping_script = "return 'pong from ' + new Date().toISOString();";
// Get list of connected URLs first
let connected_urls = manager.get_connected_urls();
for url in connected_urls {
info!(" 📤 Pinging {}", url);
if let Some(future) = manager.with_client(&url, |client| {
client.play(ping_script.to_string())
}) {
match future.await {
Ok(output) => info!(" ✅ {} responded: {}", url, output),
Err(e) => warn!(" ⚠️ {} error: {}", url, e),
}
} else {
warn!(" ❌ {} is not connected", url);
}
}
// Wait for async operations to complete
sleep(Duration::from_secs(3)).await;
// Demonstrate authentication status check
info!("🔐 Checking authentication status...");
// Note: For complex async operations, you may need to handle them differently
// due to Rust's lifetime constraints with closures and futures
info!(" 💡 Authentication check would be done here in a real application");
info!(" 💡 Use manager.with_client() to access client methods like whoami()");
// Demonstrate connection management
info!("🔧 Testing connection management...");
// Disconnect from a specific server
info!(" 🔌 Disconnecting from ws://localhost:3031...");
if let Err(e) = manager.disconnect_from_server("ws://localhost:3031").await {
warn!(" ⚠️ Disconnect error: {}", e);
} else {
info!(" ✅ Disconnected successfully");
}
// Check status after disconnect
sleep(Duration::from_secs(1)).await;
let new_statuses = manager.get_all_connection_statuses();
for (url, status) in &new_statuses {
info!(" {} -> {}", url, status);
}
// Reconnect
info!(" 🔌 Reconnecting to ws://localhost:3031...");
if let Err(e) = manager.connect_to_server("ws://localhost:3031").await {
warn!(" ⚠️ Reconnect error: {}", e);
} else {
info!(" ✅ Reconnected successfully");
sleep(Duration::from_secs(1)).await;
}
// Final status check
info!("📊 Final connection status:");
let final_statuses = manager.get_all_connection_statuses();
for (url, status) in &final_statuses {
info!(" {} -> {}", url, status);
}
// Demonstrate adding a connection at runtime
info!(" Adding new connection at runtime...");
manager.add_connection(
"ws://localhost:3032".to_string(),
Some(private_key.to_string())
);
// Try to connect to the new server (will fail if server isn't running)
if let Err(e) = manager.connect_to_server("ws://localhost:3032").await {
warn!(" ⚠️ Could not connect to ws://localhost:3032: {}", e);
warn!(" 💡 Start a server on port 3032 to test this feature");
} else {
info!(" ✅ Connected to new server ws://localhost:3032");
}
info!("🎉 WebSocket Manager Demo completed!");
info!("💡 Key takeaways:");
info!(" - Use WsManager::builder() to configure multiple servers");
info!(" - Call connect() to establish all connections");
info!(" - Use with_client() for operations on specific servers");
info!(" - Use with_all_clients() for bulk operations");
info!(" - Connections are managed automatically with keep-alive");
Ok(())
}