use super::{
kx_pair::KxPair, packet_queues::AuthoredPacketQueue, replay_filter::ReplayFilter,
topology::Topology,
};
use std::{
fmt,
ops::{Add, Index, IndexMut},
time::Duration,
};
pub struct Session<X> {
pub kx_pair: KxPair,
pub topology: Topology<X>,
pub authored_packet_queue: AuthoredPacketQueue,
pub mean_authored_packet_period: Duration,
pub replay_filter: ReplayFilter,
}
pub type SessionIndex = u32;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum RelSessionIndex {
Current,
Prev,
}
impl RelSessionIndex {
pub fn from_session_index(
session_index: SessionIndex,
current_session_index: SessionIndex,
) -> Option<Self> {
match current_session_index.checked_sub(session_index) {
Some(0) => Some(Self::Current),
Some(1) => Some(Self::Prev),
_ => None,
}
}
}
impl Add<SessionIndex> for RelSessionIndex {
type Output = SessionIndex;
fn add(self, other: SessionIndex) -> Self::Output {
match self {
Self::Current => other,
Self::Prev => other.checked_sub(1).expect("Session index underflow"),
}
}
}
pub enum SessionSlot<X> {
Empty,
KxPair(KxPair),
Disabled,
Full(Session<X>),
}
impl<X> SessionSlot<X> {
pub fn is_empty(&self) -> bool {
matches!(self, Self::Empty)
}
pub fn as_option(&self) -> Option<&Session<X>> {
match self {
Self::Full(session) => Some(session),
_ => None,
}
}
pub fn as_mut_option(&mut self) -> Option<&mut Session<X>> {
match self {
Self::Full(session) => Some(session),
_ => None,
}
}
}
pub struct Sessions<X> {
pub current: SessionSlot<X>,
pub prev: SessionSlot<X>,
}
impl<X> Sessions<X> {
pub fn is_empty(&self) -> bool {
self.current.is_empty() && self.prev.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Session<X>> {
[&self.current, &self.prev]
.into_iter()
.filter_map(|session| session.as_option())
}
pub fn enumerate_mut(&mut self) -> impl Iterator<Item = (RelSessionIndex, &mut Session<X>)> {
[(RelSessionIndex::Current, &mut self.current), (RelSessionIndex::Prev, &mut self.prev)]
.into_iter()
.filter_map(|(index, session)| session.as_mut_option().map(|session| (index, session)))
}
}
impl<X> Index<RelSessionIndex> for Sessions<X> {
type Output = SessionSlot<X>;
fn index(&self, index: RelSessionIndex) -> &Self::Output {
match index {
RelSessionIndex::Current => &self.current,
RelSessionIndex::Prev => &self.prev,
}
}
}
impl<X> IndexMut<RelSessionIndex> for Sessions<X> {
fn index_mut(&mut self, index: RelSessionIndex) -> &mut Self::Output {
match index {
RelSessionIndex::Current => &mut self.current,
RelSessionIndex::Prev => &mut self.prev,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum SessionPhase {
CoverToCurrent,
RequestsToCurrent,
CoverToPrev,
DisconnectFromPrev,
}
impl SessionPhase {
pub fn need_prev(self) -> bool {
self < Self::DisconnectFromPrev
}
pub fn allow_requests_and_replies(self, rel_session_index: RelSessionIndex) -> bool {
match rel_session_index {
RelSessionIndex::Prev => self < Self::CoverToPrev,
RelSessionIndex::Current => self >= Self::RequestsToCurrent,
}
}
pub fn default_request_session(self) -> RelSessionIndex {
if self >= Self::RequestsToCurrent {
RelSessionIndex::Current
} else {
RelSessionIndex::Prev
}
}
}
impl fmt::Display for SessionPhase {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::CoverToCurrent => write!(fmt, "Generating cover traffic to current mixnode set"),
Self::RequestsToCurrent => write!(fmt, "Building requests using current mixnode set"),
Self::CoverToPrev => write!(fmt, "Only sending cover traffic to previous mixnode set"),
Self::DisconnectFromPrev => write!(fmt, "Only using current mixnode set"),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct SessionStatus {
pub current_index: SessionIndex,
pub phase: SessionPhase,
}
impl fmt::Display for SessionStatus {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Current index {}, phase: {}", self.current_index, self.phase)
}
}