use actix_web::{web, App, HttpServer, HttpResponse}; use askama::Template; use chrono::{Utc, Datelike}; use tokio::time::{self, Duration}; use actix_files as fs; use serde::Deserialize; use crate::config::Config; use crate::ts3::{get_ts3_connection, create_channel, get_client_info}; use crate::rrd::{update_rrd_stats, generate_graphs}; mod config; mod ts3; mod rrd; #[derive(Deserialize)] struct ChannelData { channel_name: String, channel_topic: String, channel_password: String, } #[derive(Template)] #[template(path = "create.html")] struct CreateTemplate<'a> { ts3_server: &'a str, ts3_server_port: u16, client_ip: &'a str, client_uuid: &'a str, now: &'a str, year: i32, flash_message: &'a str, // Zawsze string! pusty lub z komunikatem. } #[derive(Template)] #[template(path = "stats.html")] struct StatsTemplate<'a> { graphs: &'a [Graph], last_update: &'a str, server_name: &'a str, now: &'a str, year: i32, } struct Graph { file: String, title: String, } async fn create_handler(data: web::Json) -> HttpResponse { let config = Config::load(); let mut stream = match get_ts3_connection(&config) { Ok(s) => s, Err(e) => { return HttpResponse::InternalServerError().body(format!("Błąd połączenia: {}", e)); } }; let client_info = get_client_info(&mut stream, "127.0.0.1"); let (client_uuid, client_dbid, client_clid) = match &client_info { Some(info) => (info.uid.as_str(), info.dbid, info.clid), None => ("Brak UUID", 0, 0), }; let result = create_channel( &mut stream, &data.channel_name, &data.channel_topic, &data.channel_password, client_dbid, client_clid, ); let flash_message = match result { Ok(_) => "Kanał utworzony pomyślnie", Err(_e) => "Błąd tworzenia kanału", }; let now_dt = Utc::now(); let now_str = now_dt.format("%Y-%m-%d %H:%M:%S").to_string(); let year = now_dt.year(); let template = CreateTemplate { ts3_server: &config.ts3_server, ts3_server_port: config.ts3_query_port, client_ip: "127.0.0.1", client_uuid, now: &now_str, year, flash_message, }; HttpResponse::Ok().content_type("text/html").body(template.render().unwrap()) } async fn stats_handler() -> HttpResponse { let config = Config::load(); generate_graphs(&config); let graphs = [ Graph { file: "hour.gif".to_string(), title: "Ostatnie 12 godzin".to_string() }, Graph { file: "day.gif".to_string(), title: "Ostatnie 24 godziny".to_string() }, Graph { file: "72h.gif".to_string(), title: "Ostatnie 72 godziny".to_string() }, Graph { file: "week.gif".to_string(), title: "Ostatni tydzień".to_string() }, ]; let now_dt = Utc::now(); let now_str = now_dt.format("%Y-%m-%d %H:%M:%S").to_string(); let year = now_dt.year(); let last_update = &now_str; let template = StatsTemplate { graphs: &graphs, last_update, server_name: "linuxiarz.pl", now: &now_str, year, }; HttpResponse::Ok().content_type("text/html").body(template.render().unwrap()) } #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); let config = Config::load(); let config_clone = config.clone(); tokio::spawn(async move { let mut interval = time::interval(Duration::from_secs(config_clone.rrd_update_interval)); loop { interval.tick().await; update_rrd_stats(&config_clone); generate_graphs(&config_clone); } }); HttpServer::new(|| { App::new() .service(fs::Files::new("/static", "./static").show_files_listing()) .route("/create", web::post().to(create_handler)) .route("/stats", web::get().to(stats_handler)) }) .bind(("0.0.0.0", 5000))? .run() .await }