use std::collections::HashMap;
use crate::message::{Message, Method, Request, Response};
use crate::transaction::client::{ClientState, ClientTransaction};
use crate::transaction::key::TransactionKey;
use crate::transaction::server::{ServerState, ServerTransaction};
use crate::transaction::timing::{Timer, Timers};
use crate::transaction::{Output, Reliability, TuEvent};
#[derive(Debug)]
pub enum Dispatch {
Matched {
key: TransactionKey,
outputs: Vec<Output>,
},
Created {
key: TransactionKey,
outputs: Vec<Output>,
},
Unmatched(Box<Message>),
}
#[derive(Debug)]
pub struct TransactionLayer {
client: HashMap<TransactionKey, ClientTransaction>,
server: HashMap<TransactionKey, ServerTransaction>,
timers: Timers,
}
impl TransactionLayer {
#[must_use]
pub fn new(timers: Timers) -> Self {
Self {
client: HashMap::new(),
server: HashMap::new(),
timers,
}
}
#[must_use]
pub fn len(&self) -> (usize, usize) {
(self.client.len(), self.server.len())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.client.is_empty() && self.server.is_empty()
}
pub fn send_request(
&mut self,
request: Request,
reliability: Reliability,
) -> Option<(TransactionKey, Vec<Output>)> {
let key = TransactionKey::from_sent_request(&request)?;
let (tx, outputs) = ClientTransaction::new(request, reliability, self.timers);
self.client.insert(key.clone(), tx);
Some((key, outputs))
}
pub fn receive(&mut self, message: Message, reliability: Reliability) -> Dispatch {
match message {
Message::Request(request) => self.receive_request(request, reliability),
Message::Response(response) => self.receive_response(response),
}
}
fn receive_request(&mut self, request: Request, reliability: Reliability) -> Dispatch {
let Some(key) = TransactionKey::from_request(&request) else {
return Dispatch::Unmatched(Box::new(Message::Request(request)));
};
if let Some(tx) = self.server.get_mut(&key) {
let outputs = tx.on_request(&request);
let terminated = tx.state().is_terminated();
if terminated {
self.server.remove(&key);
}
return Dispatch::Matched { key, outputs };
}
if request.method == Method::Ack {
return Dispatch::Unmatched(Box::new(Message::Request(request)));
}
let (tx, outputs) = ServerTransaction::new(request, reliability, self.timers);
self.server.insert(key.clone(), tx);
Dispatch::Created { key, outputs }
}
fn receive_response(&mut self, response: Response) -> Dispatch {
let Some(key) = TransactionKey::from_response(&response) else {
return Dispatch::Unmatched(Box::new(Message::Response(response)));
};
let Some(tx) = self.client.get_mut(&key) else {
return Dispatch::Unmatched(Box::new(Message::Response(response)));
};
let outputs = tx.on_response(response);
if tx.state().is_terminated() {
self.client.remove(&key);
}
Dispatch::Matched { key, outputs }
}
pub fn send_response(&mut self, key: &TransactionKey, response: Response) -> Vec<Output> {
let Some(tx) = self.server.get_mut(key) else {
return Vec::new();
};
let outputs = tx.on_tu_response(response);
if tx.state().is_terminated() {
self.server.remove(key);
}
outputs
}
pub fn abandon(&mut self, key: &TransactionKey) -> bool {
self.server.remove(key).is_some()
}
pub fn on_timer(&mut self, key: &TransactionKey, timer: Timer) -> Vec<Output> {
if let Some(tx) = self.client.get_mut(key) {
let outputs = tx.on_timer(timer);
if tx.state().is_terminated() {
self.client.remove(key);
}
return outputs;
}
if let Some(tx) = self.server.get_mut(key) {
let outputs = tx.on_timer(timer);
if tx.state().is_terminated() {
self.server.remove(key);
}
return outputs;
}
Vec::new()
}
pub fn on_transport_error(&mut self, key: &TransactionKey) -> Vec<Output> {
if let Some(tx) = self.client.get_mut(key) {
let outputs = tx.on_transport_error();
self.client.remove(key);
return outputs;
}
if let Some(tx) = self.server.get_mut(key) {
let outputs = tx.on_transport_error();
self.server.remove(key);
return outputs;
}
Vec::new()
}
#[must_use]
pub fn server_request(&self, key: &TransactionKey) -> Option<&Request> {
self.server.get(key).map(ServerTransaction::request)
}
#[must_use]
pub fn client_request(&self, key: &TransactionKey) -> Option<&Request> {
self.client.get(key).map(ClientTransaction::request)
}
#[must_use]
pub fn client_state(&self, key: &TransactionKey) -> Option<ClientState> {
self.client.get(key).map(ClientTransaction::state)
}
#[must_use]
pub fn server_state(&self, key: &TransactionKey) -> Option<ServerState> {
self.server.get(key).map(ServerTransaction::state)
}
}
#[must_use]
pub fn tu_events(outputs: &[Output]) -> Vec<&TuEvent> {
outputs
.iter()
.filter_map(|o| match o {
Output::ToTu(event) => Some(event.as_ref()),
_ => None,
})
.collect()
}
#[must_use]
pub fn sent_messages(outputs: &[Output]) -> Vec<&Message> {
outputs
.iter()
.filter_map(|o| match o {
Output::Send(message) => Some(message.as_ref()),
_ => None,
})
.collect()
}