2023-04-28 08:13:32 +00:00
|
|
|
use tokio::{
|
|
|
|
|
io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter},
|
|
|
|
|
net::TcpListener,
|
|
|
|
|
};
|
|
|
|
|
use tracing::{error, info};
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
const IP: &str = "0.0.0.0";
|
|
|
|
|
const PORT: u16 = 1222;
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
type Error = Box<dyn std::error::Error + Send + Sync>;
|
|
|
|
|
type Result<T> = std::result::Result<T, Error>;
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
#[tokio::main]
|
|
|
|
|
async fn main() -> Result<()> {
|
|
|
|
|
tracing_subscriber::fmt::try_init().expect("Tracing was not setup");
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
let listener = TcpListener::bind(format!("{IP}:{PORT}")).await?;
|
|
|
|
|
info!("Listening on: {}", format!("{IP}:{PORT}"));
|
|
|
|
|
// Infinite loop to always listen to new connections on this IP/PORT
|
2023-04-27 13:23:56 +00:00
|
|
|
loop {
|
2023-04-28 08:13:32 +00:00
|
|
|
// Get the TCP stream out of the new connection, and the address from which
|
|
|
|
|
// it is connected to
|
|
|
|
|
let (mut stream, address) = listener.accept().await?;
|
|
|
|
|
info!("New address connected: {}", address);
|
|
|
|
|
// We spawn a new task, so every incoming connection can be put on a thread
|
|
|
|
|
// and be worked on "in the background"
|
|
|
|
|
// This allows us to handle multiple connections "at the same time"
|
|
|
|
|
let _ = stream.write_all("You are connected!\n".as_bytes()).await;
|
2023-04-27 13:23:56 +00:00
|
|
|
tokio::spawn(async move {
|
2023-04-28 08:13:32 +00:00
|
|
|
// From the stream (TcpStream), we can extract the reading, and the writing part
|
|
|
|
|
// So we can read and write to the connected client on this port
|
|
|
|
|
let (reader, writer) = stream.split();
|
|
|
|
|
|
|
|
|
|
// So we don't read "directly" on the reader. Therefore we use
|
|
|
|
|
// BufReader, which performs large, infrequent reads on the underlying
|
|
|
|
|
// AsyncRead instance (reader)
|
|
|
|
|
let mut reader = BufReader::new(reader);
|
|
|
|
|
|
|
|
|
|
// We do the same for the writing part to the stream
|
|
|
|
|
// let mut writer = BufWriter::new(writer);
|
|
|
|
|
let mut writer = BufWriter::new(writer);
|
|
|
|
|
|
|
|
|
|
// We need to store what we read from the stream in a local buffer/object
|
|
|
|
|
let mut line = String::new();
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
// We read exactly one line per loop. A line ends with \n.
|
|
|
|
|
// So if the client doesn't frame their package with \n at the end,
|
|
|
|
|
// we won't process until we find one.
|
|
|
|
|
let _ = match reader.read_line(&mut line).await {
|
|
|
|
|
Ok(n) if n == 0 => return,
|
|
|
|
|
Ok(n) => n,
|
|
|
|
|
Err(e) => {
|
|
|
|
|
error!("Error reading: {}", e);
|
2023-04-27 13:23:56 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2023-04-28 08:13:32 +00:00
|
|
|
};
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
info!("New client message received: {}", line.trim_end());
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
if let Err(e) = writer.write_all(line.as_bytes()).await {
|
|
|
|
|
error!("Error writing: {}", e);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
let _ = writer.write_all(&[b'\n']).await;
|
|
|
|
|
let _ = writer.flush().await;
|
2023-04-27 13:23:56 +00:00
|
|
|
|
2023-04-28 08:13:32 +00:00
|
|
|
line.clear();
|
2023-04-27 13:23:56 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|