use std::{io, net::SocketAddr, sync::atomic::Ordering};
use once_cell::race::OnceBox;
use tokio::{
sync::{mpsc, oneshot},
task::JoinHandle,
};
use crate::{
Tcp,
connections::{Connection, DisconnectOrigin},
};
mod disconnect;
mod handshake;
mod on_connect;
mod reading;
mod writing;
pub use disconnect::Disconnect;
pub use handshake::Handshake;
pub use on_connect::OnConnect;
pub use reading::Reading;
pub use writing::Writing;
type OnDisconnectBundle = (JoinHandle<()>, oneshot::Receiver<()>);
#[derive(Default)]
pub(crate) struct Protocols {
pub(crate) handshake: OnceBox<ProtocolHandler<Connection, io::Result<Connection>>>,
pub(crate) reading: OnceBox<ProtocolHandler<Connection, io::Result<Connection>>>,
pub(crate) writing: OnceBox<writing::WritingHandler>,
pub(crate) on_connect: OnceBox<ProtocolHandler<SocketAddr, JoinHandle<()>>>,
pub(crate) disconnect: OnceBox<ProtocolHandler<(SocketAddr, DisconnectOrigin), OnDisconnectBundle>>,
}
pub(crate) type ReturnableItem<T, U> = (T, oneshot::Sender<U>);
pub(crate) type ReturnableConnection = ReturnableItem<Connection, io::Result<Connection>>;
pub(crate) struct ProtocolHandler<T, U>(mpsc::Sender<ReturnableItem<T, U>>);
pub(crate) trait Protocol<T, U> {
async fn trigger(&self, item: ReturnableItem<T, U>);
}
impl<T, U> Protocol<T, U> for ProtocolHandler<T, U> {
async fn trigger(&self, item: ReturnableItem<T, U>) {
let _ = self.0.send(item).await;
}
}
pub(crate) struct DisconnectOnDrop {
pub(crate) node: Option<Tcp>,
pub(crate) addr: SocketAddr,
pub(crate) origin: DisconnectOrigin,
}
impl DisconnectOnDrop {
pub(crate) fn new(node: Tcp, addr: SocketAddr, origin: DisconnectOrigin) -> Self {
Self { node: Some(node), addr, origin }
}
}
impl Drop for DisconnectOnDrop {
fn drop(&mut self) {
if let Some(node) = self.node.take() {
let (addr, origin) = (self.addr, self.origin);
let needs_recovery =
node.connections.0.read().get(&addr).is_some_and(|c| !c.disconnecting.load(Ordering::Acquire));
if needs_recovery {
tokio::spawn(async move { node.disconnect_w_origin(addr, origin).await });
}
}
}
}