### Basic Axum Server Setup Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html A minimal example demonstrating how to bind a TCP listener and serve an Axum router. This is a common setup for starting an Axum application. ```rust let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, handler.into_make_service()).await.unwrap(); ``` -------------------------------- ### Tapaculo Quick Start Example Source: https://docs.rs/tapaculo/latest/tapaculo A basic example demonstrating how to set up and run a Tapaculo server. It includes JWT authentication, in-memory pub/sub, and a simple message broadcasting logic. ```Rust use tapaculo::*; #[tokio::main] async fn main() -> anyhow::Result<()> { let auth = JwtAuth::new("your-secret-key"); let pubsub = InMemoryPubSub::new(); Server::new() .with_auth(auth) .with_pubsub(pubsub) .on_message(|ctx, envelope| async move { // Echo messages to all other players ctx.broadcast_to_others(envelope.data).await.ok(); }) .listen("0.0.0.0:8080") .await } ``` -------------------------------- ### Quick Start: Tapaculo Server Setup Source: https://docs.rs/tapaculo/latest/index.html This snippet demonstrates how to set up a basic Tapaculo server with JWT authentication and an in-memory PubSub backend. It includes a message handler that echoes messages to other players. Ensure you have the necessary dependencies and tokio runtime configured. ```rust use tapaculo::* #[tokio::main] async fn main() -> anyhow::Result<()> { let auth = JwtAuth::new("your-secret-key"); let pubsub = InMemoryPubSub::new(); Server::new() .with_auth(auth) .with_pubsub(pubsub) .on_message(|ctx, envelope| async move { // Echo messages to all other players ctx.broadcast_to_others(envelope.data).await.ok(); }) .listen("0.0.0.0:8080") .await } ``` -------------------------------- ### Quick Start: Basic Tapaculo Server Setup Source: https://docs.rs/tapaculo/latest/src/tapaculo/lib.rs.html Sets up a basic Tapaculo server with JWT authentication and an in-memory pub/sub system. It configures a message handler to broadcast received messages to all other players in the room. ```rust use tapaculo::* ; #[tokio::main] async fn main() -> anyhow::Result<()> { let auth = JwtAuth::new("your-secret-key"); let pubsub = InMemoryPubSub::new(); Server::new() .with_auth(auth) .with_pubsub(pubsub) .on_message(|ctx, envelope| async move { // Echo messages to all other players ctx.broadcast_to_others(envelope.data).await.ok(); }) .listen("0.0.0.0:8080") .await } ``` -------------------------------- ### Chess Server Setup Source: https://docs.rs/tapaculo/latest/index.html Configures and starts a turn-based chess server for two players. Requires JWT authentication and an in-memory pub/sub backend. Messages are broadcast to all other players in the room. ```rust use tapaculo::*; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] enum ChessMove { Move { from: String, to: String }, Resign, } #[tokio::main] async fn main() -> anyhow::Result<()> { let room_settings = RoomSettings { max_players: Some(2), allow_spectators: false, store_message_history: true, ..Default::default() }; Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .with_room_settings(room_settings) .on_message_typed::(|ctx, envelope| async move { ctx.broadcast_to_others(envelope.data).await.ok(); }) .listen("0.0.0.0:8080") .await } ``` -------------------------------- ### Start WebSocket Server Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html A convenience function to start the WebSocket server. It internally calls `into_router()` and then uses `axum::serve` to begin listening for connections. Use `into_router()` directly if you need to integrate with custom HTTP routes. ```rust pub async fn listen(self, addr: &str) -> anyhow::Result<()> { let app = self.into_router(); let listener = tokio::net::TcpListener::bind(addr).await?; tracing::info!("WebSocket server listening on {}", addr); axum::serve(listener, app).await?; Ok(()) } ``` -------------------------------- ### Server::listen Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Server.html Starts the WebSocket server, acting as a convenience wrapper around `into_router` and `axum::serve`. ```APIDOC ## Server::listen ### Description Start the WebSocket server. Convenience wrapper around [`into_router`] + `axum::serve`. If you need to add your own HTTP routes, use [`into_router`] instead. ### Method ``` pub async fn listen(self, addr: &str) -> Result<()> ``` ``` -------------------------------- ### Create new InMemoryPubSub with default buffer Source: https://docs.rs/tapaculo/latest/tapaculo/pubsub/struct.InMemoryPubSub.html Instantiates a new InMemoryPubSub with a default per-topic buffer size of 64 messages. This is the simplest way to get started with the in-memory pub/sub system. ```rust pub fn new() -> Self ``` -------------------------------- ### Binding and Serving with Tokio Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Basic setup for binding a TCP listener and serving an Axum application. ```rust let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, routes).await.unwrap(); ``` -------------------------------- ### Example Usage of PubSubBackend Source: https://docs.rs/tapaculo/latest/tapaculo/pubsub/trait.PubSubBackend.html Demonstrates publishing a message and subscribing to a topic with a handler that processes incoming bytes. ```rust backend.publish("topic", &my_struct).await?; backend.subscribe("topic", |bytes| async move { println!("Got {} bytes", bytes.len()); }).await?; ``` -------------------------------- ### Chat Server Example: Group Messaging Setup Source: https://docs.rs/tapaculo/latest/src/tapaculo/lib.rs.html Sets up a Tapaculo server for group chat with up to 50 players. It enables message history and applies rate limiting to prevent spam, broadcasting all messages to everyone in the room. ```rust use tapaculo::* ; use std::time::Duration; # #[tokio::main] # async fn main() -> anyhow::Result<()> { Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .with_room_settings(RoomSettings { max_players: Some(50), store_message_history: true, max_history_messages: 200, ..Default::default() }) .with_limits(MessageLimits { max_messages_per_window: 10, window_duration: Duration::from_secs(1), ..Default::default() }) .on_message(|ctx, envelope| async move { ctx.broadcast(envelope.data).await.ok(); }) .listen("0.0.0.0:8081") .await # } ``` -------------------------------- ### JWT Authentication Setup Source: https://docs.rs/tapaculo/latest/tapaculo/index.html Initializes JWT authentication with a secret key and shows how to sign an access token for a user, room, and session. ```rust use tapaculo::JwtAuth; let auth = JwtAuth::new("your-secret-key"); let access_token = auth.sign_access( "user_id".to_string(), "room_id".to_string(), "session_id".to_string(), 3600 // 1 hour )?; ``` -------------------------------- ### Chess Server Example: Turn-Based Game Setup Source: https://docs.rs/tapaculo/latest/src/tapaculo/lib.rs.html Configures a Tapaculo server for a 2-player turn-based game like Chess. It uses typed messages for specific game moves and sets room constraints for a maximum of two players with message history enabled. ```rust use tapaculo::* ; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] enum ChessMove { Move { from: String, to: String }, Resign, } #[tokio::main] async fn main() -> anyhow::Result<()> { let room_settings = RoomSettings { max_players: Some(2), allow_spectators: false, store_message_history: true, ..Default::default() }; Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .with_room_settings(room_settings) .on_message_typed::(|ctx, envelope| async move { ctx.broadcast_to_others(envelope.data).await.ok(); }) .listen("0.0.0.0:8080") .await } ``` -------------------------------- ### Example Usage of InMemoryPubSub Source: https://docs.rs/tapaculo/latest/tapaculo/pubsub/index.html Demonstrates how to use the InMemoryPubSub for subscribing to and publishing messages within an application. Requires Tokio and Serde for message handling. ```rust use tapaculo::pubsub::{InMemoryPubSub, PubSubBackend, PubSubExt}; use serde::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct MyMsg { val: String } #[tokio::main] async fn main() { let backend = InMemoryPubSub::new(); // Subscribe to messages let _sub = backend.subscribe("chat", |bytes| async move { let msg: MyMsg = serde_json::from_slice(&bytes).unwrap(); println!("Got message: {}", msg.val); }).await.unwrap(); // Publish a message backend.publish("chat", &MyMsg { val: "hello".into() }).await.unwrap(); } ``` -------------------------------- ### Create a new JwtAuth instance Source: https://docs.rs/tapaculo/latest/tapaculo/auth/struct.JwtAuth.html Instantiate JwtAuth with a secret key for signing and verifying tokens. This is the basic setup for JWT authentication. ```rust use tapaculo::auth::{JwtAuth, JwtAuthOptions}; let auth = JwtAuth::new("my-secret-key"); ``` -------------------------------- ### WebSocket Server Setup with Axum Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Sets up a basic Axum router with a WebSocket endpoint for handling real-time communication. Requires necessary imports for Axum, rate limiting, room management, and authentication. ```rust use crate::{ rate_limit::{MessageLimits, RateLimiter}, room::{PlayerMetadata, RoomInfo, RoomManager, RoomSettings, StoredMessage}, JwtAuth, PubSubBackend, PubSubExt, }; use axum::{ extract::{ ws::{Message, WebSocket}, Query, State, WebSocketUpgrade, }, http::StatusCode, response::IntoResponse, routing::{get, post}, Json, Router, }; use futures::{ SinkExt, StreamExt }; use rand::Rng; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use std::{collections::HashMap, sync::Arc}; use tokio::sync::mpsc; /// WebSocket server for real-time multiplayer communication with room management. ``` -------------------------------- ### Server Listening Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Starts the WebSocket server and listens for incoming connections on the specified address. This is a convenience wrapper around `into_router` and `axum::serve`. For more control over routing, use `into_router` directly. ```APIDOC ## listen ### Description Start the WebSocket server. Convenience wrapper around [`into_router`] + `axum::serve`. If you need to add your own HTTP routes, use [`into_router`] instead. ### Method Signature `pub async fn listen(self, addr: &str) -> anyhow::Result<()>` ### Parameters - **addr** (string) - Required - The address to bind the server to (e.g., "0.0.0.0:8080"). ### Returns A `Result` indicating success or failure during server startup and operation. ``` -------------------------------- ### Router Missing State Example Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Illustrates a router that requires `AppState` and how it becomes `Router<()>` after providing the state. ```rust let router: Router = Router::new() .route("/", get(|_: State| async {})); let router: Router<()> = router.with_state(AppState {}); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, router).await.unwrap(); ``` -------------------------------- ### Chat Server Setup Source: https://docs.rs/tapaculo/latest/index.html Sets up a group messaging chat server with JWT authentication and an in-memory pub/sub backend. Supports up to 50 players and includes message history and rate limiting. ```rust use tapaculo::*; use std::time::Duration; Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .with_room_settings(RoomSettings { max_players: Some(50), store_message_history: true, max_history_messages: 200, ..Default::default() }) .with_limits(MessageLimits { max_messages_per_window: 10, window_duration: Duration::from_secs(1), ..Default::default() }) .on_message(|ctx, envelope| async move { ctx.broadcast(envelope.data).await.ok(); }) .listen("0.0.0.0:8081") .await ``` -------------------------------- ### Axum Router: Comprehensive Route Definitions Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html A comprehensive example showcasing various route definitions including static paths, captures, wildcards, and multiple methods for different endpoints. ```rust use axum::{Router, routing::{get, delete}, extract::Path}; let app = Router::new() .route("/", get(root)) .route("/users", get(list_users).post(create_user)) .route("/users/{id}", get(show_user)) .route("/api/{version}/users/{id}/action", delete(do_users_action)) .route("/assets/{*path}", get(serve_asset)); async fn root() {} async fn list_users() {} async fn create_user() {} async fn show_user(Path(id): Path) {} async fn do_users_action(Path((version, id)): Path<(String, u64)>) {} async fn serve_asset(Path(path): Path) {} ``` -------------------------------- ### Get Room Information Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Asynchronously retrieves optional information about the room, such as its capacity. ```rust pub async fn get_room_info(&self) -> Option ``` -------------------------------- ### Using `as_service` for Type Inference Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Provides an example of using `Router::as_service` to resolve type inference errors when calling methods from `tower::ServiceExt` on a `Router`. ```rust use axum::{ Router, routing::get, http::Request, body::Body, }; use tower::{Service, ServiceExt}; let mut router = Router::new().route("/", get(|| async {{}})); let request = Request::new(Body::empty()); let response = router.ready().await?.call(request).await?; ``` -------------------------------- ### Get Room Information Source: https://docs.rs/tapaculo/latest/src/tapaculo/room.rs.html Retrieves summary information about the room's current state. ```APIDOC ## Room::get_info ### Description Returns a `RoomInfo` struct containing summary details about the room's current state, including ID, member count, and member list. ### Signature ```rust pub fn get_info(&self) -> RoomInfo ``` ### Returns - `RoomInfo` - An object containing room details. ``` -------------------------------- ### Get Room Information Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Retrieves general information about the room, such as capacity. Returns None if the room is not found. ```rust pub async fn get_room_info(&self) -> Option { if let Some(room) = self.room_manager.get_room(&self.room_id).await { let room = room.read().await; Some(room.get_info()) } else { None } } ``` -------------------------------- ### Define Route with Wildcard Capture in Axum Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html This example shows how to define a route with a wildcard capture like `/{*key}` and extract the captured path segments using `axum::extract::Path`. ```rust use axum::{ Router, routing::get, extract::Path, }; let app: Router = Router::new().route("/{*key}", get(handler)); async fn handler(Path(path): Path) -> String { path } ``` -------------------------------- ### Axum Router Panic Example Without v0.7 Checks Disabled Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html This code demonstrates a panic scenario when defining routes with ':' or '*' without first calling `without_v07_checks`. ```rust use axum::{ routing::get, Router, }; // This panics... let app = Router::<()>::new() .route("/:colon", get(|| async {{}})); ``` -------------------------------- ### Server::new Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Server.html Creates a new Server instance with default configuration. ```APIDOC ## Server::new ### Description Creates a new server with default configuration. ### Method ``` pub fn new() -> Self ``` ``` -------------------------------- ### Axum Router: Handling Multiple HTTP Methods for a Single Route Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Demonstrates adding multiple handlers for the same route path, each associated with a different HTTP method (e.g., GET, POST, DELETE). ```rust use axum::{Router, routing::{get, delete}, extract::Path}; let app = Router::new().route( "/", get(get_root).post(post_root).delete(delete_root), ); async fn get_root() {} async fn post_root() {} async fn delete_root() {} ``` ```rust let app = Router::new() .route("/", get(get_root)) .route("/", post(post_root)) .route("/", delete(delete_root)); ``` -------------------------------- ### Server Initialization and Configuration Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Demonstrates how to create a new Tapaculo server and configure its various components using builder-style methods. ```APIDOC ## Server Initialization ### Description Creates a new Tapaculo server with default settings. ### Method `Server::new()` ## Server Configuration Methods ### Description These methods allow you to customize the server's behavior by configuring authentication, message handling, and other components. ### `with_auth` #### Description Configure the JWT authentication handler. #### Parameters - `auth` (JwtAuth) - The JWT authentication configuration. ### `with_pubsub` #### Description Configure the PubSub backend. #### Parameters - `ps` (impl PubSubBackend + 'static) - The PubSub backend implementation. ### `with_room_settings` #### Description Configure room settings. #### Parameters - `settings` (RoomSettings) - The room settings to apply. ### `with_limits` #### Description Configure rate limiting for messages. #### Parameters - `limits` (MessageLimits) - The message limits configuration. ### `on_message` #### Description Set the callback function to handle incoming messages. #### Parameters - `f` (Fn(Context, Envelope) -> Fut) - The message handler function. ### `on_message_typed` #### Description Set a typed message handler that automatically deserializes messages to a specific type. #### Parameters - `T` (DeserializeOwned + Send + 'static) - The type to deserialize messages into. - `f` (Fn(Context, Envelope) -> Fut) - The typed message handler function. ### `on_message_validate` #### Description Set a message validator that is called before processing messages. #### Parameters - `validator` (Fn(&Context, &Envelope) -> Result<(), String>) - The message validation function. ### `with_event_handler` #### Description Set the event handler for room lifecycle events. #### Parameters - `handler` (H: RoomEventHandler + 'static) - The room event handler implementation. ``` -------------------------------- ### Basic Router with Middleware Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Demonstrates creating a router with routes and applying HTTP tracing middleware to all of them. ```rust use axum::routing::get; use tower_http::trace::TraceLayer; let app = Router::new() .route("/foo", get(|| async {{}})) .route("/bar", get(|| async {{}})) .layer(TraceLayer::new_for_http()); ``` -------------------------------- ### get_user_metadata Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get metadata for a specific user. ```APIDOC ## get_user_metadata ### Description Get metadata for a specific user. ### Method `get_user_metadata` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **user_id** (&str) - Required - The ID of the user whose metadata to retrieve. ### Request Example ```json { "user_id": "some_user_id" } ``` ### Response #### Success Response (200) - **metadata** (Option) - Optional metadata for the specified user. #### Response Example ```json { "example": { "key": "value" } } ``` ``` -------------------------------- ### get_room_info Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get room capacity info. ```APIDOC ## get_room_info ### Description Get room capacity info. ### Method `get_room_info` ### Parameters None ### Response #### Success Response (200) - **room_info** (Option) - Optional room capacity information. #### Response Example ```json { "example": { "capacity": 10, "current_users": 5 } } ``` ``` -------------------------------- ### session_id Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get the current session ID. ```APIDOC ## session_id ### Description Get the current session ID. ### Method `session_id` ### Parameters None ### Response #### Success Response (200) - **session_id** (&str) - The ID of the current session. #### Response Example ```json { "example": "current_session_id" } ``` ``` -------------------------------- ### Sign and Verify JWTs with JwtAuth Source: https://docs.rs/tapaculo/latest/tapaculo/auth/index.html Demonstrates how to create a JwtAuth instance, sign access and refresh tokens, and verify an access token. Ensure you have a secret key for authentication. ```rust use tapaculo::auth::JwtAuth; let auth = JwtAuth::new("super-secret-key"); let access = auth.sign_access( "user42".into(), "room99".into(), "session1".into(), 3600 ).unwrap(); let refresh = auth.sign_refresh("user42".into(), 86400).unwrap(); let claims = auth.verify_access(&access).unwrap(); assert_eq!(claims.sub, "user42"); assert_eq!(claims.room, "room99"); ``` -------------------------------- ### room_id Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get the current room ID. ```APIDOC ## room_id ### Description Get the current room ID. ### Method `room_id` ### Parameters None ### Response #### Success Response (200) - **room_id** (&str) - The ID of the current room. #### Response Example ```json { "example": "current_room_id" } ``` ``` -------------------------------- ### get_message_history Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get message history for this room (if enabled). ```APIDOC ## get_message_history ### Description Get message history for this room (if enabled). ### Method `get_message_history` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **limit** (usize) - Required - The maximum number of messages to retrieve. ### Request Example ```json { "limit": 100 } ``` ### Response #### Success Response (200) - **history** (Vec) - A vector of stored messages. #### Response Example ```json { "example": [ { "user_id": "user1", "message": "Hello!", "timestamp": "2023-10-27T10:00:00Z" } ] } ``` ``` -------------------------------- ### get_room_members Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get all user IDs currently in this room. ```APIDOC ## get_room_members ### Description Get all user IDs currently in this room. ### Method `get_room_members` ### Parameters None ### Response #### Success Response (200) - **members** (Vec) - A vector of user IDs currently in the room. #### Response Example ```json { "example": ["user1", "user2"] } ``` ``` -------------------------------- ### user_id Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get the current user’s ID. ```APIDOC ## user_id ### Description Get the current user’s ID. ### Method `user_id` ### Parameters None ### Response #### Success Response (200) - **user_id** (&str) - The ID of the current user. #### Response Example ```json { "example": "current_user_id" } ``` ``` -------------------------------- ### get_custom_state Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Get a clone of the custom state (if set and type matches). ```APIDOC ## get_custom_state ### Description Get a clone of the custom state (if set and type matches). Note: Returns a clone to avoid holding the read lock. ### Method `get_custom_state` ### Parameters None ### Response #### Success Response (200) - **state** (Option) - An optional clone of the custom state if it exists and matches the requested type `T`. #### Response Example ```json { "example": "custom_state_value" } ``` ``` -------------------------------- ### Room::new Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.Room.html Creates a new Room instance with a given ID and settings. ```APIDOC ## `Room::new` ### Description Creates a new Room instance with a given ID and settings. ### Signature ```rust pub fn new(id: String, settings: RoomSettings) -> Self ``` ``` -------------------------------- ### Room::get_custom_state Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.Room.html Gets a reference to the custom state with type checking. ```APIDOC ## `Room::get_custom_state` ### Description Get a reference to the custom state with type checking. ### Signature ```rust pub fn get_custom_state(&self) -> Option<&T> ``` ``` -------------------------------- ### Server::with_room_settings Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Server.html Configures room settings for the server. ```APIDOC ## Server::with_room_settings ### Description Configure room settings. ### Method ``` pub fn with_room_settings(self, settings: RoomSettings) -> Self ``` ``` -------------------------------- ### Server::with_pubsub Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Server.html Configures the PubSub backend for the server. ```APIDOC ## Server::with_pubsub ### Description Configure the PubSub backend. ### Method ``` pub fn with_pubsub(self, ps: impl PubSubBackend + 'static) -> Self ``` ``` -------------------------------- ### Server New Method Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Initializes a new Tapaculo server with default settings. This includes a default JWT secret, in-memory PubSub, and basic room manager configuration. ```rust pub fn new() -> Self { Self { auth: JwtAuth::new("secret"), auth_configured: false, pubsub: Arc::new(crate::InMemoryPubSub::new()), room_manager: RoomManager::new(RoomSettings::default()), rate_limiter: None, on_message: Arc::new(|_, _| Box::pin(async {})), message_validator: None, event_handler: Arc::new(NoOpEventHandler), token_endpoint: false, token_ttl_secs: 3600, } } ``` -------------------------------- ### Get Current Session ID Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Retrieves the unique identifier for the current session. ```rust pub fn session_id(&self) -> &str ``` -------------------------------- ### Get Current Room ID Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Retrieves the unique identifier for the current room. ```rust pub fn room_id(&self) -> &str ``` -------------------------------- ### Get Current User ID Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Retrieves the unique identifier for the current user. ```rust pub fn user_id(&self) -> &str ``` -------------------------------- ### Create a New Router Instance Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Instantiates a new `Router`. Without any added routes, this router will return a 404 Not Found response for all incoming requests. ```rust pub fn new() -> Router ``` -------------------------------- ### Get Custom State Source: https://docs.rs/tapaculo/latest/src/tapaculo/room.rs.html Retrieves the custom state associated with the room, with type safety. ```APIDOC ## Room::get_custom_state ### Description Provides type-safe access to the custom state stored within the room. This is useful for application-specific data like game state. ### Signature ```rust pub fn get_custom_state(&self) -> Option<&T> ``` ### Type Parameters - **T**: The type of the custom state to retrieve. Must be `'static`. ### Returns - `Some(&T)` if the custom state exists and matches the requested type `T`. - `None` if no custom state is set or if it's not of type `T`. ``` -------------------------------- ### Redis PubSub Initialization Source: https://docs.rs/tapaculo/latest/index.html Initializes the Redis PubSub backend for production environments, connecting to a Redis instance at the specified URL. ```rust use tapaculo::RedisPubSub; let pubsub = RedisPubSub::new("redis://localhost:6379")?; ``` -------------------------------- ### From and FromRef Implementations for RoomSettings Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.RoomSettings.html Allows conversion into RoomSettings from itself (`from`) or from a reference to RoomSettings (`from_ref`). `from_ref` requires the type to be Clone. ```rust fn from(t: T) -> T ``` ```rust fn from_ref(input: &T) -> T ``` -------------------------------- ### RoomManager::new Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.RoomManager.html Creates a new instance of RoomManager with the specified default settings. ```APIDOC ## RoomManager::new ### Description Creates a new instance of RoomManager with the specified default settings. ### Signature ```rust pub fn new(default_settings: RoomSettings) -> Self ``` ``` -------------------------------- ### Get User Metadata Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Asynchronously retrieves the metadata for a specific user, if available and the type matches. ```rust pub async fn get_user_metadata(&self, user_id: &str) -> Option ``` -------------------------------- ### Convert Router to MakeService Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Use `into_make_service` to convert a router into a `MakeService`. This is the standard way to run a router in a production environment using `axum::serve`. ```rust use axum::{routing::get, Router}; let app = Router::new().route("/", get(|| async {{ "Hi!" }})); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); ``` -------------------------------- ### In-Memory PubSub Initialization Source: https://docs.rs/tapaculo/latest/index.html Initializes the in-memory PubSub backend for development purposes. An optional buffer size can be specified. ```rust use tapaculo::InMemoryPubSub; let pubsub = InMemoryPubSub::new(); // or with custom buffer size let pubsub = InMemoryPubSub::with_buffer(128); ``` -------------------------------- ### Room Initialization Source: https://docs.rs/tapaculo/latest/src/tapaculo/room.rs.html Creates a new `Room` instance with a unique ID and specified settings. Initializes player collection, message history, and timestamps. ```rust pub fn new(id: String, settings: RoomSettings) -> Self { let now = Instant::now(); Self { id, settings, players: HashMap::new(), message_history: VecDeque::new(), created_at: now, last_activity: now, custom_state: None, } } ``` -------------------------------- ### Get All Room Members Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Asynchronously retrieves a list of user IDs for all clients currently present in the room. ```rust pub async fn get_room_members(&self) -> Vec ``` -------------------------------- ### Error::cause Implementation (Deprecated) Source: https://docs.rs/tapaculo/latest/tapaculo/error/enum.PubSubError.html Deprecated method for getting the cause of the error. Use Error::source instead. ```rust fn cause(&self) -> Option<&dyn Error> ``` -------------------------------- ### Convert Router to MakeService with ConnectInfo Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Use `into_make_service_with_connect_info` to convert a router into a `MakeService` that captures connection information. This allows extracting client details like their remote address. ```rust use axum::{extract::ConnectInfo, routing::get, Router}; use std::net::SocketAddr; let app = Router::new().route("/", get(handler)); async fn handler(ConnectInfo(addr): ConnectInfo) -> String { format!("Hello {{addr}}") } let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app.into_make_service_with_connect_info::()).await.unwrap(); ``` -------------------------------- ### Get User Metadata Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Retrieves the metadata for a specific user ID in the room. Returns None if the user or room is not found. ```rust pub async fn get_user_metadata(&self, user_id: &str) -> Option { if let Some(room) = self.room_manager.get_room(&self.room_id).await { let room = room.read().await; room.players.get(user_id).cloned() } else { None } } ``` -------------------------------- ### Create In-Memory Pub/Sub with Custom Buffer Source: https://docs.rs/tapaculo/latest/src/tapaculo/pubsub/memory.rs.html Creates a new in-memory Pub/Sub backend with a specified buffer size for each topic. The buffer retains messages, overwriting the oldest when full. The minimum buffer size is 1. ```Rust pub fn with_buffer(buffer: usize) -> Self { Self { topics: Arc::new(Mutex::new(HashMap::new())), buffer: buffer.max(1), } } ``` -------------------------------- ### Get Room Members Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Retrieves a list of user IDs currently in the room. Returns an empty vector if the room is not found. ```rust pub async fn get_room_members(&self) -> Vec { if let Some(room) = self.room_manager.get_room(&self.room_id).await { let room = room.read().await; room.players.keys().cloned().collect() } else { Vec::new() } } ``` -------------------------------- ### TryFrom and TryInto Implementations for RoomSettings Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.RoomSettings.html Facilitates fallible conversions to and from RoomSettings. `try_from()` attempts conversion from `U` to `T`, returning a `Result`. `try_into()` performs the reverse conversion. ```rust type Error = Infallible ``` ```rust fn try_from(value: U) -> Result>::Error> ``` ```rust type Error = >::Error ``` ```rust fn try_into(self) -> Result>::Error> ``` -------------------------------- ### Error::description Implementation (Deprecated) Source: https://docs.rs/tapaculo/latest/tapaculo/error/enum.PubSubError.html Deprecated method for getting a string description of the error. Use Display or to_string() instead. ```rust fn description(&self) -> &str ``` -------------------------------- ### Axum Router with Fallback and Method Not Allowed Fallback Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Demonstrates setting up a router with a general fallback handler and a specific handler for method not allowed errors. This allows for graceful handling of unmatched routes and unsupported HTTP methods. ```rust use axum::response::IntoResponse; use axum::routing::get; use axum::Router; async fn hello_world() -> impl IntoResponse { "Hello, world!\n" } async fn default_fallback() -> impl IntoResponse { "Default fallback\n" } async fn handle_405() -> impl IntoResponse { "Method not allowed fallback" } #[tokio::main] async fn main() { let router = Router::new() .route("/", get(hello_world)) .fallback(default_fallback) .method_not_allowed_fallback(handle_405); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, router).await.unwrap(); } ``` -------------------------------- ### Get Message History Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Context.html Asynchronously retrieves a specified number of recent messages from the room's history, if message history is enabled. ```rust pub async fn get_message_history(&self, limit: usize) -> Vec ``` -------------------------------- ### Configure PubSub Backend Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Sets a custom PubSub backend for message broadcasting and subscription management. Supports any type implementing the PubSubBackend trait. ```rust pub fn with_pubsub(mut self, ps: impl PubSubBackend + 'static) -> Self { self.pubsub = Arc::new(ps); self } ``` -------------------------------- ### Axum Router Panic Example: Overlapping Routes Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html This code demonstrates a panic scenario in Axum when attempting to define the same route path twice. ```rust use axum::{routing::get, Router}; let app = Router::new() .route("/", get(|| async {{}})) .route("/", get(|| async {{}})); ``` -------------------------------- ### Server::into_router Source: https://docs.rs/tapaculo/latest/tapaculo/server/struct.Server.html Builds the axum `Router` for the server, allowing integration with other HTTP routes. ```APIDOC ## Server::into_router ### Description Build the axum `Router` for this server. Use this when you need to merge the WebSocket server with your own HTTP routes before serving. Also spawns the background room-cleanup task. ### Method ``` pub fn into_router(self) -> Router ``` ### Example ```rust use tapaculo::* use axum::{routing::get, Router}; #[tokio::main] async fn main() -> anyhow::Result<()> { let ws_router = Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .into_router(); let app = ws_router.route("/healthz", get(|| async { "ok" })); let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; axum::serve(listener, app).await?; Ok(()) } ``` ``` -------------------------------- ### Routing to Arbitrary Services with Axum Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Demonstrates routing requests to custom services using `any_service` and `route_service`. Suitable for services with different response body types or direct routing. ```rust use axum:: Router, body::Body, routing::{any_service, get_service}, extract::Request, http::StatusCode, error_handling::HandleErrorLayer, }; use tower_http::services::ServeFile; use http::Response; use std::{convert::Infallible, io}; use tower::service_fn; let app = Router::new() .route( // Any request to `/` goes to a service "/", // Services whose response body is not `axum::body::BoxBody` // can be wrapped in `axum::routing::any_service` (or one of the other routing filters) // to have the response body mapped any_service(service_fn(|_: Request| async { let res = Response::new(Body::from("Hi from `GET /`")); Ok::<_, Infallible>(res) })) ) .route_service( "/foo", // This service's response body is `axum::body::BoxBody` so // it can be routed to directly. service_fn(|req: Request| async move { let body = Body::from(format!("Hi from `{} /foo`", req.method())); let res = Response::new(body); Ok::<_, Infallible>(res) }) ) .route_service( // GET `/static/Cargo.toml` goes to a service from tower-http "/static/Cargo.toml", ServeFile::new("Cargo.toml"), ); ``` -------------------------------- ### Incorrect Return Type for `routes` Function Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Shows an example where returning `Router` from a function that calls `with_state` leads to type errors when calling `into_make_service`. ```rust fn routes(state: AppState) -> Router { Router::new() .route("/", get(|_: State| async {})) .with_state(state) } let app = routes(AppState {}); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); ``` -------------------------------- ### into_make_service_with_connect_info Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Converts the router into a `MakeService` that stores connection information in request extensions. This allows extracting details like the client's remote address. ```APIDOC ## pub fn into_make_service_with_connect_info( self, ) -> IntoMakeServiceWithConnectInfo Converts the `Router` into a `MakeService` that captures connection information. This is useful for accessing client details like IP addresses within your handlers. ### Example with SocketAddr ```rust use axum::{extract::ConnectInfo, routing::get, Router}; use std::net::SocketAddr; let app = Router::new().route("/", get(handler)); async fn handler(ConnectInfo(addr): ConnectInfo) -> String { format!("Hello {{addr}}") } // let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); // axum::serve(listener, app.into_make_service_with_connect_info::()).await.unwrap(); ``` ### Example with Custom ConnectInfo ```rust use axum::{extract::connect_info::{ConnectInfo, Connected}, routing::get, serve::IncomingStream, Router}; use tokio::net::TcpListener; let app = Router::new().route("/", get(handler)); async fn handler(ConnectInfo(my_connect_info): ConnectInfo) -> String { format!("Hello {{my_connect_info:?}}") } #[derive(Clone, Debug)] struct MyConnectInfo { // ... fields for connection info } impl Connected> for MyConnectInfo { fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self { // Implementation to extract connection info MyConnectInfo { /* ... */ } } } // let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); // axum::serve(listener, app.into_make_service_with_connect_info::()).await.unwrap(); ``` ``` -------------------------------- ### try_from Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Performs the conversion. Read more ```APIDOC ## try_from ### Description Performs the conversion. ### Signature `fn try_from(value: U) -> Result>::Error>` ### Parameters - `value` (`U`): The value to convert from. ### Associated Type - `Error = Infallible`: The type returned in the event of a conversion error. ### Constraints - `U`: Must implement `Into`. ``` -------------------------------- ### Create New In-Memory Pub/Sub Source: https://docs.rs/tapaculo/latest/src/tapaculo/pubsub/memory.rs.html Initializes a new in-memory Pub/Sub backend with a default per-topic buffer size of 64 messages. This is suitable for local, single-process messaging. ```Rust pub fn new() -> Self { Self::with_buffer(64) } ``` -------------------------------- ### Get Message History Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Fetches a limited number of recent messages from the room's history. Returns an empty vector if the room is not found or history is disabled. ```rust pub async fn get_message_history(&self, limit: usize) -> Vec { if let Some(room) = self.room_manager.get_room(&self.room_id).await { let room = room.read().await; let mut msgs: Vec = room .message_history .iter() .rev() .take(limit) .cloned() .collect(); msgs.reverse(); msgs } else { Vec::new() } } ``` -------------------------------- ### Get Custom State Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.Room.html Retrieves a reference to the custom state associated with the room, performing type checking. Use this to access application-specific data stored in the room. ```rust pub fn get_custom_state(&self) -> Option<&T> ``` -------------------------------- ### Clone Implementation for RoomSettings Source: https://docs.rs/tapaculo/latest/tapaculo/room/struct.RoomSettings.html Provides methods to duplicate RoomSettings values. Use `clone()` for a simple copy or `clone_from()` for in-place assignment. ```rust fn clone(&self) -> RoomSettings ``` ```rust fn clone_from(&mut self, source: &Self) ``` -------------------------------- ### Disable v0.7 Route Matching Checks in Axum Router Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Use `without_v07_checks` to allow route paths starting with ':' or '*'. Calling this method prevents panics when defining such routes. ```rust use axum::{ routing::get, Router, }; let app = Router::<()>::new() .without_v07_checks() .route("/:colon", get(|| async {{}})) .route("/*asterisk", get(|| async {{}})); // Our app now accepts // - GET /:colon // - GET /*asterisk ``` -------------------------------- ### Get Custom Room State Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Retrieves a clone of the custom state associated with the room, if it matches the requested type. Returns None if the room is not found or the type does not match. ```rust pub async fn get_custom_state(&self) -> Option { if let Some(room) = self.room_manager.get_room(&self.room_id).await { let room = room.read().await; room.get_custom_state::().cloned() } else { None } } ``` -------------------------------- ### into_make_service Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Converts this router into a `MakeService`. A `MakeService` is a `Service` whose response is another service, typically used for creating a server that can handle multiple connections. ```APIDOC ## pub fn into_make_service(self) -> IntoMakeService Converts the `Router` into a `MakeService`. This is the standard way to turn a `Router` into something that can be served by a TCP listener. ### Example ```rust use axum::{routing::get, Router}; let app = Router::new().route("/", get(|| async {{ "Hi!" }})); // This can then be used with `axum::serve` // let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); // axum::serve(listener, app).await.unwrap(); ``` ``` -------------------------------- ### Returning Routers from Functions (Without State) Source: https://docs.rs/tapaculo/latest/tapaculo/struct.Router.html Illustrates the recommended way to define routes in a function and apply state later. This avoids issues when merging or nesting routers. ```rust use axum::{Router, routing::get, extract::State}; #[derive(Clone)] struct AppState {} // Don't call `Router::with_state` here fn routes() -> Router { Router::new() .route("/", get(|_: State| async {})) } // Instead do it before you run the server let routes = routes().with_state(AppState {}); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, routes).await.unwrap(); ``` -------------------------------- ### Build Axum Router for WebSocket Server Source: https://docs.rs/tapaculo/latest/src/tapaculo/server.rs.html Use this to merge the WebSocket server with custom HTTP routes. It also spawns a background task for cleaning up empty rooms. Ensure authentication is configured using `.with_auth()` before deployment to avoid using the default secret key. ```rust use tapaculo::* use axum::{ routing::get, Router, }; #[tokio::main] async fn main() -> anyhow::Result<()> { let ws_router = Server::new() .with_auth(JwtAuth::new("secret")) .with_pubsub(InMemoryPubSub::new()) .into_router(); let app = ws_router.route("/healthz", get(|| async { "ok" })); let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await?; axum::serve(listener, app).await?; Ok(()) } ```