use crate::packet::{Packet, PacketReceiver};
use std::{
io::{self, Read, Write},
net::{Shutdown, SocketAddr, TcpListener, TcpStream, ToSocketAddrs},
sync::{
atomic::{AtomicBool, Ordering},
mpsc::{channel, Receiver, Sender},
Arc, Mutex,
},
thread,
};
type ConnectionSender = Arc<Mutex<Sender<(u32, Vec<u8>)>>>;
pub struct Connection {
connected: Arc<AtomicBool>,
packets: Arc<PacketReceiver>,
sender: ConnectionSender,
stream: TcpStream,
address: SocketAddr,
}
impl Connection {
pub fn new(stream: TcpStream) -> io::Result<Self> {
let connected = Arc::new(AtomicBool::new(true));
let packets = Arc::new(PacketReceiver::new());
let mut thread_stream = stream.try_clone()?;
let thread_packets = Arc::clone(&packets);
let thread_connected = Arc::clone(&connected);
thread::spawn(move || {
let mut int_buffer = [0; 4];
loop {
if !thread_connected.load(Ordering::Relaxed) {
return;
}
if thread_stream.read_exact(&mut int_buffer).is_err() {
break;
}
let len = u32::from_be_bytes(int_buffer);
if thread_stream.read_exact(&mut int_buffer).is_err() {
break;
}
let id = u32::from_be_bytes(int_buffer);
let mut buffer = vec![0; len as usize];
if thread_stream.read_exact(&mut buffer).is_err() {
break;
}
thread_packets.insert(id, buffer);
}
thread_connected.store(false, Ordering::Relaxed);
});
let mut thread_stream = stream.try_clone()?;
let (sender, receiver) = channel();
let thread_connected = Arc::clone(&connected);
thread::spawn(move || {
loop {
if !thread_connected.load(Ordering::Relaxed) {
return;
}
let (id, buffer): (u32, Vec<u8>) = match receiver.recv() {
Ok(data) => data,
Err(_) => break,
};
let len = buffer.len() as u32;
if thread_stream.write_all(&len.to_be_bytes()).is_err() {
break;
}
if thread_stream.write_all(&id.to_be_bytes()).is_err() {
break;
}
if thread_stream.write_all(&buffer).is_err() {
break;
}
if thread_stream.flush().is_err() {
break;
}
}
thread_connected.store(false, Ordering::Relaxed);
});
Ok(Self {
connected,
packets,
sender: Arc::new(Mutex::new(sender)),
address: stream.peer_addr()?,
stream,
})
}
pub fn connect<A: ToSocketAddrs>(address: A) -> io::Result<Self> {
Self::new(TcpStream::connect(address)?)
}
pub fn connected(&self) -> bool {
self.connected.load(Ordering::Relaxed)
}
pub fn clear(&self) {
self.packets.clear();
}
pub fn recv<P: Packet>(&self) -> Vec<P> {
self.packets.extract()
}
pub fn send<P: Packet>(&self, packet: P) {
let data = bincode::serialize(&packet).expect("Failed to serialize packet");
self.sender
.lock()
.map(|sender| sender.send((P::ID, data)))
.ok();
}
pub fn address(&self) -> SocketAddr {
self.address
}
}
impl Drop for Connection {
fn drop(&mut self) {
self.connected.store(false, Ordering::Relaxed);
self.stream.shutdown(Shutdown::Both).ok();
}
}
pub struct Listener {
listening: Arc<AtomicBool>,
receiver: Arc<Mutex<Receiver<Connection>>>,
address: SocketAddr,
}
impl Listener {
pub fn bind<A: ToSocketAddrs>(address: A) -> io::Result<Self> {
let listener = TcpListener::bind(address)?;
let address = listener.local_addr()?;
let listening = Arc::new(AtomicBool::new(true));
let listening_thread = Arc::clone(&listening);
let (sender, receiver) = channel();
thread::spawn(move || {
for stream in listener.incoming() {
let connection = match stream {
Ok(stream) => match Connection::new(stream) {
Ok(connection) => connection,
Err(_) => break,
},
Err(_) => break,
};
if sender.send(connection).is_err() {
break;
}
}
listening_thread.store(false, Ordering::Relaxed);
});
Ok(Self {
listening,
receiver: Arc::new(Mutex::new(receiver)),
address,
})
}
pub fn listening(&self) -> bool {
self.listening.load(Ordering::Relaxed)
}
pub fn accept(&self) -> Option<Connection> {
self.receiver
.lock()
.ok()
.and_then(|receiver| receiver.try_recv().ok())
}
pub fn address(&self) -> SocketAddr {
self.address
}
}