use crate::enums::internal_event::InternalEvent;
use crate::errors::p2p_error::P2pError;
use crate::models::user_data::UserData;
use crate::switchboard_server::commands::msg;
use crate::switchboard_server::p2p::display_picture_session::DisplayPictureSession;
use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use std::sync::Arc;
use std::sync::atomic::AtomicU32;
use tokio::sync::RwLock;
use tokio::sync::broadcast::Receiver;
use tokio::sync::mpsc::Sender;
pub async fn handle_invite(
destination: String,
invite: Vec<u8>,
user_data: Arc<RwLock<UserData>>,
command_internal_rx: &mut Receiver<InternalEvent>,
tr_id: Arc<AtomicU32>,
sb_tx: Sender<Vec<u8>>,
) -> Result<(), Box<dyn std::error::Error>> {
{
let user_data = user_data.read().await;
let user_email = user_data.email.as_ref().ok_or(P2pError::NotLoggedIn)?;
if destination != *user_email {
return Err(P2pError::OtherDestination.into());
}
}
let invite_string = unsafe { str::from_utf8_unchecked(invite.as_slice()) };
let mut invite_parameters = invite_string.lines();
invite_parameters.next();
let to = invite_parameters
.next()
.ok_or(P2pError::CouldNotGetSessionData)?;
{
let user_data = user_data.read().await;
let user_email = user_data.email.as_ref().ok_or(P2pError::NotLoggedIn)?;
if !to.contains(format!("msnmsgr:{user_email}").as_str()) {
return Err(P2pError::OtherDestination.into());
}
}
let from = invite_parameters
.next()
.ok_or(P2pError::CouldNotGetSessionData)?
.replace("From: <msnmsgr:", "")
.replace(">", "");
let session = DisplayPictureSession::new_from_invite(&invite)?;
let ack_payload = DisplayPictureSession::acknowledge(&invite)?;
msg::send_p2p(
&tr_id,
&sb_tx,
command_internal_rx,
ack_payload,
from.as_str(),
)
.await?;
let context = invite_parameters
.find(|line| line.contains("Context: "))
.ok_or(P2pError::CouldNotGetSessionData)?
.replace("Context: ", "");
{
let user_data = user_data.read().await;
let msn_object = user_data
.msn_object
.as_ref()
.ok_or(P2pError::CouldNotGetUserData)?;
if context != STANDARD.encode((msn_object.to_owned() + "\0").as_bytes()) {
return Err(P2pError::OtherContext.into());
}
}
let ok_payload = session.ok(from.as_str(), to)?;
msg::send_p2p(
&tr_id,
&sb_tx,
command_internal_rx,
ok_payload,
from.as_str(),
)
.await?;
let preparation_payload = session.data_preparation()?;
msg::send_p2p(
&tr_id,
&sb_tx,
command_internal_rx,
preparation_payload,
from.as_str(),
)
.await?;
let user_data = user_data.read().await;
let display_picture = user_data
.display_picture
.as_ref()
.ok_or(P2pError::CouldNotGetDisplayPicture)?;
let data_payloads = session.data(display_picture)?;
for data_payload in data_payloads {
msg::send_p2p(
&tr_id,
&sb_tx,
command_internal_rx,
data_payload,
from.as_str(),
)
.await?;
}
Ok(())
}
pub async fn handle_bye(
destination: String,
bye: Vec<u8>,
user_data: Arc<RwLock<UserData>>,
command_internal_rx: &mut Receiver<InternalEvent>,
tr_id: Arc<AtomicU32>,
sb_tx: Sender<Vec<u8>>,
) -> Result<(), Box<dyn std::error::Error>> {
{
let user_data = user_data.read().await;
let user_email = user_data.email.as_ref().ok_or(P2pError::NotLoggedIn)?;
if destination != *user_email {
return Err(P2pError::OtherDestination.into());
}
}
let bye_string = unsafe { str::from_utf8_unchecked(bye.as_slice()) };
let mut bye_parameters = bye_string.lines();
let from = bye_parameters
.nth(2)
.ok_or(P2pError::CouldNotGetSessionData)?
.replace("From: <msnmsgr:", "")
.replace(">", "");
let ack_payload = DisplayPictureSession::acknowledge(&bye)?;
msg::send_p2p(
&tr_id,
&sb_tx,
command_internal_rx,
ack_payload,
from.as_str(),
)
.await
.map_err(|error| error.into())
}