App state in Actix-web

Understanding App State

This Actix-Web Rust server handles messages and tracks server status. It shares state using Mutex-protected HashMap and String. Clients can GET or POST a message and GET a list of servers. State is initialized in main and injected into request handlers for simple thread-safe access.

use actix_web::{App, HttpResponse, HttpServer, web};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Mutex;

#[derive(Serialize, Deserialize)]
struct Message {
    content: String,
}

#[derive(Serialize, Clone)]
struct Server {
    name: String,
    status: String,
}

// shared application state
struct AppState {
    // Use a regular Mutex for simplicity
    servers: Mutex<HashMap<String, Server>>,
    // For a simple version, we'll just keep the last message
    last_message: Mutex<String>,
}

// Handle GET requests to /message
async fn get_message(data: web::Data<AppState>) -> HttpResponse {
    let message = data.last_message.lock().unwrap().clone();
    HttpResponse::Ok().json(Message { content: message })
}

// Handle POST requests to /message
async fn post_message(msg: web::Json<Message>, data: web::Data<AppState>) -> HttpResponse {
    // Store the message
    let mut last_message = data.last_message.lock().unwrap();
    *last_message = msg.content.clone();

    // Return success response
    HttpResponse::Ok().body("Message received")
}

// List all servers
async fn list_servers(data: web::Data<AppState>) -> HttpResponse {
    let servers = data.servers.lock().unwrap();
    let server_list: Vec<_> = servers.values().cloned().collect();
    HttpResponse::Ok().json(server_list)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    println!("Starting simple message server...");

    // Initialize our state
    let mut server_map = HashMap::new();
    server_map.insert(
        "server1".to_string(),
        Server {
            name: "Demo Server".to_string(),
            status: "Online".to_string(),
        },
    );

    let state = web::Data::new(AppState {
        servers: Mutex::new(server_map),
        last_message: Mutex::new("No messages yet".to_string()),
    });

    HttpServer::new(move || {
        App::new()
            .app_data(state.clone())
            .route("/message", web::get().to(get_message))
            .route("/message", web::post().to(post_message))
            .route("/servers", web::get().to(list_servers))
    })
    .bind("127.0.0.1:8000")?
    .run()
    .await
}