Crate wsforge_core

Crate wsforge_core 

Source
Expand description

Β§WsForge Core - High-Performance WebSocket Framework

wsforge-core is the foundational library for the WsForge WebSocket framework. It provides type-safe, ergonomic abstractions for building real-time WebSocket applications with exceptional performance and developer experience.

Β§Overview

WsForge Core combines the power of tokio-tungstenite with a flexible, type-safe API inspired by modern web frameworks like Axum. It’s designed for building production-ready WebSocket servers that are both fast and maintainable.

Β§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 various types - String, Message, Result, JsonResponse
  • πŸ“‘ Broadcasting: Built-in broadcast, broadcast_except, and targeted messaging
  • ⚑ Concurrent: Lock-free connection management with DashMap
  • πŸ”„ Lifecycle Hooks: on_connect and on_disconnect callbacks
  • 🌐 Hybrid Server: Serve static files and WebSocket on same port
  • πŸ›‘οΈ Type Safety: Compile-time guarantees for correctness

Β§Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Application                            β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Handlers  β”‚  β”‚  Router  β”‚  β”‚  State & Extractors   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      WsForge Core                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Connection  β”‚  β”‚     Message     β”‚  β”‚   Static Files  β”‚ β”‚
β”‚  β”‚   Manager    β”‚  β”‚     Router      β”‚  β”‚     Handler     β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    tokio-tungstenite                          β”‚
β”‚                  (WebSocket Protocol)                         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Β§Module Structure

  • connection: WebSocket connection management and lifecycle
  • message: Message types and parsing utilities
  • [handler]: Handler trait and response types
  • extractor: Type-safe data extraction from messages
  • router: Routing and server management
  • state: Shared application state container
  • error: Error types and result handling
  • static_files: Static file serving for hybrid servers

Β§Quick Start Examples

Β§Echo Server

The simplest possible WebSocket server:

use wsforge_core::prelude::*;

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

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

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

Β§Chat Server with Broadcasting

A real-time chat application:

use wsforge_core::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!("βœ… {} connected (Total: {})", conn_id, manager.count());
        })
        .on_disconnect(|manager, conn_id| {
            println!("❌ {} disconnected", conn_id);
        });

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

Β§Web Application with Static Files

Hybrid HTTP/WebSocket server:

use wsforge_core::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
        .default_handler(handler(ws_handler));

    // Handles both:
    // http://localhost:8080/        -> public/index.html
    // ws://localhost:8080           -> WebSocket handler

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

Β§Handler Patterns

Β§Simple Handler

use wsforge_core::prelude::*;

async fn simple_handler() -> Result<String> {
    Ok("Hello, WebSocket!".to_string())
}

Β§With JSON Extraction

use wsforge_core::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct Request {
    action: String,
    data: String,
}

async fn json_handler(Json(req): Json<Request>) -> Result<String> {
    Ok(format!("Action: {}, Data: {}", req.action, req.data))
}

Β§With State and Connection

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

async fn stateful_handler(
    msg: Message,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<String> {
    Ok(format!(
        "Connection {} | {} total connections",
        conn.id(),
        manager.count()
    ))
}

Β§Extractors

WsForge provides powerful type-safe extractors:

ExtractorDescriptionExample
MessageRaw messagemsg: Message
Json<T>JSON deserializationJson(data): Json<MyStruct>
ConnectionActive connectionconn: Connection
State<T>Shared stateState(db): State<Arc<Database>>
ConnectInfoConnection metadataConnectInfo(info)
DataRaw bytesData(bytes): Data

Β§Response Types

Handlers can return various types:

use wsforge_core::prelude::*;

// No response
async fn handler1() -> Result<()> {
    Ok(())
}

// Text response
async fn handler2() -> Result<String> {
    Ok("response".to_string())
}

// Raw message
async fn handler3() -> Result<Message> {
    Ok(Message::text("response"))
}

// Binary response
async fn handler4() -> Result<Vec<u8>> {
    Ok(vec!)[1][2][3][4]
}

// JSON response
async fn handler5() -> Result<JsonResponse<serde_json::Value>> {
    Ok(JsonResponse(serde_json::json!({"status": "ok"})))
}

Β§Broadcasting Patterns

Β§Broadcast to All

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

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

Β§Broadcast Except Sender

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

async fn broadcast_others(
    msg: Message,
    conn: Connection,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    manager.broadcast_except(conn.id(), msg);
    Ok(())
}

Β§Targeted Broadcasting

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

async fn broadcast_to_room(
    msg: Message,
    State(manager): State<Arc<ConnectionManager>>,
) -> Result<()> {
    let room_members = vec!["conn_1".to_string(), "conn_2".to_string()];
    manager.broadcast_to(&room_members, msg);
    Ok(())
}

Β§Error Handling

WsForge provides comprehensive error handling:

use wsforge_core::prelude::*;

async fn safe_handler(msg: Message) -> Result<String> {
    // Parse JSON
    let data: serde_json::Value = msg.json()?;

    // Validate
    if data.is_null() {
        return Err(Error::custom("Data cannot be null"));
    }

    // Process and return
    Ok("processed".to_string())
}

Β§Performance Characteristics

  • Connection Management: O(1) lock-free operations via DashMap
  • Message Routing: O(1) handler lookup
  • Broadcasting: O(n) where n is the number of connections
  • Memory: Zero-copy message handling where possible
  • Concurrency: Full async/await with tokio

Β§Testing

WsForge handlers are easy to test:

use wsforge_core::prelude::*;

async fn my_handler(msg: Message) -> Result<String> {
    Ok(format!("Echo: {}", msg.as_text().unwrap_or("")))
}

#[tokio::test]
async fn test_handler() {
    let msg = Message::text("hello");
    let result = my_handler(msg).await.unwrap();
    assert_eq!(result, "Echo: hello");
}

Β§Production Considerations

Β§Rate Limiting

use wsforge_core::prelude::*;
use std::sync::Arc;
use tokio::sync::RwLock;
use std::collections::HashMap;

struct RateLimiter {
    limits: RwLock<HashMap<String, u32>>,
}

async fn rate_limited_handler(
    msg: Message,
    conn: Connection,
    State(limiter): State<Arc<RateLimiter>>,
) -> Result<String> {
    // Check rate limit
    // Process if allowed
    Ok("processed".to_string())
}

Β§Graceful Shutdown

use wsforge_core::prelude::*;
use tokio::signal;

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

    tokio::select! {
        _ = router.listen("127.0.0.1:8080") => {},
        _ = signal::ctrl_c() => {
            println!("Shutting down gracefully...");
        }
    }

    Ok(())
}

Β§Further Reading

Re-exportsΒ§

pub use connection::Connection;
pub use connection::ConnectionId;
pub use error::Error;
pub use error::Result;
pub use extractor::ConnectInfo;
pub use extractor::Data;
pub use extractor::Extension;
pub use extractor::Extensions;
pub use extractor::Json;
pub use extractor::Path;
pub use extractor::Query;
pub use extractor::State;
pub use handler::Handler;
pub use handler::HandlerService;
pub use handler::IntoResponse;
pub use handler::JsonResponse;
pub use handler::handler;
pub use message::Message;
pub use message::MessageType;
pub use router::Route;
pub use router::Router;
pub use state::AppState;
pub use static_files::StaticFileHandler;

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.
prelude
Commonly used types and traits for WsForge applications.
router
Routing and server management for WebSocket connections.
state
Shared application state management.
static_files
Static file serving for hybrid HTTP/WebSocket servers.