diff --git a/src/communities/community.rs b/src/communities/community.rs index 0429502..c6571e8 100644 --- a/src/communities/community.rs +++ b/src/communities/community.rs @@ -76,6 +76,23 @@ impl Community { c } + pub async fn to_json(&self) -> JsonValue { + let mut json = JsonValue::new_object(); + json["name"] = self.name.clone().into(); + json["owner_id"] = self.owner_id.to_string().into(); + json["members"] = self + .members + .clone() + .iter() + .map(|f| f.to_string()) + .collect::>() + .into(); + json["private_key"] = self.private_key.as_bytes().to_vec().into(); + json["public_key"] = self.public_key.as_bytes().to_vec().into(); + json["connections"] = self.connections.read().await.clone().len().into(); + json + } + pub fn add_member(&mut self, member_id: Uuid) { self.members.push(member_id); } diff --git a/src/gui/app_state.rs b/src/gui/app_state.rs index 8f4e380..b919d86 100644 --- a/src/gui/app_state.rs +++ b/src/gui/app_state.rs @@ -1,5 +1,7 @@ use std::collections::VecDeque; +use json::{JsonValue, object}; + #[derive(Clone)] pub struct AppState { pub logs: VecDeque, @@ -67,4 +69,32 @@ impl AppState { self.net_down.remove(0); } } + pub fn to_json(&self) -> JsonValue { + let json = object! { + "cpu" => self.cpu + .iter() + .map(|(_, y)| *y) + .collect::>(), + "ram" => self.ram + .iter() + .map(|(_, y)| *y) + .collect::>(), + "ping" => self + .ping + .iter() + .map(|(_, y)| *y) + .collect::>(), + "net_up" => self + .net_up + .iter() + .map(|(_, y)| *y) + .collect::>(), + "net_down" => self + .net_down + .iter() + .map(|(_, y)| *y) + .collect::>(), + }; + json + } } diff --git a/src/server/api.rs b/src/server/api.rs new file mode 100644 index 0000000..bb53a1b --- /dev/null +++ b/src/server/api.rs @@ -0,0 +1,76 @@ +use axum::http::HeaderValue; +use http_body_util::Full; +use hyper::body::Bytes; +use hyper::{HeaderMap, Response as HttpResponse, StatusCode}; +use json::JsonValue; + +use crate::util::config_util::CONFIG; +use crate::{APP_STATE, communities::community_manager, users::user_manager}; + +pub async fn handle( + path: &str, + is_local: &bool, + headers: HeaderMap, +) -> HttpResponse> { + if !is_local { + return HttpResponse::builder() + .status(StatusCode::FORBIDDEN) + .body(Full::new(Bytes::from("403 Forbidden".to_string()))) + .unwrap(); + } + let mut path_parts = path.split("/"); + let (status, content, body_text) = match path_parts.nth(1).unwrap() { + "app_state" => (StatusCode::OK, "application/json", { + let json = APP_STATE.lock().unwrap().clone(); + json.to_json().to_string() + }), + "users" => (StatusCode::OK, "application/json", { + if path_parts.nth(2).is_some() { + if path_parts.nth(2).unwrap() == "add" { + "{}".to_string() + } else if path_parts.nth(2).unwrap() == "remove" { + "{}".to_string() + } else if path_parts.nth(2).unwrap() == "get" { + let users = user_manager::get_users(); + let mut json = JsonValue::new_array(); + for user in users { + let _ = json.push(user.to_json()); + } + json.to_string() + } else { + "{}".to_string() + } + } else { + let users = user_manager::get_users(); + let mut json = JsonValue::new_array(); + for user in users { + let _ = json.push(user.to_json()); + } + json.to_string() + } + }), + "communities" => (StatusCode::OK, "application/json", { + let communities = community_manager::get_communities().await; + let mut json = JsonValue::new_array(); + for community in communities { + let _ = json.push(community.to_json().await); + } + json.to_string() + }), + "settings" => (StatusCode::OK, "application/json", { + CONFIG.lock().unwrap().config.to_string() + }), + + _ => ( + StatusCode::NOT_FOUND, + "application/json", + "404 Not Found".to_string(), + ), + }; + let body = Full::new(Bytes::from(body_text.to_string())); + HttpResponse::builder() + .header("Content-Type", content) + .status(status) + .body(body) + .unwrap() +} diff --git a/src/server/mod.rs b/src/server/mod.rs index 538dc53..e19c91e 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,2 +1,3 @@ +pub mod api; pub mod server; pub mod socket; diff --git a/src/server/server.rs b/src/server/server.rs index 38827c8..2791c01 100644 --- a/src/server/server.rs +++ b/src/server/server.rs @@ -1,3 +1,7 @@ +use crate::gui::log_panel::log_message; +use crate::server::api; +use crate::server::socket::handle; +use crate::util::file_util::load_file_buf; use base64::Engine; use base64::engine::general_purpose::STANDARD; use futures::{StreamExt, TryFutureExt}; @@ -9,7 +13,6 @@ use hyper::{ }; use hyper_util::rt::tokio::TokioIo; use hyper_util::service::TowerToHyperService; -// FIX: Add necessary rustls imports for builder in minimal-feature environment use rustls::ServerConfig; use rustls::pki_types::{CertificateDer, PrivateKeyDer}; use sha1::{Digest, Sha1}; @@ -20,15 +23,11 @@ use std::net::{IpAddr, SocketAddr}; use std::result::Result::Ok; use std::sync::Arc; use std::{future::Future, pin::Pin, time::Duration}; -use tokio::net::{TcpListener, TcpStream}; +use tokio::net::TcpListener; +use tokio_rustls::TlsAcceptor; use tokio_tungstenite::WebSocketStream; use tower::Service; -use crate::gui::log_panel::log_message; -use crate::server::socket::handle; -use crate::util::file_util::load_file_buf; -use tokio_rustls::TlsAcceptor; - #[derive(Clone)] struct HttpService { peer_addr: SocketAddr, @@ -101,7 +100,6 @@ impl Service> for HttpService { Ok(response) } else { log_message("No Sec-WebSocket-Key found in request headers"); - // Handle error: No Sec-WebSocket-Key let response = HttpResponse::builder() .status(StatusCode::BAD_REQUEST) .body(Full::new(Bytes::from("Missing Sec-WebSocket-Key"))) @@ -109,18 +107,31 @@ impl Service> for HttpService { Ok(response) } } else { - let (status, body_text) = match path.as_str() { - "/" => ( - StatusCode::OK, - "Server: Try connecting to WebSocket at ws[s]://:/ws or check /status.", - ), - "/status" => (StatusCode::OK, "Server Status: Online"), - "/index" => (StatusCode::OK, include_str!("../../static/web/index.html")), - _ => (StatusCode::NOT_FOUND, "404 Not Found"), - }; - let body = Full::new(Bytes::from(body_text.to_string())); - let response = HttpResponse::builder().status(status).body(body).unwrap(); - Ok(response) + if path.starts_with("/api") { + Ok(api::handle(&path, &is_local, headers).await) + } else { + let (status, content, body_text) = match path.as_str() { + "/" => ( + StatusCode::OK, + "text/plain", + "Server: Try connecting to WebSocket at ws[s]://:/ws or check /status.", + ), + "/status" => (StatusCode::OK, "text/plain", "Server Status: Online"), + "/index" => ( + StatusCode::OK, + "text/html", + include_str!("../../static/web/index.html"), + ), + _ => (StatusCode::NOT_FOUND, "text/plain", "404 Not Found"), + }; + let body = Full::new(Bytes::from(body_text.to_string())); + let response = HttpResponse::builder() + .header("Content-Type", content) + .status(status) + .body(body) + .unwrap(); + Ok(response) + } } }; diff --git a/src/util/chat_files.rs b/src/util/chat_files.rs index b400c7b..f7fd2f1 100644 --- a/src/util/chat_files.rs +++ b/src/util/chat_files.rs @@ -84,7 +84,6 @@ pub fn add_message( } let file_name = format!("msgs_{}.json", chunk_index); - log_message(format!("Saving message to {}/{}", user_dir, file_name)); save_file(&user_dir, &file_name, &message_chunk.dump()); } pub fn change_message_state(