101 lines
2.9 KiB
Rust
101 lines
2.9 KiB
Rust
use std::time::Duration;
|
|
|
|
use bevy::prelude::*;
|
|
use uuid::Uuid;
|
|
|
|
use super::{
|
|
packet::{InboundPacket, OutboundPacket, Packet},
|
|
peer::{Peer, PeerChangeEvent, PeerMap, PeerReceiveTiming, PeerSendTiming},
|
|
queues::{NetworkReceive, NetworkSend},
|
|
};
|
|
|
|
pub fn handle_network_input(
|
|
from_socket: Res<NetworkReceive>,
|
|
peer_map: Res<PeerMap>,
|
|
mut peers: Query<(&Peer, &mut PeerReceiveTiming)>,
|
|
mut to_app: EventWriter<InboundPacket>,
|
|
time: Res<Time>,
|
|
mut change_peer: EventWriter<PeerChangeEvent>,
|
|
) -> Result {
|
|
for (mut message, address) in from_socket.iter() {
|
|
if message.len() < 16 {
|
|
return Err(format!(
|
|
"Message of length {} is not large enough to contain UUID",
|
|
message.len()
|
|
)
|
|
.into());
|
|
}
|
|
let uuid = Uuid::from_slice(message.split_off(message.len() - 16).as_slice())?;
|
|
to_app.write(InboundPacket(Packet::new(message, uuid)));
|
|
if let Some(peer_id) = peer_map.get(&uuid) {
|
|
let (peer, mut last) = peers.get_mut(*peer_id)?;
|
|
last.update(&time);
|
|
if address == peer.addr {
|
|
continue;
|
|
}
|
|
}
|
|
change_peer.write(PeerChangeEvent::new(uuid, Some(address)));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn handle_network_output(
|
|
mut from_app: EventReader<OutboundPacket>,
|
|
peer_map: Res<PeerMap>,
|
|
mut peers: Query<(&Peer, &mut PeerSendTiming)>,
|
|
config: Res<Config>,
|
|
to_socket: Res<NetworkSend>,
|
|
time: Res<Time>,
|
|
) -> Result {
|
|
for packet in from_app.read() {
|
|
let peer_id = peer_map.try_get(&packet.0.peer)?;
|
|
let (peer, mut last) = peers.get_mut(*peer_id)?;
|
|
// Append our UUID for client identification
|
|
let message = [packet.0.message.as_slice(), config.id.as_bytes()].concat();
|
|
to_socket.send(message, peer.addr)?;
|
|
last.update(&time);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
const TIMEOUT: Duration = Duration::from_secs(10);
|
|
|
|
pub fn heartbeat(
|
|
peers: Query<(&Peer, &PeerSendTiming)>,
|
|
time: Res<Time>,
|
|
mut outbound: EventWriter<OutboundPacket>,
|
|
) {
|
|
for (peer, last) in peers {
|
|
// Allow for 2 consecutive missed heartbeats without timing out
|
|
if last.time() + TIMEOUT / 3 > time.elapsed() {
|
|
continue;
|
|
}
|
|
outbound.write(OutboundPacket(Packet::new(Vec::new(), peer.uuid)));
|
|
}
|
|
}
|
|
|
|
pub fn timeouts(
|
|
peers: Query<(&Peer, &PeerReceiveTiming)>,
|
|
time: Res<Time>,
|
|
mut delete: EventWriter<PeerChangeEvent>,
|
|
) {
|
|
for (peer, last) in peers {
|
|
if let Some(previous) = last.time() {
|
|
if previous + TIMEOUT < time.elapsed() {
|
|
warn!("Peer {} timed out", peer.uuid);
|
|
delete.write(PeerChangeEvent::new(peer.uuid, None));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Resource)]
|
|
pub struct Config {
|
|
pub id: Uuid,
|
|
}
|
|
|
|
impl Config {
|
|
pub fn new() -> Self {
|
|
Self { id: Uuid::new_v4() }
|
|
}
|
|
}
|