use std::{
io,
marker::PhantomData,
net::{TcpStream, ToSocketAddrs},
time::Duration,
};
use serde::{de::DeserializeOwned, Serialize};
use crate::{
pkg::{Pkg, PkgData},
stog, PeerID,
};
pub struct Client<T> {
pub stream: TcpStream,
pub id: PeerID,
pub peers: Vec<Option<String>>,
pub last_host_timestamp: Duration,
pub _marker: PhantomData<T>,
}
impl<T: DeserializeOwned + Serialize> Client<T> {
pub fn connect<A>(addr: A) -> io::Result<Self>
where
A: ToSocketAddrs,
{
let stream = TcpStream::connect(addr)?;
stream.set_read_timeout(crate::IO_TIMEOUT)?;
stream.set_write_timeout(crate::IO_TIMEOUT)?;
let s = Self {
stream,
id: 0, peers: Vec::default(), last_host_timestamp: Duration::ZERO, _marker: PhantomData,
};
Ok(s)
}
pub fn handle_pkg(&mut self, pkg: Pkg<T>) -> stog::Result<Option<Pkg<T>>> {
if pkg.is_from_server() {
self.last_host_timestamp = pkg.time;
}
match pkg.data {
PkgData::SetPeer(id) => {
self.id = id
}
PkgData::SetPeers(ps) => {
self.peers = ps;
}
PkgData::Data(_, _) => {
return Ok(Some(pkg));
}
PkgData::GlobalData(_) => return Ok(Some(pkg)),
_ => unimplemented!(),
}
Ok(None)
}
pub fn poll(&mut self) -> stog::Result<Option<Pkg<T>>> {
match stog::read(&mut self.stream) {
Ok(pkg) => self.handle_pkg(pkg),
Err(stog::Error::NoPackage) => Ok(None),
Err(stog::Error::ConnClosed) => Err(stog::Error::ConnClosed),
Err(e) => panic!("polling error: {e:?}"),
}
}
pub fn get_active_peers(&self) -> impl Iterator<Item = PeerID> + '_ {
self.peers.iter().enumerate().filter_map(
|(i, p)| {
if p.is_some() {
Some(i as PeerID)
} else {
None
}
},
)
}
}