use actix::prelude::*; use actix_files::Files; use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; use actix_web_actors::ws; use log::info; use serde::{Deserialize, Serialize}; use std::{fs, time::Duration}; use chrono::Local; mod landing; /// Greeting API structures #[derive(Serialize, Deserialize)] struct GreetingRequest { name: String, } #[derive(Serialize)] struct GreetingResponse { message: String, } #[derive(Serialize)] enum ToFrontend { Landing(landing::Landing) } /// WebSocket actor struct MyWebSocket; impl Actor for MyWebSocket { type Context = ws::WebsocketContext; fn started(&mut self, ctx: &mut Self::Context) { info!("WebSocket actor started"); ctx.run_interval(Duration::from_secs(1), |_, ctx| { let current_time = Local::now().format("%H:%M:%S").to_string(); let message = ToFrontend::Landing(landing::Landing { time: current_time }); if let Ok(json_message) = serde_json::to_string(&message) { ctx.text(json_message); } }); } } impl StreamHandler> for MyWebSocket { fn handle( &mut self, msg: Result, ctx: &mut ws::WebsocketContext, ) { if let Ok(ws::Message::Ping(msg)) = msg { ctx.pong(&msg); } } } async fn websocket_handler(req: HttpRequest, stream: web::Payload) -> Result { ws::start(MyWebSocket {}, &req, stream) } #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); let address = "127.0.0.1"; let port = 8080; info!("Starting server at http://{}:{}", address, port); HttpServer::new(|| { App::new() .route("/ws/", web::get().to(websocket_handler)) // WebSocket endpoint .service(Files::new("/assets", "./public/assets")) .service(Files::new("/", "./public").index_file("index.html")) // Serve frontend .default_service(web::route().to(|| async { let index_html = fs::read_to_string("./public/index.html") .unwrap_or_else(|_| "404 Not Found".to_string()); HttpResponse::Ok() .content_type("text/html; charset=utf-8") .body(index_html) })) }) .bind((address, port))? .run() .await }