Crate wsforge

Crate wsforge 

Source
Expand description

ยงWsForge - High-Performance WebSocket Framework for Rust

WsForge is a complete, production-ready WebSocket framework that combines exceptional performance with an intuitive, type-safe API. Built on tokio-tungstenite, it provides everything needed to build real-time applications, from simple echo servers to complex multiplayer games and chat platforms.

ยงOverview

WsForge brings together the best practices from modern web frameworks like Axum and combines them with the performance of Rustโ€™s async ecosystem. Whether youโ€™re building a chat application, real-time dashboard, collaborative editor, or multiplayer game, WsForge provides the tools you need.

ยง๐ŸŒŸ Key Features

  • ๐Ÿš€ High Performance: Built on tokio-tungstenite with zero-copy optimizations
  • ๐Ÿ”ง Type-Safe Extractors: Automatic extraction of JSON, State, Connection info
  • ๐ŸŽฏ Flexible Handlers: Return String, Message, Result, JsonResponse, or ()
  • ๐Ÿ“ก Broadcasting: Built-in broadcast, broadcast_except, and targeted messaging
  • โšก Concurrent: Lock-free connection management using DashMap
  • ๐Ÿ”„ Lifecycle Hooks: on_connect and on_disconnect callbacks
  • ๐ŸŒ Hybrid Server: Serve static files and WebSocket on the same port
  • ๐Ÿ›ก๏ธ Type Safety: Compile-time guarantees prevent common errors
  • ๐ŸŽจ Developer Friendly: Intuitive API similar to popular Rust web frameworks
  • ๐Ÿ“ฆ Batteries Included: Macros, examples, and documentation

ยงQuick Start

Add WsForge to your Cargo.toml:

[dependencies]
wsforge = "0.1.0"
tokio = { version = "1.40", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

ยงEcho Server Example

Create a simple echo server in just a few lines:

use wsforge::prelude::*;

async fn echo(msg: Message) -> Result<Message> {
    Ok(msg)
}

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new()
        .default_handler(handler(echo));

    println!("WebSocket server running on ws://127.0.0.1:8080");
    router.listen("127.0.0.1:8080").await?;
    Ok(())
}

ยงChat Server Example

Build a real-time chat server with broadcasting:

use wsforge::prelude::*;
use std::sync::Arc;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct ChatMessage {
    username: String,
    text: String,
}

async fn chat_handler(
    Json(msg): Json<ChatMessage>,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    println!("{}: {}", msg.username, msg.text);

    // Broadcast to everyone except sender
    let response = serde_json::to_string(&msg)?;
    manager.broadcast_except(conn.id(), Message::text(response));

    Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new()
        .default_handler(handler(chat_handler))
        .on_connect(|manager, conn_id| {
            println!("โœ… {} joined (Total: {})", conn_id, manager.count());
        })
        .on_disconnect(|manager, conn_id| {
            println!("โŒ {} left (Total: {})", conn_id, manager.count());
        });

    router.listen("127.0.0.1:8080").await?;
    Ok(())
}

ยงWeb Application Example

Create a hybrid server that serves static files and handles WebSocket connections:

use wsforge::prelude::*;
use std::sync::Arc;

async fn ws_handler(
    msg: Message,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    manager.broadcast(msg);
    Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new()
        .serve_static("public")  // Serve HTML/CSS/JS from ./public
        .default_handler(handler(ws_handler));

    println!("Server running on http://127.0.0.1:8080");
    router.listen("127.0.0.1:8080").await?;
    Ok(())
}

ยง๐Ÿ“š Core Concepts

ยงHandlers

Handlers are async functions that process WebSocket messages. They can extract data using type-safe extractors and return various response types:

use wsforge::prelude::*;
use std::sync::Arc;

// Simple handler
async fn simple() -> Result<String> {
    Ok("Hello!".to_string())
}

// Handler with extractors
async fn with_extractors(
    msg: Message,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    println!("Received from {}: {:?}", conn.id(), msg);
    Ok(())
}

ยงExtractors

Extractors automatically parse and validate data from messages and context:

ExtractorDescription
MessageRaw WebSocket message
Json<T>Deserialize JSON automatically
ConnectionAccess to the active connection
State<T>Shared application state
ConnectInfoConnection metadata
DataRaw binary data

ยงBroadcasting

Send messages to multiple connections efficiently:

use wsforge::prelude::*;
use std::sync::Arc;

async fn broadcast_example(
    msg: Message,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    // Broadcast to all
    manager.broadcast(msg.clone());

    // Broadcast except sender
    manager.broadcast_except(conn.id(), msg.clone());

    // Broadcast to specific connections
    let targets = vec!["conn_1".to_string(), "conn_2".to_string()];
    manager.broadcast_to(&targets, msg);

    Ok(())
}

ยงState Management

Share data across all connections:

use wsforge::prelude::*;
use std::sync::Arc;

struct Database {
    // Database connection pool
}

struct Config {
    max_connections: usize,
}

async fn handler(
    State(db): State<Arc<Database>>,
    State(config): State<Arc<Config>>,
) -> Result<String> {
    Ok(format!("Max connections: {}", config.max_connections))
}

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new()
        .with_state(Arc::new(Database {}))
        .with_state(Arc::new(Config { max_connections: 100 }))
        .default_handler(handler(handler));

    router.listen("127.0.0.1:8080").await?;
    Ok(())
}

ยง๐ŸŽฎ Complete Examples

ยงReal-Time Game Server

use wsforge::prelude::*;
use std::sync::Arc;
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize)]
struct GameMove {
    player_id: u64,
    x: f32,
    y: f32,
}

async fn game_handler(
    Json(game_move): Json<GameMove>,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    // Broadcast move to all other players
    let json = serde_json::to_string(&game_move)?;
    manager.broadcast_except(conn.id(), Message::text(json));
    Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new()
        .default_handler(handler(game_handler))
        .on_connect(|manager, conn_id| {
            println!("๐ŸŽฎ Player {} joined", conn_id);
        });

    router.listen("0.0.0.0:8080").await?;
    Ok(())
}

ยงMulti-Room Chat

use wsforge::prelude::*;
use std::sync::Arc;
use std::collections::HashMap;
use tokio::sync::RwLock;
use serde::{Deserialize, Serialize};

#[derive(Clone)]
struct RoomManager {
    rooms: Arc<RwLock<HashMap<String, Vec<String>>>>,
}

#[derive(Deserialize)]
struct RoomMessage {
    room: String,
    text: String,
}

async fn room_handler(
    Json(msg): Json<RoomMessage>,
    conn: Connection,
    State(room_mgr): State<Arc<RoomManager>>,
    State(conn_mgr): State<Arc<ConnectionManager>>,
) -> Result<()> {
    // Get room members and broadcast
    let rooms = room_mgr.rooms.read().await;
    if let Some(members) = rooms.get(&msg.room) {
        let json = serde_json::to_string(&msg)?;
        conn_mgr.broadcast_to(members, Message::text(json));
    }
    Ok(())
}

ยง๐Ÿ”ง Advanced Features

ยงCustom Middleware

use wsforge::prelude::*;

async fn auth_middleware(
    msg: Message,
    extensions: &Extensions,
) -> Result<()> {
    // Verify authentication token
    let token = msg.as_text().ok_or(Error::custom("Invalid token"))?;

    // Store user info in extensions
    extensions.insert("user_id", 123_u64);

    Ok(())
}

ยงGraceful Shutdown

use wsforge::prelude::*;
use tokio::signal;

#[tokio::main]
async fn main() -> Result<()> {
    let router = Router::new();

    tokio::select! {
        result = router.listen("127.0.0.1:8080") => {
            if let Err(e) = result {
                eprintln!("Server error: {}", e);
            }
        }
        _ = signal::ctrl_c() => {
            println!("Shutting down gracefully...");
        }
    }

    Ok(())
}

ยง๐Ÿ“Š Performance

WsForge is designed for high performance:

  • Concurrent Connections: Handles thousands of connections efficiently
  • Lock-Free: DashMap-based connection management eliminates lock contention
  • Zero-Copy: Minimizes allocations and copies where possible
  • Async Native: Built on tokio for maximum async performance
  • Benchmarked: 47K+ requests/second for simple echo operations

ยง๐Ÿ›ก๏ธ Security

  • Path Traversal Protection: Static file handler prevents directory escapes
  • Type Safety: Rustโ€™s type system prevents common errors
  • Input Validation: JSON parsing with serde provides automatic validation
  • Connection Limits: Easy to implement rate limiting and connection caps

ยง๐Ÿ“– Documentation

ยง๐Ÿค Contributing

Contributions are welcome! Please see our Contributing Guide.

ยง๐Ÿ“ License

Licensed under the MIT License. See LICENSE for details.

ยง๐Ÿ™ Acknowledgments

Modulesยง

connection
WebSocket connection management and message handling.
error
Error types and result handling for WsForge.
extractor
Type-safe data extraction from WebSocket messages and context.
handler
Handler traits and implementations for WebSocket message processing.
message
WebSocket message types and utilities.
middleware
Middleware system for request/response processing.
prelude
Prelude module for convenient imports.
router
Routing and server management for WebSocket connections with middleware support.
state
Shared application state management.
static_files
Static file serving for hybrid HTTP/WebSocket servers.

Macrosยง

routesmacros
Creates a new Router instance.

Structsยง

AppState
A type-safe container for shared application state.
ConnectInfo
Extractor for connection metadata.
Connection
Represents an active WebSocket connection.
Data
Extractor for raw binary data.
Extension
Extractor for custom extension data.
Extensions
Container for request-scoped extension data.
HandlerService
Service wrapper for handler functions.
Json
Extractor for JSON data from messages.
JsonResponse
JSON response wrapper.
LoggerMiddleware
Built-in logger middleware for logging WebSocket messages.
Message
A WebSocket message.
MiddlewareChain
Middleware chain holds all middlewares and the final handler.
Next
Represents the next middleware or handler in the chain.
Path
Extractor for path parameters.
Query
Extractor for query parameters.
Route
Represents a single route with its path and middleware chain.
Router
The main router for WebSocket servers with middleware support.
State
Extractor for shared application state.
StaticFileHandler
Handler for serving static files from a directory.

Enumsยง

Error
The main error type for WsForge operations.
MessageType
Represents the type of a WebSocket message.

Traitsยง

Handler
Core trait for message handlers.
IntoResponse
Trait for converting handler return values into WebSocket messages.
Middleware
Middleware trait that all middleware must implement.

Functionsยง

handler
Converts an async function into a handler.

Type Aliasesยง

ConnectionId
A unique identifier for a WebSocket connection.
Result
A type alias for Result<T, Error>.

Attribute Macrosยง

websocket_handlermacros
Transforms an async function into a WebSocket handler.

Derive Macrosยง

WebSocketHandlermacros
Derives the Handler trait for custom handler types.
WebSocketMessagemacros
Derives message conversion methods for custom types.