use color_eyre::Report; use tokio::{ io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, net::TcpListener, sync::broadcast, }; use tracing::info; use tracing_subscriber::filter::EnvFilter; #[tokio::main] async fn main() -> Result<(), Report> { // Setup the Environment setup()?; // Set up a TCP listener to listen for incoming tcp requests let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap(); // Setting up broadcast channel: A channel that will accept messages and broadcast them to everyone connected to the TCP server // the channel accepts an i32 that is the maximum number of messages the channel can retain at any given time let (sender, _receiver) = broadcast::channel(10); // First loop accept all the tcp client requests loop { // prevent the compiler error when we try to access something in a loop when it was initialized outside of the loop let sender = sender.clone(); let mut receiver = sender.subscribe(); // accept the requests let (mut socket, addr) = listener.accept().await.unwrap(); tokio::spawn(async move { // Splitting the TCP socket into read/write halves let (reader, mut writer) = socket.split(); let mut buffer_reader = BufReader::new(reader); let mut line: String = String::new(); // second loop keeps receiving input from that one client going loop { tokio::select! { result = buffer_reader.read_line(&mut line) => { if result.unwrap() == 0{ break; } // send items to the broadcast channel sender.send((line.clone(), addr)).unwrap(); // clear the input buffer line.clear(); } result = receiver.recv() => { let (msg, other_addr) = result.unwrap(); if addr != other_addr { writer.write_all(msg.as_bytes()).await.unwrap(); } } } } }); } } fn setup() -> Result<(), Report> { info!("Changing some environment variables!"); if std::env::var("RUST_LIB_BACKTRACE").is_err() { std::env::set_var("RUST_LIB_BACKTRACE", "1"); info!("RUST_LIB_BACKTRACE is set. There will be pretty error messages !") } color_eyre::install()?; if std::env::var("RUST_LOG").is_err() { std::env::set_var("RUST_LOG", "info"); info!("RUST_LOG is set. All errors shall be logged !") } tracing_subscriber::fmt::fmt() .with_env_filter(EnvFilter::from_default_env()) .init(); Ok(()) }