#[cfg(feature = "bevy")]
mod bevy;
#[cfg(feature = "bevy")]
pub use bevy::*;
use web_time::Duration;
use std::{error::Error, fmt::Debug, hash::Hash};
use bytes::Bytes;
use derivative::Derivative;
use crate::{
client::{ClientState, DisconnectReason},
lane::LaneIndex,
};
pub trait ServerTransport {
type Error: Error + Send + Sync;
type Opening<'this>
where
Self: 'this;
type Open<'this>
where
Self: 'this;
type Connecting<'this>
where
Self: 'this;
type Connected<'this>
where
Self: 'this;
type ClientKey: Send + Sync + Debug + Clone + PartialEq + Eq + Hash;
type MessageKey: Send + Sync + Debug + Clone + PartialEq + Eq + Hash;
fn state(&self) -> ServerState<Self::Opening<'_>, Self::Open<'_>>;
fn client_state(
&self,
client_key: Self::ClientKey,
) -> ClientState<Self::Connecting<'_>, Self::Connected<'_>>;
fn client_keys(&self) -> impl Iterator<Item = Self::ClientKey> + '_;
fn poll(&mut self, delta_time: Duration) -> impl Iterator<Item = ServerEvent<Self>>;
fn send(
&mut self,
client_key: Self::ClientKey,
msg: impl Into<Bytes>,
lane: impl Into<LaneIndex>,
) -> Result<Self::MessageKey, Self::Error>;
fn flush(&mut self) -> Result<(), Self::Error>;
fn disconnect(
&mut self,
client_key: Self::ClientKey,
reason: impl Into<String>,
) -> Result<(), Self::Error>;
fn close(&mut self, reason: impl Into<String>) -> Result<(), Self::Error>;
}
#[derive(Debug, Clone, Default)]
pub enum ServerState<A, B> {
#[default]
Closed,
Opening(A),
Open(B),
}
pub type ServerStateFor<'t, T> =
ServerState<<T as ServerTransport>::Opening<'t>, <T as ServerTransport>::Open<'t>>;
pub type ClientStateFor<'t, T> =
ClientState<<T as ServerTransport>::Connecting<'t>, <T as ServerTransport>::Connected<'t>>;
impl<A, B> ServerState<A, B> {
pub const fn is_closed(&self) -> bool {
matches!(self, Self::Closed)
}
pub const fn is_opening(&self) -> bool {
matches!(self, Self::Opening(_))
}
pub const fn is_open(&self) -> bool {
matches!(self, Self::Open(_))
}
pub const fn as_ref(&self) -> ServerState<&A, &B> {
match self {
Self::Closed => ServerState::Closed,
Self::Opening(a) => ServerState::Opening(a),
Self::Open(b) => ServerState::Open(b),
}
}
pub fn map<A2, B2>(
self,
fa: impl FnOnce(A) -> A2,
fb: impl FnOnce(B) -> B2,
) -> ServerState<A2, B2> {
match self {
Self::Closed => ServerState::Closed,
Self::Opening(a) => ServerState::Opening(fa(a)),
Self::Open(b) => ServerState::Open(fb(b)),
}
}
}
#[derive(Derivative)]
#[derivative(Debug(bound = "T::Error: Debug"), Clone(bound = "T::Error: Clone"))]
pub enum ServerEvent<T: ServerTransport + ?Sized> {
Opened,
Closed {
reason: CloseReason<T::Error>,
},
Connecting {
client_key: T::ClientKey,
},
Connected {
client_key: T::ClientKey,
},
Disconnected {
client_key: T::ClientKey,
reason: DisconnectReason<T::Error>,
},
Recv {
client_key: T::ClientKey,
msg: Bytes,
lane: LaneIndex,
},
Ack {
client_key: T::ClientKey,
msg_key: T::MessageKey,
},
Nack {
client_key: T::ClientKey,
msg_key: T::MessageKey,
},
}
impl<Error, ClientKey, MessageKey, T> ServerEvent<T>
where
T: ServerTransport<Error = Error, ClientKey = ClientKey, MessageKey = MessageKey>,
{
pub fn remap<R>(self) -> ServerEvent<R>
where
R: ServerTransport<Error = Error, ClientKey = ClientKey, MessageKey = MessageKey>,
{
match self {
Self::Opened => ServerEvent::Opened,
Self::Closed { reason } => ServerEvent::Closed { reason },
Self::Connecting { client_key } => ServerEvent::Connecting { client_key },
Self::Connected { client_key } => ServerEvent::Connected { client_key },
Self::Disconnected { client_key, reason } => {
ServerEvent::Disconnected { client_key, reason }
}
Self::Recv {
client_key,
msg,
lane,
} => ServerEvent::Recv {
client_key,
msg,
lane,
},
Self::Ack {
client_key,
msg_key,
} => ServerEvent::Ack {
client_key,
msg_key,
},
Self::Nack {
client_key,
msg_key,
} => ServerEvent::Nack {
client_key,
msg_key,
},
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum CloseReason<E> {
#[error("disconnected locally: {0}")]
Local(String),
#[error("connection error")]
Error(
#[source]
#[from]
E,
),
}
impl<E> CloseReason<E> {
pub fn map_err<F>(self, f: impl FnOnce(E) -> F) -> CloseReason<F> {
match self {
Self::Local(reason) => CloseReason::Local(reason),
Self::Error(err) => CloseReason::Error(f(err)),
}
}
}