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; #[derive(Serialize)] enum DownMsg { Landing(landing::DownMsg), } /// 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 = DownMsg::Landing(landing::DownMsg::TimeUpdate(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 = std::env::var("EXAMPLE_ELM_APP_PORT") .unwrap_or("8080".to_string()) .parse() .unwrap(); 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 }