use super::{InPacket, RawPacket, Recv, RecvBuf, Send, SendBuf, SlotKey};
use crate::wire::{ip::Address, PayloadMut};
pub struct Client<R, S> {
state: ClientState,
recv: R,
send: S,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum ClientState {
Uninstantiated {
remote: Address,
remote_port: u16,
},
InStack {
key: SlotKey,
},
Finished,
}
impl<R, S> Client<R, S>
where
R: RecvBuf,
S: SendBuf,
{
pub fn new(
remote: Address,
remote_port: u16,
recv: R,
send: S,
) -> Self {
Client {
state: ClientState::Uninstantiated {
remote,
remote_port,
},
recv,
send,
}
}
}
impl<R, S> Client<R, S> {
pub fn recv(&self) -> &R {
&self.recv
}
pub fn recv_mut(&mut self) -> &mut R {
&mut self.recv
}
pub fn send(&self) -> &S {
&self.send
}
pub fn send_mut(&mut self) -> &mut S {
&mut self.send
}
pub fn is_closed(&self) -> bool {
match self.state {
ClientState::Finished => true,
_ => false,
}
}
pub fn connection_key(&self) -> Option<SlotKey> {
match self.state {
ClientState::InStack { key } => Some(key),
_ => None,
}
}
}
impl<R, S, P> Recv<P> for &'_ mut Client<R, S>
where
R: RecvBuf,
S: SendBuf,
P: PayloadMut,
{
fn receive(&mut self, packet: InPacket<P>) {
let key = match self.state {
ClientState::InStack { key } => key,
_ => return,
};
if packet.key() != Some(key) {
return;
}
match packet {
InPacket::Stray(_) | InPacket::Sending(_) => (),
InPacket::Closed(_) | InPacket::Closing(_) => {
self.state = ClientState::Finished;
},
InPacket::Open(mut open) => {
open.read(&mut self.recv);
let _ = open.write(&mut self.send);
},
}
}
}
impl<R, S, P> Send<P> for &'_ mut Client<R, S>
where
R: RecvBuf,
S: SendBuf,
P: PayloadMut,
{
fn send(&mut self, packet: RawPacket<P>) {
let open = match self.state {
ClientState::Uninstantiated { remote, remote_port } => {
match packet.open(remote, remote_port) {
Ok(open) => {
self.state = ClientState::InStack { key: open.key() };
open
},
Err(crate::layer::Error::Exhausted) => return,
Err(_other) => {
self.state = ClientState::Finished;
return;
},
}
},
ClientState::InStack { key } => {
match packet.attach(key) {
Ok(open) => open,
Err(_) => return self.state = ClientState::Finished,
}
},
ClientState::Finished => return,
};
let _ = open.write(&mut self.send);
}
}