0.3.4-alpha.2
This commit is contained in:
42
crates/common/game-realtime-transport-lib/src/connection.rs
Normal file
42
crates/common/game-realtime-transport-lib/src/connection.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
// file: crates/common/game-realtime-transport-lib/src/connection.rs
|
||||
// version: 1
|
||||
|
||||
/// Established realtime connection that owns independent send and receive halves.
|
||||
pub trait RealtimeConnection {
|
||||
/// Send half produced when this connection is split.
|
||||
type Sender: crate::RealtimeSender;
|
||||
/// Receive half produced when this connection is split.
|
||||
type Receiver: crate::RealtimeReceiver;
|
||||
|
||||
/// Consumes the connection and returns independent send and receive halves.
|
||||
fn split(self) -> (Self::Sender, Self::Receiver);
|
||||
}
|
||||
|
||||
/// Send half of an established realtime connection.
|
||||
pub trait RealtimeSender {
|
||||
/// Future returned by [`RealtimeSender::send`].
|
||||
type SendFuture<'a>: core::future::Future<Output = Result<(), crate::TransportError>>
|
||||
where
|
||||
Self: 'a;
|
||||
/// Future returned by [`RealtimeSender::close`].
|
||||
type CloseFuture<'a>: core::future::Future<Output = Result<(), crate::TransportError>>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
/// Sends one owned opaque binary message, respecting backend backpressure.
|
||||
fn send(&mut self, message: crate::TransportMessage) -> Self::SendFuture<'_>;
|
||||
|
||||
/// Initiates a clean local transport-level close.
|
||||
fn close(&mut self) -> Self::CloseFuture<'_>;
|
||||
}
|
||||
|
||||
/// Receive half of an established realtime connection.
|
||||
pub trait RealtimeReceiver {
|
||||
/// Future returned by [`RealtimeReceiver::receive`].
|
||||
type ReceiveFuture<'a>: core::future::Future<Output = Result<crate::TransportReceive, crate::TransportError>>
|
||||
where
|
||||
Self: 'a;
|
||||
|
||||
/// Receives one binary message or observes a clean remote close.
|
||||
fn receive(&mut self) -> Self::ReceiveFuture<'_>;
|
||||
}
|
||||
82
crates/common/game-realtime-transport-lib/src/error.rs
Normal file
82
crates/common/game-realtime-transport-lib/src/error.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
// file: crates/common/game-realtime-transport-lib/src/error.rs
|
||||
// version: 1
|
||||
|
||||
/// Stable transport-neutral category for a realtime operation failure.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum TransportErrorKind {
|
||||
/// An endpoint or transport configuration is invalid.
|
||||
InvalidConfiguration,
|
||||
/// A client connection could not be established.
|
||||
Connect,
|
||||
/// A server endpoint could not be bound.
|
||||
Bind,
|
||||
/// A server could not accept an incoming connection.
|
||||
Accept,
|
||||
/// An operation exceeded its configured deadline.
|
||||
Timeout,
|
||||
/// A payload exceeds the configured transport bound.
|
||||
MessageTooLarge,
|
||||
/// The transport cannot currently accept more outbound data within its configured bounds.
|
||||
Backpressure,
|
||||
/// The requested operation requires a connection that is already closed.
|
||||
Closed,
|
||||
/// An underlying I/O operation failed.
|
||||
Io,
|
||||
/// The backend reported a protocol-level or transport-specific failure.
|
||||
Protocol,
|
||||
/// The operation was explicitly aborted or cancelled when that distinction is observable.
|
||||
Aborted,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for TransportErrorKind {
|
||||
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
return match self {
|
||||
crate::TransportErrorKind::InvalidConfiguration => formatter.write_str("invalid configuration"),
|
||||
crate::TransportErrorKind::Connect => formatter.write_str("connect failure"),
|
||||
crate::TransportErrorKind::Bind => formatter.write_str("bind failure"),
|
||||
crate::TransportErrorKind::Accept => formatter.write_str("accept failure"),
|
||||
crate::TransportErrorKind::Timeout => formatter.write_str("operation timed out"),
|
||||
crate::TransportErrorKind::MessageTooLarge => formatter.write_str("message too large"),
|
||||
crate::TransportErrorKind::Backpressure => formatter.write_str("transport backpressure"),
|
||||
crate::TransportErrorKind::Closed => formatter.write_str("connection closed"),
|
||||
crate::TransportErrorKind::Io => formatter.write_str("I/O failure"),
|
||||
crate::TransportErrorKind::Protocol => formatter.write_str("protocol failure"),
|
||||
crate::TransportErrorKind::Aborted => formatter.write_str("operation aborted"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Transport-neutral operation failure with a stable category and diagnostic detail.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TransportError {
|
||||
detail: String,
|
||||
kind: crate::TransportErrorKind,
|
||||
}
|
||||
|
||||
impl TransportError {
|
||||
/// Creates a transport failure from a stable category and backend-neutral diagnostic detail.
|
||||
#[must_use]
|
||||
pub fn new(kind: crate::TransportErrorKind, detail: impl Into<String>) -> Self {
|
||||
return Self { detail: detail.into(), kind };
|
||||
}
|
||||
|
||||
/// Borrows the diagnostic detail associated with the failure.
|
||||
#[must_use]
|
||||
pub fn detail(&self) -> &str {
|
||||
return self.detail.as_str();
|
||||
}
|
||||
|
||||
/// Returns the stable transport-neutral failure category.
|
||||
#[must_use]
|
||||
pub fn kind(&self) -> crate::TransportErrorKind {
|
||||
return self.kind;
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for TransportError {
|
||||
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
return write!(formatter, "{}: {}", self.kind, self.detail);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TransportError {}
|
||||
31
crates/common/game-realtime-transport-lib/src/lib.rs
Normal file
31
crates/common/game-realtime-transport-lib/src/lib.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// file: crates/common/game-realtime-transport-lib/src/lib.rs
|
||||
// version: 1
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Transport-neutral realtime connection contracts for games.sasedev.
|
||||
|
||||
mod connection;
|
||||
mod error;
|
||||
mod message;
|
||||
|
||||
/// Re-export of an established realtime connection that can be split into independent halves.
|
||||
pub use self::connection::RealtimeConnection;
|
||||
/// Re-export of the receive half of an established realtime connection.
|
||||
pub use self::connection::RealtimeReceiver;
|
||||
/// Re-export of the send half of an established realtime connection.
|
||||
pub use self::connection::RealtimeSender;
|
||||
/// Re-export of a transport-neutral operation failure.
|
||||
pub use self::error::TransportError;
|
||||
/// Re-export of transport-neutral error categories.
|
||||
pub use self::error::TransportErrorKind;
|
||||
/// Re-export of an owned opaque binary transport message.
|
||||
pub use self::message::TransportMessage;
|
||||
/// Re-export of the result of one receive operation.
|
||||
pub use self::message::TransportReceive;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/contract.rs"]
|
||||
mod tests;
|
||||
49
crates/common/game-realtime-transport-lib/src/message.rs
Normal file
49
crates/common/game-realtime-transport-lib/src/message.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
// file: crates/common/game-realtime-transport-lib/src/message.rs
|
||||
// version: 1
|
||||
|
||||
/// Owned opaque binary payload carried by a realtime transport.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct TransportMessage {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl TransportMessage {
|
||||
/// Creates a transport message from owned bytes.
|
||||
#[must_use]
|
||||
pub fn new(bytes: Vec<u8>) -> Self {
|
||||
return Self { bytes };
|
||||
}
|
||||
|
||||
/// Borrows the opaque payload bytes.
|
||||
#[must_use]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
return self.bytes.as_slice();
|
||||
}
|
||||
|
||||
/// Consumes the message and returns its owned payload bytes.
|
||||
#[must_use]
|
||||
pub fn into_bytes(self) -> Vec<u8> {
|
||||
return self.bytes;
|
||||
}
|
||||
|
||||
/// Returns whether the payload is empty.
|
||||
#[must_use]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
return self.bytes.is_empty();
|
||||
}
|
||||
|
||||
/// Returns the payload length in bytes.
|
||||
#[must_use]
|
||||
pub fn len(&self) -> usize {
|
||||
return self.bytes.len();
|
||||
}
|
||||
}
|
||||
|
||||
/// Outcome of one successful transport receive operation.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum TransportReceive {
|
||||
/// One opaque binary message was received.
|
||||
Message(crate::TransportMessage),
|
||||
/// The remote peer completed a clean transport-level close.
|
||||
Closed,
|
||||
}
|
||||
Reference in New Issue
Block a user