use std::{ collections::HashMap, net::SocketAddr, sync::{ atomic::{AtomicBool, Ordering}, Arc, }, }; use anyhow::Error; use futures_util::{SinkExt, StreamExt}; use giterated_models::{messages::error::ConnectionError, model::instance::Instance}; use rsa::RsaPublicKey; use serde::Serialize; use serde_json::Value; use tokio::{ net::TcpStream, sync::{Mutex, RwLock}, }; use tokio_tungstenite::{tungstenite::Message, WebSocketStream}; use crate::{ authentication::AuthenticationTokenGranter, backend::{RepositoryBackend, UserBackend}, message::NetworkMessage, }; use super::{ authentication::authentication_handle, handshake::handshake_handle, repository::repository_handle, user::user_handle, Connections, }; pub async fn connection_wrapper( socket: WebSocketStream, connections: Arc>, repository_backend: Arc>, user_backend: Arc>, auth_granter: Arc>, addr: SocketAddr, instance: impl ToOwned, ) { let connection_state = ConnectionState { socket: Arc::new(Mutex::new(socket)), connections, repository_backend, user_backend, auth_granter, addr, instance: instance.to_owned(), handshaked: Arc::new(AtomicBool::new(false)), cached_keys: Arc::default(), }; let mut handshaked = false; loop { let mut socket = connection_state.socket.lock().await; let message = socket.next().await; drop(socket); match message { Some(Ok(message)) => { let payload = match message { Message::Binary(payload) => payload, Message::Ping(_) => { let mut socket = connection_state.socket.lock().await; let _ = socket.send(Message::Pong(vec![])).await; drop(socket); continue; } Message::Close(_) => return, _ => continue, }; let message = NetworkMessage(payload.clone()); if !handshaked { if handshake_handle(&message, &connection_state).await.is_ok() { if connection_state.handshaked.load(Ordering::SeqCst) { handshaked = true; } } } else { let raw = serde_json::from_slice::(&payload).unwrap(); let message_type = raw.get("message_type").unwrap().as_str().unwrap(); match authentication_handle(message_type, &message, &connection_state).await { Err(e) => { let _ = connection_state.send(ConnectionError(e.to_string())).await; } Ok(true) => continue, Ok(false) => {} } match repository_handle(message_type, &message, &connection_state).await { Err(e) => { let _ = connection_state.send(ConnectionError(e.to_string())).await; } Ok(true) => continue, Ok(false) => {} } match user_handle(message_type, &message, &connection_state).await { Err(e) => { let _ = connection_state.send(ConnectionError(e.to_string())).await; } Ok(true) => continue, Ok(false) => {} } match authentication_handle(message_type, &message, &connection_state).await { Err(e) => { let _ = connection_state.send(ConnectionError(e.to_string())).await; } Ok(true) => continue, Ok(false) => {} } error!( "Message completely unhandled: {}", std::str::from_utf8(&payload).unwrap() ); } } Some(Err(e)) => { error!("Closing connection for {:?} for {}", e, addr); return; } _ => { info!("Unhandled"); continue; } } } } #[derive(Clone)] pub struct ConnectionState { socket: Arc>>, pub connections: Arc>, pub repository_backend: Arc>, pub user_backend: Arc>, pub auth_granter: Arc>, pub addr: SocketAddr, pub instance: Instance, pub handshaked: Arc, pub cached_keys: Arc>>, } impl ConnectionState { pub async fn send(&self, message: T) -> Result<(), Error> { let payload = serde_json::to_string(&message)?; info!("Sending payload: {}", &payload); self.socket .lock() .await .send(Message::Binary(payload.into_bytes())) .await?; Ok(()) } }