# Framework WebSocket Connection Manager A simplified WebSocket connection manager built on top of the robust `circle_client_ws` library. This framework provides a clean builder pattern API for managing multiple self-managing WebSocket connections with authentication support and script execution capabilities. ## Features - 🔗 **Multiple Self-Managing Connections**: Each connection handles its own lifecycle automatically - 🔐 **secp256k1 Authentication**: Built-in support for cryptographic authentication (native only) - 📜 **Rhai Script Execution**: Execute Rhai scripts on connected servers via the `play` function - 🌐 **Cross-Platform**: Works in both WASM (browser) and native environments - 🎯 **Builder Pattern**: Clean, fluent API for configuration - ⚡ **Async/Await**: Modern async/await interface - 🔄 **Automatic Connection Management**: Each client handles keep-alive and reconnection internally - 🛠️ **WASM-opt Compatible**: Feature flags to avoid crypto-related wasm-opt issues ## Simplified Architecture ```mermaid graph TD A[Framework Lib] --> B[WsManager] B --> C[WsManagerBuilder] B --> D[Connection Pool] D --> E[Self-Managing CircleWsClient 1] D --> F[Self-Managing CircleWsClient 2] D --> G[Self-Managing CircleWsClient N] E --> E1[Internal Keep-Alive] E --> E2[Internal Reconnection] E --> E3[Internal Auth] F --> F1[Internal Keep-Alive] F --> F2[Internal Reconnection] F --> F3[Internal Auth] G --> G1[Internal Keep-Alive] G --> G2[Internal Reconnection] G --> G3[Internal Auth] H[Website Example] --> A I[Other Applications] --> A ``` ### Key Architectural Changes - **Self-Managing Clients**: Each `CircleWsClient` handles its own connection lifecycle - **Simplified WsManager**: Acts as a simple container and builder, not a complex orchestrator - **No External Keep-Alive**: Keep-alive and reconnection logic moved into individual clients - **Builder Pattern**: Clean API with `new()`, `private_key()`, `add_server_url()`, and `build()` methods ## Quick Start ### Add to Your Project Add the framework to your `Cargo.toml`: #### For Native Applications (with full crypto support) ```toml [dependencies] framework = { path = "path/to/framework", features = ["crypto"] } serde = { version = "1.0", features = ["derive"] } ``` #### For WASM Applications (wasm-opt compatible) ```toml [dependencies] framework = { path = "path/to/framework", features = ["wasm-compatible"] } serde = { version = "1.0", features = ["derive"] } ``` #### For Mixed Targets ```toml [target.'cfg(target_arch = "wasm32")'.dependencies] framework = { path = "path/to/framework", features = ["wasm-compatible"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] framework = { path = "path/to/framework", features = ["crypto"] } [dependencies] serde = { version = "1.0", features = ["derive"] } ``` ### Basic Usage (New Simplified API) ```rust use framework::ws_manager; #[tokio::main] async fn main() -> Result<(), Box> { // Create a connection manager using the builder pattern let manager = ws_manager() .add_server_url("ws://localhost:8080".to_string()) .add_server_url("ws://localhost:8081".to_string()) .build(); // Connect to all configured servers // Each client handles its own authentication, keep-alive, and reconnection manager.connect().await?; // Execute a Rhai script on a specific server let script = r#" let message = "Hello from WebSocket!"; let value = 42; `{"message": "${message}", "value": ${value}}` "#; let result = manager.execute_script("ws://localhost:8080", script.to_string()).await?; println!("Result: {:?}", result); // Check connection status println!("Connected URLs: {:?}", manager.get_connected_urls()); // Cleanup (optional - clients clean up automatically when dropped) manager.disconnect_all().await; Ok(()) } ``` ### With Authentication (Simplified) ```rust use framework::ws_manager; #[tokio::main] async fn main() -> Result<(), Box> { // Create manager with authentication using builder pattern let manager = ws_manager() .private_key("your_private_key_hex".to_string()) .add_server_url("wss://secure-server.com".to_string()) .build(); // Connect - authentication is handled automatically by each client manager.connect().await?; // Execute scripts on authenticated connections let result = manager.execute_script("wss://secure-server.com", "your_script".to_string()).await?; Ok(()) } ``` ### WASM/Yew Integration (Simplified) ```rust use yew::prelude::*; use framework::ws_manager; #[function_component(WebSocketComponent)] pub fn websocket_component() -> Html { // Create manager with builder pattern let manager = use_state(|| { ws_manager() .add_server_url("ws://localhost:8080".to_string()) .build() }); let on_connect = { let manager = manager.clone(); Callback::from(move |_| { let manager = (*manager).clone(); wasm_bindgen_futures::spawn_local(async move { // Simple connect - each client manages itself if let Err(e) = manager.connect().await { log::error!("Connection failed: {}", e); } else { log::info!("Connected successfully!"); // Clients automatically handle keep-alive and reconnection } }); }) }; let on_execute_script = { let manager = manager.clone(); Callback::from(move |_| { let manager = (*manager).clone(); wasm_bindgen_futures::spawn_local(async move { let script = "\"Hello from WASM!\"".to_string(); match manager.execute_script("ws://localhost:8080", script).await { Ok(result) => log::info!("Script result: {:?}", result), Err(e) => log::error!("Script execution failed: {}", e), } }); }) }; html! {
// ... rest of your UI
} } ``` ## API Reference ### Core Types (Simplified API) #### `WsManagerBuilder` Builder for creating WebSocket connection managers with a fluent API. **Methods:** - `new() -> Self` - Create a new builder - `private_key(self, private_key: String) -> Self` - Set authentication private key - `add_server_url(self, url: String) -> Self` - Add a server URL to connect to - `build(self) -> WsManager` - Build the final manager #### `WsManager` The simplified connection manager that holds multiple self-managing WebSocket connections. **Methods:** - `builder() -> WsManagerBuilder` - Create a new builder - `connect() -> Result<(), CircleWsClientError>` - Connect to all configured servers - `execute_script(url: &str, script: String) -> Result` - Execute a Rhai script - `execute_script_on_all(script: String) -> HashMap>` - Execute script on all servers - `disconnect(url: &str)` - Disconnect from a specific server - `disconnect_all()` - Disconnect from all servers - `get_connected_urls() -> Vec` - Get list of connected URLs - `is_connected(url: &str) -> bool` - Check if connected to a URL - `connection_count() -> usize` - Get number of connected servers - `get_connection_status(url: &str) -> String` - Get connection status for a URL - `get_all_connection_statuses() -> HashMap` - Get all connection statuses - `get_server_urls() -> Vec` - Get list of configured server URLs #### Convenience Functions - `ws_manager() -> WsManagerBuilder` - Create a new WsManager builder ### Key Simplifications 1. **No Complex Configuration Objects**: Simple builder pattern with direct methods 2. **Self-Managing Clients**: Each connection handles its own lifecycle automatically 3. **No External Keep-Alive Management**: Keep-alive logic is internal to each client 4. **Simplified Error Handling**: Uses `CircleWsClientError` directly from the underlying library ### Error Handling The library uses `CircleWsClientError` from the underlying client library for error handling: ```rust match manager.connect().await { Ok(_) => println!("Connected successfully to all configured servers"), Err(CircleWsClientError::NotConnected) => println!("Failed to connect to any servers"), Err(CircleWsClientError::Auth(auth_error)) => println!("Authentication error: {:?}", auth_error), Err(e) => println!("Other error: {:?}", e), } // Execute script with error handling match manager.execute_script("ws://localhost:8080", script).await { Ok(result) => println!("Script result: {:?}", result), Err(CircleWsClientError::NotConnected) => println!("Not connected to server"), Err(e) => println!("Script execution error: {:?}", e), } ``` ## Example Application The `examples/website` directory contains a complete Yew WASM application demonstrating the WebSocket connection manager: - **Interactive UI**: Connect to multiple WebSocket servers - **Script Editor**: Write and execute Rhai scripts - **Real-time Results**: See script execution results in real-time - **Connection Management**: Connect, disconnect, and monitor connection status ### Running the Example ```bash cd examples/website ## WASM-opt Compatibility This framework solves the common issue where cryptographic dependencies cause wasm-opt parsing errors in WASM builds. The solution uses feature flags to conditionally enable crypto functionality. ### The Problem When building WASM applications with aggressive optimizations, you might encounter: ``` [parse exception: invalid code after misc prefix: 17 (at 0:732852)] Fatal: error parsing wasm (try --debug for more info) ``` This is caused by cryptographic libraries (`secp256k1`, `sha3`) that are incompatible with wasm-opt's optimization passes. ### The Solution Use feature flags to control crypto dependencies: - **`crypto`**: Full secp256k1 authentication support (native applications) - **`wasm-compatible`**: Basic WebSocket functionality without crypto (WASM applications) ### Usage Examples #### WASM Application (Recommended) ```toml [dependencies] framework = { features = ["wasm-compatible"] } ``` #### Native Application with Authentication ```toml [dependencies] framework = { features = ["crypto"] } ``` #### Conditional Compilation ```rust #[cfg(feature = "crypto")] fn with_authentication() { let auth = AuthConfig::new("private_key".to_string()); let manager = WsConnectionManager::::with_auth(auth); // ... authenticated operations } #[cfg(not(feature = "crypto"))] fn without_authentication() { let manager = WsConnectionManager::::new(); // ... basic WebSocket operations } ``` For detailed information about the solution, see [`WASM_OPT_SOLUTION.md`](WASM_OPT_SOLUTION.md). trunk serve ``` Then navigate to `http://localhost:8080/websocket` to see the demo. ## Dependencies The framework builds on these excellent libraries: - **[circle_client_ws](../circles/src/client_ws)**: Robust WebSocket client with authentication - **[yew](https://yew.rs/)**: Modern Rust framework for web frontend (WASM only) - **[tokio](https://tokio.rs/)**: Async runtime (native only) - **[serde](https://serde.rs/)**: Serialization framework ## Development ### Building ```bash # Check the library cargo check # Run tests cargo test # Build the example cd examples/website trunk build --release ``` ### Testing The library includes comprehensive tests for all major functionality: ```bash cargo test ``` ### Contributing 1. Fork the repository 2. Create a feature branch 3. Add tests for new functionality 4. Ensure all tests pass 5. Submit a pull request ## License This project is part of the larger framework and follows the same license terms. ## Roadmap - [ ] Connection pooling and load balancing - [ ] Automatic reconnection with exponential backoff - [ ] Metrics and monitoring integration - [ ] Support for additional authentication methods - [ ] WebSocket compression support - [ ] Connection health checks and heartbeat ## Support For questions, issues, or contributions, please refer to the main project repository.