/ client / src / gui.rs
gui.rs
  1  use crate::encrypt_data;
  2  use crate::receive_and_fetch_messages;
  3  use crate::send_encrypted_message;
  4  use crate::pad_message;
  5  use rocket::{get, post, routes, serde::json::Json};
  6  use rocket::fs::NamedFile;
  7  use rocket::tokio;
  8  use rocket::fs::FileServer;
  9  use serde::{Deserialize, Serialize};
 10  use std::sync::{Arc, Mutex};
 11  use std::time::Duration;
 12  use std::path::PathBuf;
 13  
 14  #[derive(Clone)]
 15  pub struct MessagingApp {
 16      username: String,
 17      messages: Arc<Mutex<Vec<String>>>,
 18      shared_hybrid_secret: Arc<String>,
 19      shared_room_id: Arc<String>,
 20      shared_url: Arc<String>,
 21  }
 22  
 23  #[derive(Serialize, Deserialize)]
 24  struct MessageInput {
 25      message: String,
 26  }
 27  
 28  impl MessagingApp {
 29      pub fn new(
 30          username: String,
 31          shared_hybrid_secret: Arc<String>,
 32          shared_room_id: Arc<Mutex<String>>,
 33          shared_url: Arc<Mutex<String>>,
 34      ) -> Self {
 35          let messages = Arc::new(Mutex::new(vec![]));
 36          let messages_clone = Arc::clone(&messages);
 37          let shared_hybrid_secret_clone = Arc::clone(&shared_hybrid_secret);
 38          let shared_room_id_clone = Arc::clone(&shared_room_id);
 39          let shared_url_clone = Arc::clone(&shared_url);
 40  
 41          let room_id = Arc::new(shared_room_id_clone.lock().unwrap_or_else(|_| panic!("Failed to lock room_id")).clone());
 42          let url = Arc::new(shared_url_clone.lock().unwrap_or_else(|_| panic!("Failed to lock url")).clone());
 43  
 44          tokio::spawn(async move {
 45              loop {
 46                  let room_id_str = shared_room_id_clone.lock().unwrap_or_else(|_| panic!("Failed to lock room_id")).clone();
 47                  let url_str = shared_url_clone.lock().unwrap_or_else(|_| panic!("Failed to lock url")).clone();
 48  
 49                  match receive_and_fetch_messages(
 50                      &room_id_str,
 51                      &shared_hybrid_secret_clone,
 52                      &url_str,
 53                      true,
 54                  ) {
 55                      Ok(new_messages) => {
 56                          let mut msgs = messages_clone.lock().unwrap_or_else(|_| panic!("Failed to lock messages"));
 57                          msgs.clear();
 58                          msgs.extend(new_messages);
 59                      }
 60                      Err(e) => {
 61                          eprintln!("Error fetching messages: {}", e);
 62                      }
 63                  }
 64                  tokio::time::sleep(Duration::from_secs(10)).await;
 65              }
 66          });
 67  
 68          MessagingApp {
 69              username,
 70              messages,
 71              shared_hybrid_secret,
 72              shared_room_id: room_id,
 73              shared_url: url,
 74          }
 75      }
 76  }
 77  
 78  #[get("/messages")]
 79  async fn get_messages(app: &rocket::State<MessagingApp>) -> Json<Vec<String>> {
 80      let result = fetch_and_update_messages(&app).await;
 81      
 82      match result {
 83          Ok(msgs) => Json(msgs),
 84          Err(e) => {
 85              eprintln!("Error fetching messages: {}", e);
 86              
 87              // Return current messages if fetching fails
 88              let msgs = app.messages.lock().unwrap_or_else(|_| panic!("Failed to lock messages"));
 89              Json(msgs.clone())
 90          }
 91      }
 92  }
 93  
 94  async fn fetch_and_update_messages(app: &rocket::State<MessagingApp>) -> Result<Vec<String>, String> {
 95      let room_id_str = app.shared_room_id.clone();
 96      let url_str = app.shared_url.clone();
 97      
 98      let new_messages = tokio::task::block_in_place(move || {
 99          receive_and_fetch_messages(
100              &room_id_str,
101              &app.shared_hybrid_secret,
102              &url_str,
103              true,
104          )
105      }).map_err(|e| format!("Error fetching messages: {}", e))?;
106  
107      // Update the in-memory message storage
108      let mut msgs = app.messages.lock().unwrap_or_else(|_| panic!("Failed to lock messages"));
109      msgs.clear();
110      msgs.extend(new_messages.clone());
111  
112      Ok(new_messages)
113  }
114  
115  #[post("/send", data = "<input>")]
116  async fn post_message(
117      input: Json<MessageInput>,
118      app: &rocket::State<MessagingApp>
119  ) -> Result<&'static str, rocket::http::Status> {
120      // Create the formatted message once
121      let formatted_message = format!("<strong>{}</strong>: {}", app.username, input.message);
122      let padded_message = pad_message(&formatted_message, 2048);
123  
124      let result = tokio::task::block_in_place(|| {
125          // Encrypt the message
126          let encrypted = encrypt_data(&padded_message, &app.shared_hybrid_secret)
127              .map_err(|e| {
128                  eprintln!("Encryption error: {}", e);
129                  rocket::http::Status::InternalServerError
130              })?;
131          
132          // Send the encrypted message
133          send_encrypted_message(&encrypted, &app.shared_room_id, &app.shared_url)
134              .map_err(|e| {
135                  eprintln!("Error sending message: {}", e);
136                  rocket::http::Status::InternalServerError
137              })
138      });
139  
140      match result {
141          Ok(_) => {
142              {
143                  let mut msgs = app.messages.lock().unwrap_or_else(|_| panic!("Failed to lock messages"));
144                  msgs.push(formatted_message);
145              }
146              Ok("Message sent")
147          }
148          Err(e) => Err(e),
149      }
150  }
151  
152  #[get("/")]
153  async fn serve_webpage() -> Option<NamedFile> {
154      NamedFile::open(PathBuf::from("static/index.html")).await.ok()
155  }
156  
157  pub fn create_rocket(app: MessagingApp) -> rocket::Rocket<rocket::Build> {
158      rocket::build()
159          .manage(app)
160          .mount("/", routes![get_messages, post_message, serve_webpage])
161          .mount("/static", FileServer::from("static"))
162  }