example-spa-elm-app/backend/src/main.rs

106 lines
3.1 KiB
Rust
Raw Normal View History

use actix::prelude::*;
2025-01-01 01:50:26 +00:00
use actix_files::Files;
use actix_web::{web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder};
2025-01-01 01:50:26 +00:00
use actix_web_actors::ws;
2025-01-07 13:54:07 +00:00
use chrono::Local;
use log::info;
2025-01-01 01:50:26 +00:00
use serde::{Deserialize, Serialize};
use std::{fs, time::Duration};
mod landing;
2025-01-07 13:54:07 +00:00
#[derive(Serialize, Debug)]
pub enum DownMsg {
Landing(landing::DownMsg),
2025-01-01 01:50:26 +00:00
}
2025-01-07 13:54:07 +00:00
#[derive(Deserialize, Debug)]
2025-01-06 06:23:48 +00:00
enum UpMsg {
Landing(landing::UpMsg),
}
2025-01-07 13:54:07 +00:00
pub struct MyWebSocket;
2025-01-01 01:50:26 +00:00
impl Actor for MyWebSocket {
type Context = ws::WebsocketContext<Self>;
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);
}
2025-01-01 01:50:26 +00:00
});
}
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for MyWebSocket {
fn handle(
&mut self,
msg: Result<ws::Message, ws::ProtocolError>,
ctx: &mut ws::WebsocketContext<Self>,
) {
2025-01-06 06:23:48 +00:00
match msg {
Ok(ws::Message::Text(text)) => {
if let Ok(up_msg) = serde_json::from_str::<UpMsg>(&text) {
match up_msg {
2025-01-07 13:54:07 +00:00
UpMsg::Landing(msg) =>
landing::msg_handler(msg, self, ctx),
2025-01-06 06:23:48 +00:00
}
}
}
Ok(ws::Message::Ping(msg)) => {
ctx.pong(&msg);
}
_ => {}
2025-01-01 01:50:26 +00:00
}
}
}
2025-01-07 13:54:07 +00:00
impl MyWebSocket {
fn send_down_msg(&self, down_msg: DownMsg, ctx: &mut ws::WebsocketContext<Self>) {
if let Ok(serialized_msg) = serde_json::to_string(&down_msg) {
ctx.text(serialized_msg);
} else {
log::error!("Failed to serialize DownMsg {:?}", down_msg);
}
}
}
2025-01-06 06:23:48 +00:00
2025-01-01 01:50:26 +00:00
async fn websocket_handler(req: HttpRequest, stream: web::Payload) -> Result<HttpResponse, Error> {
ws::start(MyWebSocket {}, &req, stream)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
let address = "127.0.0.1";
2025-01-03 23:20:22 +00:00
let port = std::env::var("EXAMPLE_ELM_APP_PORT")
.unwrap_or("8080".to_string())
.parse()
.unwrap();
2025-01-01 01:50:26 +00:00
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
}