use crate::session::Session;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt, Error, ErrorKind, Result},
net::{
tcp::{OwnedReadHalf, OwnedWriteHalf},
TcpListener,
},
};
#[repr(transparent)]
#[derive(Debug)]
pub struct SocketListener {
socket: TcpListener,
}
impl SocketListener {
pub async fn new(url: &str) -> Result<Self> {
TcpListener::bind(url).await.map(|socket| Self { socket })
}
pub fn address(&self) -> String {
let addr = self.socket.local_addr().unwrap();
format!("{}:{}", addr.ip(), addr.port())
}
async fn connect(&mut self) -> Result<(SocketReader, SocketWriter)> {
let (stream, _) = self.socket.accept().await?;
let (read_stream, write_stream) = stream.into_split();
Ok((
SocketReader::new(read_stream),
SocketWriter::new(write_stream),
))
}
pub async fn new_session(&mut self) -> Result<Session> {
let (socket_reader, socket_writer) = self.connect().await?;
Ok(Session::new(socket_reader, socket_writer))
}
}
#[derive(Debug)]
pub(crate) struct SocketReader {
read_stream: OwnedReadHalf,
buf: [u8; 1024],
}
impl SocketReader {
const fn new(read_stream: OwnedReadHalf) -> Self {
Self {
read_stream,
buf: [0; 1024],
}
}
pub(crate) async fn read(&mut self) -> Result<String> {
let mut msg = String::new();
while !msg.contains('\n') {
self.buf.fill(0); let msg_part = match self.read_stream.read(&mut self.buf).await? {
0 => {
return Err(Error::new(
ErrorKind::ConnectionAborted,
"Connection closed by peer",
));
}
_ => std::str::from_utf8(&self.buf).unwrap().to_string(),
};
msg.push_str(&msg_part);
}
Ok(msg)
}
}
#[repr(transparent)]
#[derive(Debug)]
pub(crate) struct SocketWriter {
write_stream: OwnedWriteHalf,
}
impl SocketWriter {
const fn new(write_stream: OwnedWriteHalf) -> Self {
Self { write_stream }
}
pub(crate) async fn write(&mut self, data: &str) -> Result<usize> {
self.write_stream.write(data.as_bytes()).await
}
}