teanet-rust/src/lib.rs
2026-08-04 21:03:51 +03:00

286 lines
9.0 KiB
Rust

use std::{
collections::VecDeque,
net::{SocketAddr, UdpSocket},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
mpsc::{Receiver, channel},
},
thread::spawn,
time::Duration,
};
use serde::{Serialize, de::DeserializeOwned};
use thiserror::*;
use crate::{
connections::{Connection, ConnectionError, ConnectionManager},
listener::{Listener, ListenerMessage},
package::CloseReason,
stats::NetStats,
};
pub mod connections;
pub(crate) mod listener;
pub mod package;
pub mod stats;
/// Error for the Peer
#[derive(Error, Debug)]
pub enum PeerError {
#[error("Error binding to port: {0}")]
BindError(std::io::Error),
#[error("Error listening to messages: {0}")]
ListenerError(std::io::Error),
}
/// Possible messages from occurring events from the peer
pub enum PeerMessage<T: Clone + Serialize + DeserializeOwned + Send + Sync + 'static> {
/// A new connection has been connected
NewConnection(Connection<T>),
/// An existing connection has disconnected, with an optional error
Disconnected(Connection<T>, Option<ConnectionError>, CloseReason),
/// The Peer has been closed
Closed,
/// A single message of type T
Message(Connection<T>, T),
}
/// Optional configuration available for peers, mainly configuration of
/// different intervals
#[derive(Debug, Clone)]
pub struct PeerConfig {
ping_interval: Duration,
timeout: Duration,
disconnect_timeout: Duration,
message_retry: Duration,
identifier: String,
}
impl Default for PeerConfig {
fn default() -> Self {
Self {
ping_interval: Duration::from_millis(100),
timeout: Duration::from_millis(2000),
disconnect_timeout: Duration::from_millis(500),
message_retry: Duration::from_millis(100),
identifier: "ExamplePeer".to_string(),
}
}
}
impl PeerConfig {
/// Set the desired interval between "ping"s
pub fn with_ping_interval(self, interval: Duration) -> PeerConfig {
PeerConfig {
ping_interval: interval,
..self
}
}
/// Set the length of timeout; that is to say the duration of time which is
/// acceptable to occur between pings before a Timeout-error occurs
pub fn with_timeout(self, timeout: Duration) -> PeerConfig {
PeerConfig { timeout, ..self }
}
/// Set the length of time that is awaited since the last "Closed" message
/// during disconnection before disconnection actually occurs. Should be
/// significantly higher than ping interval.
pub fn with_disconnect(self, timeout: Duration) -> PeerConfig {
PeerConfig {
disconnect_timeout: timeout,
..self
}
}
/// Sets the duration which is awaited before any queued reliable messages
/// are sent again. This timer is also reset every time any new messages are
/// sent manually.
pub fn with_retry(self, retry: Duration) -> PeerConfig {
PeerConfig {
message_retry: retry,
..self
}
}
/// Sets the identifier string which must be same for both connecting peers
/// in order for connection to succeed.
pub fn with_identifier(self, ident: String) -> PeerConfig {
PeerConfig {
identifier: ident,
..self
}
}
}
pub struct Peer<T: std::fmt::Debug + Clone + Serialize + DeserializeOwned + Send + Sync + 'static> {
connection_mgr: ConnectionManager<T>,
closed: Arc<AtomicBool>,
receiver: Receiver<ListenerMessage<T>>,
messages: VecDeque<PeerMessage<T>>,
}
impl<T: std::fmt::Debug + Clone + Serialize + DeserializeOwned + Send + Sync + 'static> Drop
for Peer<T>
{
fn drop(&mut self) {
self.closed.store(true, Ordering::Relaxed);
}
}
impl<T: std::fmt::Debug + Clone + Serialize + DeserializeOwned + Send + Sync + 'static> Peer<T> {
/// Bind given port to listen to incoming messages. Creates a new Peer that
/// can establish new connections.
pub fn listen(port: Option<u16>, config: PeerConfig) -> Result<Peer<T>, PeerError> {
let socket = Arc::new(
UdpSocket::bind(SocketAddr::from(([0, 0, 0, 0], port.unwrap_or(0))))
.map_err(|e| PeerError::BindError(e))?,
);
let closed = Arc::new(AtomicBool::new(false));
let (sender, receiver) = channel();
spawn({
let socket = socket.clone();
let closed = closed.clone();
if let Err(e) = socket.set_nonblocking(true) {
sender.send(ListenerMessage::Error(e)).ok();
}
move || {
let mut listener = Listener::new(socket, sender);
while !closed.load(Ordering::Relaxed) {
listener.poll();
}
}
});
Ok(Peer {
connection_mgr: ConnectionManager::new(socket, config.clone()),
closed,
receiver,
messages: VecDeque::new(),
})
}
/// Connect the peer to the given address.
pub fn connect_to(&mut self, addr: SocketAddr) {
self.connection_mgr.connect_to(addr);
}
/// Send pings and poll for events from the listener thread. Returns
/// possible events, such as connections and messages. Should be called as
/// often as possible.
#[must_use]
pub fn poll(&mut self) -> Result<Option<PeerMessage<T>>, PeerError> {
if self.connection_mgr.udp.is_closed() {
if self.closed.load(Ordering::Acquire) {
self.messages.push_back(PeerMessage::Closed);
}
self.closed.store(true, Ordering::Release);
}
self.connection_mgr.send_pings();
self.connection_mgr.send_queued_messages();
let mut msg;
while {
msg = match self.receiver.try_recv() {
Ok(msg) => Some(msg),
Err(_) => None,
};
msg.is_some()
} {
match msg.unwrap() {
ListenerMessage::Package(package, socket_addr, bytes) => {
self.messages.extend(self.connection_mgr.handle_package(
package,
&socket_addr,
bytes,
));
}
ListenerMessage::PackageError(listener_error, socket_addr) => {
println!("Error: {}", listener_error);
self.connection_mgr.error_connection(
&socket_addr,
ConnectionError::ListenerError(listener_error),
);
}
ListenerMessage::Error(error) => {
println!("Error {}", error);
self.close();
return Err(PeerError::ListenerError(error));
}
}
}
self.connection_mgr.close_silent_connections();
self.messages
.extend(self.connection_mgr.purge_old_connections());
Ok(self.messages.pop_front())
}
/// Send a reliable message, which is retried until the remote peer
/// acknowledges it.
pub fn send_reliable(&mut self, to: &SocketAddr, message: T) {
self.connection_mgr.send(to, message, true);
}
/// Sends an unreliable message, which is never retried again.
pub fn send_unreliable(&mut self, to: &SocketAddr, message: T) {
self.connection_mgr.send(to, message, false);
}
/// Send a reliable message to every connection currently connected
pub fn broadcast_reliable(&mut self, message: T) {
for connection in self.connections() {
self.connection_mgr
.send(&connection.address, message.clone(), true);
}
}
/// Send an unreliable message to every connection currently connected
pub fn broadcast_unreliable(&mut self, message: T) {
for connection in self.connections() {
self.connection_mgr
.send(&connection.address, message.clone(), false);
}
}
/// Close the Peer, disconnecting all connections.
pub fn close(&mut self) {
self.connection_mgr.close();
}
pub fn close_connection(&mut self, addr: &SocketAddr, reason: CloseReason) {
self.connection_mgr.close_connection(addr, reason);
}
/// List of all current connections
pub fn connections(&self) -> Vec<Connection<T>> {
self.connection_mgr.connections()
}
pub fn set_accepting_connections(&mut self, accepting: bool) {
self.connection_mgr.set_accepting_connections(accepting);
}
pub fn statistics(&self) -> NetStats {
let conns = self.connection_mgr.connections();
let all_stats = conns.iter().map(|c| c.statistics());
let mut total_stats = NetStats::default();
for stats in all_stats {
total_stats.bytes_rx += stats.bytes_rx;
total_stats.bytes_tx += stats.bytes_tx;
total_stats.messages_expected += stats.messages_expected;
total_stats.messages_received += stats.messages_received;
}
total_stats
}
}