use actix::prelude::*; use actix_files::Files; use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder}; use actix_web_actors::ws; use chrono::Local; use log::info; use serde::{Deserialize, Serialize}; use std::{fs, time::Duration}; mod landing; #[derive(Serialize, Debug)] pub enum DownMsg { Landing(landing::DownMsg), } #[derive(Deserialize, Debug)] enum UpMsg { Landing(landing::UpMsg), } pub 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, ) { match msg { Ok(ws::Message::Text(text)) => { if let Ok(up_msg) = serde_json::from_str::(&text) { match up_msg { UpMsg::Landing(msg) => landing::msg_handler(msg, self, ctx), } } } Ok(ws::Message::Ping(msg)) => { ctx.pong(&msg); } _ => {} } } } impl MyWebSocket { fn send_down_msg(&self, down_msg: DownMsg, ctx: &mut ws::WebsocketContext) { if let Ok(serialized_msg) = serde_json::to_string(&down_msg) { ctx.text(serialized_msg); } else { log::error!("Failed to serialize DownMsg {:?}", down_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 }