Go to file
2025-07-21 00:17:46 +02:00
examples/website first commit 2025-07-21 00:17:46 +02:00
src first commit 2025-07-21 00:17:46 +02:00
.gitignore first commit 2025-07-21 00:17:46 +02:00
ARCHITECTURE.md first commit 2025-07-21 00:17:46 +02:00
Cargo.lock first commit 2025-07-21 00:17:46 +02:00
Cargo.toml first commit 2025-07-21 00:17:46 +02:00
README.md first commit 2025-07-21 00:17:46 +02:00
WASM_OPT_SOLUTION.md first commit 2025-07-21 00:17:46 +02:00

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

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)

[dependencies]
framework = { path = "path/to/framework", features = ["crypto"] }
serde = { version = "1.0", features = ["derive"] }

For WASM Applications (wasm-opt compatible)

[dependencies]
framework = { path = "path/to/framework", features = ["wasm-compatible"] }
serde = { version = "1.0", features = ["derive"] }

For Mixed Targets

[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)

use framework::ws_manager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 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)

use framework::ws_manager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 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)

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! {
        <div>
            <button onclick={on_connect}>{"Connect"}</button>
            <button onclick={on_execute_script}>{"Execute Script"}</button>
            // ... rest of your UI
        </div>
    }
}

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<PlayResultClient, CircleWsClientError> - Execute a Rhai script
  • execute_script_on_all(script: String) -> HashMap<String, Result<PlayResultClient, CircleWsClientError>> - Execute script on all servers
  • disconnect(url: &str) - Disconnect from a specific server
  • disconnect_all() - Disconnect from all servers
  • get_connected_urls() -> Vec<String> - 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<String, String> - Get all connection statuses
  • get_server_urls() -> Vec<String> - 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:

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

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

[dependencies]
framework = { features = ["crypto"] }

Conditional Compilation

#[cfg(feature = "crypto")]
fn with_authentication() {
    let auth = AuthConfig::new("private_key".to_string());
    let manager = WsConnectionManager::<MyData>::with_auth(auth);
    // ... authenticated operations
}

#[cfg(not(feature = "crypto"))]
fn without_authentication() {
    let manager = WsConnectionManager::<MyData>::new();
    // ... basic WebSocket operations
}

For detailed information about the solution, see 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:

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.