Timur Gordon 7ca492346d livekit wip
2025-08-29 15:29:24 +02:00
2025-08-05 15:02:23 +02:00
2025-08-29 15:29:24 +02:00
2025-07-21 00:17:46 +02:00

Awesome Web Assembly for Real-time Experiences

This repository contains a collection of tools and libraries for building real-time experiences using WebAssembly (WASM). It includes a WebSocket connection manager built on top of the robust circle_client_ws library, as well as a file browser component for managing files on a server.

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.

Description
Local Embedded Application Front End Framework
Readme 57 MiB
Languages
Rust 74.6%
JavaScript 16.2%
HTML 8.3%
Shell 0.9%