use crate::{ExactAddressType, GeneralAddressType};
pub use super::packet::PacketState;
use super::packet::{Packet, PacketLifetimeEnded, RespondToBroadcastAddressError};
pub struct Router {
current_device_identifier: ExactAddressType,
}
pub enum RouteResult {
ReceivedOnly(Packet),
TransitOnly(Packet),
ReceivedAndTransit { received: Packet, transit: Packet },
}
pub enum RouteError {
PacketLifetimeEnded,
RespondToBroadcastAddressError,
}
impl From<PacketLifetimeEnded> for RouteError {
fn from(_: PacketLifetimeEnded) -> Self {
Self::PacketLifetimeEnded
}
}
impl From<RespondToBroadcastAddressError> for RouteError {
fn from(_: RespondToBroadcastAddressError) -> Self {
Self::RespondToBroadcastAddressError
}
}
impl Router {
pub fn new(current_device_identifier: ExactAddressType) -> Self {
Self {
current_device_identifier,
}
}
fn handle_broadcast(&self, packet: Packet) -> Result<RouteResult, RouteError> {
let received = packet.clone();
let transit: Option<Packet> = match packet.deacrease_lifetime() {
Ok(packet) => Some(packet),
Err(PacketLifetimeEnded) => None,
};
if let Some(transit) = transit {
return Ok(RouteResult::ReceivedAndTransit { received, transit });
}
return Ok(RouteResult::ReceivedOnly(received));
}
fn keep_copy_and_prepare_transit(&self, packet: Packet) -> Result<RouteResult, RouteError> {
let received = packet.clone();
let transit = packet.mutated()?;
Ok(RouteResult::ReceivedAndTransit { received, transit })
}
pub fn route(&self, packet: Packet) -> Result<RouteResult, RouteError> {
if packet.is_destination_reached(self.current_device_identifier.into()) {
return match packet.get_spec_state() {
PacketState::Normal => Ok(RouteResult::ReceivedOnly(packet)), PacketState::Ping => self.keep_copy_and_prepare_transit(packet),
PacketState::Pong => Ok(RouteResult::ReceivedOnly(packet)),
PacketState::SendTransaction => Ok(RouteResult::TransitOnly(packet.mutated()?)),
PacketState::AcceptTransaction => Ok(RouteResult::TransitOnly(packet.mutated()?)),
PacketState::InitTransaction => self.keep_copy_and_prepare_transit(packet),
PacketState::FinishTransaction => Ok(RouteResult::ReceivedOnly(packet)),
};
}
if packet.is_destination_reached(GeneralAddressType::Broadcast) {
return self.handle_broadcast(packet);
}
match packet.deacrease_lifetime() {
Ok(packet) => Ok(RouteResult::TransitOnly(packet)),
Err(PacketLifetimeEnded) => return Err(RouteError::PacketLifetimeEnded), }
}
}