use log::error;
#[cfg(feature = "debug-logging")]
use log::info;
use std::io;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpStream;
use tokio::sync::mpsc;
use crate::client::{ClientEvent, VncClient};
use crate::framebuffer::Framebuffer;
#[allow(clippy::too_many_arguments)] pub async fn connect_repeater(
client_id: usize,
repeater_host: String,
repeater_port: u16,
repeater_id: String,
framebuffer: Framebuffer,
desktop_name: String,
password: Option<String>,
event_tx: mpsc::UnboundedSender<ClientEvent>,
) -> Result<VncClient, io::Error> {
#[cfg(feature = "debug-logging")]
info!("Connecting to VNC repeater {repeater_host}:{repeater_port} with ID: {repeater_id}");
#[cfg(feature = "debug-logging")]
info!("Attempting TCP connection to {repeater_host}:{repeater_port}...");
let mut stream = match TcpStream::connect(format!("{repeater_host}:{repeater_port}")).await {
Ok(s) => {
#[cfg(feature = "debug-logging")]
info!("TCP connection established to {repeater_host}:{repeater_port}");
s
}
Err(e) => {
error!("Failed to establish TCP connection to {repeater_host}:{repeater_port}: {e}");
return Err(e);
}
};
let mut id_buffer = [0u8; 250];
let id_string = format!("ID:{repeater_id}");
if id_string.len() > 250 {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Repeater ID too long (max 246 characters after 'ID:' prefix)",
));
}
id_buffer[..id_string.len()].copy_from_slice(id_string.as_bytes());
#[cfg(feature = "debug-logging")]
info!("Sending repeater ID: {id_string}");
if let Err(e) = stream.write_all(&id_buffer).await {
error!("Failed to send repeater ID to {repeater_host}:{repeater_port}: {e}");
return Err(e);
}
#[cfg(feature = "debug-logging")]
info!("Repeater ID sent, proceeding with VNC handshake");
let mut client = VncClient::new(
client_id,
stream,
framebuffer,
desktop_name,
password,
event_tx,
)
.await?;
client.set_repeater_metadata(repeater_id, Some(repeater_port));
#[cfg(feature = "debug-logging")]
info!("VNC repeater connection established successfully");
Ok(client)
}
#[derive(Debug, Clone)]
pub enum RepeaterProgress {
RfbMessageSent {
success: bool,
},
HandshakeComplete {
success: bool,
},
}
#[allow(clippy::too_many_arguments)]
pub async fn connect_repeater_with_progress(
client_id: usize,
repeater_host: String,
repeater_port: u16,
repeater_id: String,
framebuffer: Framebuffer,
desktop_name: String,
password: Option<String>,
event_tx: mpsc::UnboundedSender<ClientEvent>,
progress_tx: Option<mpsc::UnboundedSender<RepeaterProgress>>,
) -> Result<VncClient, io::Error> {
#[cfg(feature = "debug-logging")]
info!("Connecting to VNC repeater {repeater_host}:{repeater_port} with ID: {repeater_id}");
#[cfg(feature = "debug-logging")]
info!("Attempting TCP connection to {repeater_host}:{repeater_port}...");
let mut stream = match TcpStream::connect(format!("{repeater_host}:{repeater_port}")).await {
Ok(s) => {
#[cfg(feature = "debug-logging")]
info!("TCP connection established to {repeater_host}:{repeater_port}");
s
}
Err(e) => {
error!("Failed to establish TCP connection to {repeater_host}:{repeater_port}: {e}");
return Err(e);
}
};
let mut id_buffer = [0u8; 250];
let id_string = format!("ID:{repeater_id}");
if id_string.len() > 250 {
if let Some(tx) = &progress_tx {
let _ = tx.send(RepeaterProgress::RfbMessageSent { success: false });
}
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"Repeater ID too long (max 246 characters after 'ID:' prefix)",
));
}
id_buffer[..id_string.len()].copy_from_slice(id_string.as_bytes());
#[cfg(feature = "debug-logging")]
info!("Sending repeater ID: {id_string}");
if let Err(e) = stream.write_all(&id_buffer).await {
error!("Failed to send repeater ID to {repeater_host}:{repeater_port}: {e}");
if let Some(tx) = &progress_tx {
let _ = tx.send(RepeaterProgress::RfbMessageSent { success: false });
}
return Err(e);
}
if let Some(tx) = &progress_tx {
let _ = tx.send(RepeaterProgress::RfbMessageSent { success: true });
}
#[cfg(feature = "debug-logging")]
info!("Repeater ID sent, proceeding with VNC handshake");
let client_result = VncClient::new(
client_id,
stream,
framebuffer,
desktop_name,
password,
event_tx,
)
.await;
match client_result {
Ok(mut client) => {
if let Some(tx) = &progress_tx {
let _ = tx.send(RepeaterProgress::HandshakeComplete { success: true });
}
client.set_repeater_metadata(repeater_id, Some(repeater_port));
#[cfg(feature = "debug-logging")]
info!("VNC repeater connection established successfully");
Ok(client)
}
Err(e) => {
if let Some(tx) = &progress_tx {
let _ = tx.send(RepeaterProgress::HandshakeComplete { success: false });
}
Err(e)
}
}
}