pub struct Router { /* private fields */ }Expand description
The main router for WebSocket servers with middleware support.
Router is the central component that manages routing, middleware, state, connections,
and server lifecycle. It uses a builder pattern for configuration and supports both
WebSocket and HTTP static file serving on the same port.
§Middleware System
The router supports two types of middleware:
- Global middleware (added with
layer()) - Applied to all routes - Per-route middleware (added with
route_with_layers()) - Applied to specific routes
Execution order: Global middleware → Per-route middleware → Handler
§Thread Safety
Router is thread-safe and can be cloned cheaply (uses Arc internally).
All connections share the same router instance.
§Examples
§Basic Setup
use wsforge::prelude::*;
async fn handler(msg: Message) -> Result<String> {
Ok("received".to_string())
}
let router = Router::new()
.default_handler(handler(handler));
router.listen("0.0.0.0:8080").await?;§With Middleware Layers
use wsforge::prelude::*;
let router = Router::new()
.layer(LoggerMiddleware::new()) // Global: logs all
.layer(auth_middleware()) // Global: auth all
.route("/public", handler(handler)) // No extra middleware
.route_with_layers(
"/admin",
vec![admin_only_middleware()], // Per-route: admin only
handler(handler)
);
router.listen("127.0.0.1:8080").await?;Implementations§
Source§impl Router
impl Router
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty router.
The router starts with no routes, no middleware, no state, and no handlers. Use the builder methods to configure it.
§Examples
use wsforge::prelude::*;
let router = Router::new();Sourcepub fn layer(self, middleware: Arc<dyn Middleware>) -> Self
pub fn layer(self, middleware: Arc<dyn Middleware>) -> Self
Add a global middleware layer that applies to all routes.
Global middleware are executed before per-route middleware and handlers. They are executed in the order they are added.
§Arguments
middleware- The middleware to add
§Examples
§Single Middleware
use wsforge::prelude::*;
let router = Router::new()
.layer(LoggerMiddleware::new());§Multiple Middleware
use wsforge::prelude::*;
let router = Router::new()
.layer(LoggerMiddleware::new()) // First: logging
.layer(auth_middleware()) // Second: authentication
.layer(rate_limit_middleware()); // Third: rate limitingSourcepub fn route(self, path: impl Into<String>, handler: Arc<dyn Handler>) -> Self
pub fn route(self, path: impl Into<String>, handler: Arc<dyn Handler>) -> Self
Registers a handler for a specific route without additional middleware.
Global middleware will still apply to this route. For route-specific middleware,
use route_with_layers().
Routes are matched against the beginning of incoming messages.
For example, a message like /chat hello would match route /chat.
§Arguments
path- The route path (e.g., “/chat”, “/api/users”)handler- The handler function wrapped withhandler()
§Examples
use wsforge::prelude::*;
async fn chat_handler(msg: Message) -> Result<String> {
Ok("chat response".to_string())
}
async fn api_handler(msg: Message) -> Result<String> {
Ok("api response".to_string())
}
let router = Router::new()
.route("/chat", handler(chat_handler))
.route("/api", handler(api_handler));Sourcepub fn route_with_layers(
self,
path: impl Into<String>,
layers: Vec<Arc<dyn Middleware>>,
handler: Arc<dyn Handler>,
) -> Self
pub fn route_with_layers( self, path: impl Into<String>, layers: Vec<Arc<dyn Middleware>>, handler: Arc<dyn Handler>, ) -> Self
Per-route middleware are executed after global middleware but before the handler. This is useful for route-specific concerns like authorization or validation.
§Arguments
path- The route path (e.g., “/admin”, “/api/users”)layers- Vector of middleware to apply to this routehandler- The handler function wrapped withhandler()
§Examples
§Admin Route with Auth
use wsforge::prelude::*;
async fn admin_handler(msg: Message) -> Result<String> {
Ok("Admin panel".to_string())
}
let router = Router::new()
.route_with_layers(
"/admin",
vec![
auth_middleware(),
admin_check_middleware(),
],
handler(admin_handler)
);§API Route with Validation
use wsforge::prelude::*;
async fn api_handler(msg: Message) -> Result<String> {
Ok("API response".to_string())
}
let router = Router::new()
.route_with_layers(
"/api/users",
vec![validate_json_middleware()],
handler(api_handler)
);Sourcepub fn with_state<T: Send + Sync + 'static>(self, data: Arc<T>) -> Self
pub fn with_state<T: Send + Sync + 'static>(self, data: Arc<T>) -> Self
Adds shared state to the router.
State is shared across all connections and can be extracted in handlers
using the [State] extractor. Any type that is Send + Sync + 'static
can be used as state.
§Type Safety
Multiple different types can be added as state. Each type is stored separately and retrieved by type.
§Arguments
data- The state data to share (wrapped inArc)
§Examples
§Single State
use wsforge::prelude::*;
use std::sync::Arc;
struct Database {
// database fields
}
async fn handler(State(db): State<Arc<Database>>) -> Result<String> {
Ok("query result".to_string())
}
let db = Arc::new(Database {});
let router = Router::new()
.with_state(db)
.default_handler(handler(handler));§Multiple States
use wsforge::prelude::*;
use std::sync::Arc;
struct Config {
port: u16,
}
struct Database {
// database fields
}
let router = Router::new()
.with_state(Arc::new(Config { port: 8080 }))
.with_state(Arc::new(Database {}));Sourcepub fn on_connect<F>(self, f: F) -> Self
pub fn on_connect<F>(self, f: F) -> Self
Sets a callback to be called when a new connection is established.
The callback receives a reference to the connection manager and the connection ID. This is useful for logging, sending welcome messages, or updating user lists.
§Arguments
f- Callback function with signatureFn(&Arc<ConnectionManager>, ConnectionId)
§Examples
§Simple Logging
use wsforge::prelude::*;
let router = Router::new()
.on_connect(|manager, conn_id| {
println!("New connection: {} (Total: {})", conn_id, manager.count());
});§Send Welcome Message
use wsforge::prelude::*;
let router = Router::new()
.on_connect(|manager, conn_id| {
if let Some(conn) = manager.get(&conn_id) {
let _ = conn.send_text("Welcome to the server!");
}
});§Broadcast Join Notification
use wsforge::prelude::*;
let router = Router::new()
.on_connect(|manager, conn_id| {
let msg = format!("User {} joined", conn_id);
manager.broadcast(Message::text(msg));
});Sourcepub fn on_disconnect<F>(self, f: F) -> Self
pub fn on_disconnect<F>(self, f: F) -> Self
Sets a callback to be called when a connection is closed.
The callback receives a reference to the connection manager and the connection ID. Note that the connection is already removed from the manager when this is called.
§Arguments
f- Callback function with signatureFn(&Arc<ConnectionManager>, ConnectionId)
§Examples
§Logging Disconnections
use wsforge::prelude::*;
let router = Router::new()
.on_disconnect(|manager, conn_id| {
println!("Connection {} closed (Remaining: {})", conn_id, manager.count());
});§Broadcast Leave Notification
use wsforge::prelude::*;
let router = Router::new()
.on_disconnect(|manager, conn_id| {
let msg = format!("User {} left", conn_id);
manager.broadcast(Message::text(msg));
});Sourcepub fn default_handler(self, handler: Arc<dyn Handler>) -> Self
pub fn default_handler(self, handler: Arc<dyn Handler>) -> Self
Sets the default handler for messages that don’t match any route.
This handler is called when no route matches the incoming message. Global middleware will still be applied to the default handler.
§Arguments
handler- The default handler wrapped withhandler()
§Examples
§Echo Server
use wsforge::prelude::*;
async fn echo(msg: Message) -> Result<Message> {
Ok(msg)
}
let router = Router::new()
.default_handler(handler(echo));§Error Handler
use wsforge::prelude::*;
async fn not_found() -> Result<String> {
Ok("Unknown command".to_string())
}
let router = Router::new()
.route("/known", handler(not_found))
.default_handler(handler(not_found));Sourcepub fn serve_static(self, path: impl Into<PathBuf>) -> Self
pub fn serve_static(self, path: impl Into<PathBuf>) -> Self
Enables static file serving from a directory.
When enabled, the router will serve static files (HTML, CSS, JavaScript, images) from the specified directory for HTTP requests, while still handling WebSocket connections on the same port.
§Path Resolution
- Requests to
/serveindex.htmlfrom the directory - Other requests map directly to files (e.g.,
/style.css→directory/style.css) - MIME types are automatically detected
§Security
Path traversal attempts (e.g., ../../etc/passwd) are automatically blocked.
§Arguments
path- Path to the directory containing static files
§Examples
§Serve Static Files
use wsforge::prelude::*;
async fn ws_handler(msg: Message) -> Result<Message> {
Ok(msg)
}
let router = Router::new()
.serve_static("public") // Serve files from ./public
.default_handler(handler(ws_handler));
// Now you can access:
// http://localhost:8080/ -> public/index.html
// http://localhost:8080/app.js -> public/app.js
// ws://localhost:8080 -> WebSocket handlerSourcepub fn connection_manager(&self) -> Arc<ConnectionManager>
pub fn connection_manager(&self) -> Arc<ConnectionManager>
Returns a reference to the connection manager.
The connection manager is automatically created with the router. Use this to get access to it for storing in state or elsewhere.
§Examples
use wsforge::prelude::*;
let router = Router::new();
let manager = router.connection_manager();
// Now you can use the manager
println!("Active connections: {}", manager.count());Sourcepub async fn listen(self, addr: impl AsRef<str>) -> Result<()>
pub async fn listen(self, addr: impl AsRef<str>) -> Result<()>
Starts the WebSocket server and listens for connections.
This method consumes the router and starts the server loop. It will run indefinitely until the process is terminated or an error occurs.
The connection manager is automatically inserted into the router’s state
before the server starts, making it available to all handlers via the
State<Arc<ConnectionManager>> extractor.
§Arguments
addr- The address to bind to (e.g., “127.0.0.1:8080”, “0.0.0.0:3000”)
§Errors
Returns an error if:
- The address format is invalid
- The port is already in use
- Permission is denied (e.g., ports < 1024 on Unix)
§Examples
§Basic Usage
use wsforge::prelude::*;
let router = Router::new();
router.listen("127.0.0.1:8080").await?;§All Interfaces
use wsforge::prelude::*;
let router = Router::new();
router.listen("0.0.0.0:8080").await?; // Accept connections from anywhere