smo-server/src/server/prox.rs

548 lines
15 KiB
Rust
Raw Normal View History

2024-12-18 16:34:50 -05:00
use std::sync::Arc;
2024-12-17 19:44:37 -05:00
use packet::{
Event,
Event_variants::{Answer, Candidate, Offer},
};
2025-01-02 20:03:58 -05:00
use tokio::io::{AsyncReadExt, AsyncWriteExt};
2024-12-18 16:34:50 -05:00
use tracing::{error, info, info_span, trace, warn, Instrument};
2024-12-20 05:32:26 -05:00
use wtransport::endpoint::IncomingSession;
2024-12-17 19:44:37 -05:00
use xtra::{Actor, Address, Handler, Mailbox};
2024-12-18 16:34:50 -05:00
use zerocopy::{FromZeros, IntoBytes};
2024-12-17 19:44:37 -05:00
2024-12-21 06:35:44 -05:00
use crate::{packet::CLIENT_NAME_SIZE, protocol::String};
use super::{
listeners, ChangedStage, Manager, PlayerConnected, PlayerDisconnected, PlayerMoved, RequestState, UuidString,
};
2024-12-17 19:44:37 -05:00
pub struct ProximityPlayer {
id: UuidString,
2024-12-21 06:35:44 -05:00
name: String<CLIENT_NAME_SIZE>,
2025-01-02 20:03:58 -05:00
global_speak: bool,
2024-12-18 16:34:50 -05:00
send: wtransport::SendStream,
connection: Arc<wtransport::Connection>,
2024-12-17 19:44:37 -05:00
}
impl ProximityPlayer {
pub fn spawn(session: IncomingSession, manager: Address<Manager>) {
tokio::spawn(
async move {
trace!("proximity chat client connected");
2024-12-18 16:34:50 -05:00
let connection = Arc::new(
session.await.expect("failed to acknowledge session").accept().await.expect("failed to accept session"),
);
2024-12-17 19:44:37 -05:00
let (mut send, mut recv) = connection.accept_bi().await.expect("failed to start channel");
let mut id = UuidString::new_zeroed();
recv.read_exact(id.as_mut_bytes()).await.expect("failed to read uuid");
2024-12-21 06:35:44 -05:00
let mut name = String::new_zeroed();
recv.read_exact(name.as_mut_bytes()).await.expect("failed to read name");
2025-01-02 20:03:58 -05:00
let global_speak = recv.read_u8().await.expect("failed to read global speak state") != 0;
2024-12-17 19:44:37 -05:00
let span = info_span!("", %id);
2024-12-18 16:34:50 -05:00
span.in_scope(|| trace!("uuid parsed"));
2024-12-21 06:35:44 -05:00
info!(parent: &span, "connected as {name}");
2024-12-17 19:44:37 -05:00
let state = manager.send(RequestState).await.unwrap();
send.write_u8(state.len() as u8).await.expect("failed to write length");
for player in state.values() {
2024-12-22 00:37:16 -05:00
trace!(parent: &span, "sending player {player:?}");
2024-12-18 16:34:50 -05:00
send.write_all(player.as_bytes()).await.expect("failed to write player");
}
{
let listeners = listeners().read().await;
send.write_u32_le(listeners.len() as u32).await.expect("failed to write peer length");
2024-12-21 06:35:44 -05:00
for (id, listener) in listeners.iter() {
2025-01-02 20:03:58 -05:00
if let Ok((name, global_speak)) = listener.send(GetStartInfo).await {
2024-12-21 06:35:44 -05:00
send.write_all(id.as_bytes()).await.expect("failed to write peer id");
send.write_all(name.as_bytes()).await.expect("failed to write peer name");
2025-01-02 20:03:58 -05:00
send.write_all(&[if global_speak { 1 } else { 0 }]).await.expect("failed to write peer global speaking status");
2024-12-21 06:35:44 -05:00
}
2024-12-18 16:34:50 -05:00
}
2024-12-17 19:44:37 -05:00
}
let (address, mailbox) = Mailbox::unbounded();
2024-12-18 16:34:50 -05:00
listeners().write().await.insert(id, address.clone());
tokio::spawn({
let connection = connection.clone();
let address = address.clone();
2024-12-18 16:34:50 -05:00
async move {
connection.closed().await;
let _ = address.send(Stop).await;
}
.instrument(span.clone())
});
tokio::spawn(
async move {
loop {
match packet::Event::deserialize(&mut recv).await {
Ok(event) => {
let _ = address.send(event).detach().await;
}
Err(error) => {
error!("error while deserializing: {error:?}");
let _ = address.send(Stop).await;
return;
}
};
}
}
.instrument(span.clone()),
);
2024-12-21 06:35:44 -05:00
xtra::run(
mailbox,
ProximityPlayer {
id,
name,
2025-01-02 20:03:58 -05:00
global_speak,
2024-12-21 06:35:44 -05:00
send,
connection,
},
)
.instrument(span)
.await;
2024-12-17 19:44:37 -05:00
}
.in_current_span(),
);
}
}
impl Actor for ProximityPlayer {
type Stop = ();
2024-12-18 16:34:50 -05:00
async fn started(&mut self, _: &Mailbox<Self>) -> Result<(), Self::Stop> {
2024-12-21 06:35:44 -05:00
let changed_event = packet::Packet {
kind: packet::Kind::PeerConnectionChanged,
data: packet::PeerConnectionChanged {
id: FromZeros::new_zeroed(),
connected: true,
name: FromZeros::new_zeroed(),
2025-01-02 20:03:58 -05:00
global_speak: false
2024-12-21 06:35:44 -05:00
},
};
for (id, listener) in listeners().write().await.iter() {
if *id != self.id {
2025-01-02 20:03:58 -05:00
if let Ok(Ok((name, global_speak))) = listener
2024-12-18 16:34:50 -05:00
.send(PeerConnectionChanged {
id: self.id,
connected: true,
2024-12-21 06:35:44 -05:00
name: self.name,
2025-01-02 20:03:58 -05:00
global_speak: self.global_speak,
2024-12-18 16:34:50 -05:00
})
2024-12-21 06:35:44 -05:00
.await
{
let personalized = packet::Packet {
data: packet::PeerConnectionChanged {
id: *id,
name,
2025-01-02 20:03:58 -05:00
global_speak,
2024-12-21 06:35:44 -05:00
..changed_event.data
},
..changed_event
};
if let Err(error) = self.send.write_all(personalized.as_bytes()).await {
error!("error while sending peer info {error}");
return Err(());
}
}
2024-12-18 16:34:50 -05:00
}
}
Ok(())
}
2024-12-17 19:44:37 -05:00
async fn stopped(self) -> Self::Stop {
listeners().write().await.remove(&self.id);
2024-12-18 16:34:50 -05:00
for listener in listeners().write().await.iter() {
if *listener.0 != self.id {
let _ = listener
.1
.send(PeerConnectionChanged {
id: self.id,
connected: false,
2024-12-21 06:35:44 -05:00
name: self.name,
2025-01-02 20:03:58 -05:00
global_speak: false,
2024-12-18 16:34:50 -05:00
})
.detach()
.await;
}
}
2024-12-17 19:44:37 -05:00
}
}
2024-12-18 16:34:50 -05:00
struct Stop;
impl Handler<Stop> for ProximityPlayer {
type Return = ();
async fn handle(&mut self, _: Stop, ctx: &mut xtra::Context<Self>) -> Self::Return {
info!("connection closed (stopped)");
ctx.stop_self();
}
}
2025-01-02 20:03:58 -05:00
struct GetStartInfo;
impl Handler<GetStartInfo> for ProximityPlayer {
type Return = (String<CLIENT_NAME_SIZE>, bool);
2024-12-21 06:35:44 -05:00
2025-01-02 20:03:58 -05:00
async fn handle(&mut self, _: GetStartInfo, _: &mut xtra::Context<Self>) -> Self::Return {
(self.name, self.global_speak)
2024-12-21 06:35:44 -05:00
}
}
impl Handler<Event> for ProximityPlayer {
type Return = ();
async fn handle(&mut self, message: Event, _: &mut xtra::Context<Self>) -> Self::Return {
async fn send_event<T: Send + 'static>(id: UuidString, value: T)
where
ProximityPlayer: Handler<T>,
{
if let Some(listener) = listeners().read().await.get(&id) {
if let Err(error) = listener.send(value).detach().await {
warn!("listener {id} is dead: {error}")
}
} else {
warn!("sending offer to dead listener {id}");
}
}
match message {
Event::Offer(offer) => {
send_event(
offer.id,
Offer {
id: self.id,
sdp: offer.sdp,
},
)
.await;
}
Event::Answer(answer) => {
send_event(
answer.id,
Answer {
id: self.id,
sdp: answer.sdp,
},
)
.await;
}
Event::Candidate(candidate) => {
send_event(
candidate.id,
Candidate {
id: self.id,
candidate: candidate.candidate,
},
)
.await;
}
2024-12-21 06:35:44 -05:00
Event::TargetChanged(changed) => {
self.name = changed.name;
}
}
}
}
impl Handler<Offer> for ProximityPlayer {
type Return = ();
2024-12-21 06:35:44 -05:00
async fn handle(&mut self, message: Offer, ctx: &mut xtra::Context<Self>) -> Self::Return {
if let Err(error) = Event::Offer(message).serialize(&mut self.send).await {
error!("error while sending offer {error}");
ctx.stop_self();
}
}
}
impl Handler<Answer> for ProximityPlayer {
type Return = ();
2024-12-21 06:35:44 -05:00
async fn handle(&mut self, message: Answer, ctx: &mut xtra::Context<Self>) -> Self::Return {
if let Err(error) = Event::Answer(message).serialize(&mut self.send).await {
error!("error while sending player move {error}");
ctx.stop_self();
}
}
}
impl Handler<Candidate> for ProximityPlayer {
type Return = ();
2024-12-21 06:35:44 -05:00
async fn handle(&mut self, message: Candidate, ctx: &mut xtra::Context<Self>) -> Self::Return {
if let Err(error) = Event::Candidate(message).serialize(&mut self.send).await {
error!("error while sending candidate {error}");
ctx.stop_self();
}
}
}
2024-12-18 16:34:50 -05:00
struct PeerConnectionChanged {
id: UuidString,
2024-12-18 16:34:50 -05:00
connected: bool,
2024-12-21 06:35:44 -05:00
name: String<CLIENT_NAME_SIZE>,
2025-01-02 20:03:58 -05:00
global_speak: bool,
2024-12-18 16:34:50 -05:00
}
impl Handler<PeerConnectionChanged> for ProximityPlayer {
2025-01-02 20:03:58 -05:00
type Return = Result<(String<CLIENT_NAME_SIZE>, bool), ()>;
2024-12-18 16:34:50 -05:00
async fn handle(&mut self, message: PeerConnectionChanged, ctx: &mut xtra::Context<Self>) -> Self::Return {
let event = packet::Packet {
kind: packet::Kind::PeerConnectionChanged,
data: packet::PeerConnectionChanged {
2024-12-20 05:32:26 -05:00
id: message.id,
2024-12-18 16:34:50 -05:00
connected: message.connected,
2024-12-21 06:35:44 -05:00
name: message.name,
2025-01-02 20:03:58 -05:00
global_speak: message.global_speak
2024-12-18 16:34:50 -05:00
},
};
if let Err(error) = self.send.write_all(event.as_bytes()).await {
error!("error while sending player move {error}");
ctx.stop_self();
2024-12-21 06:35:44 -05:00
return Err(());
2024-12-18 16:34:50 -05:00
}
2024-12-21 06:35:44 -05:00
2025-01-02 20:03:58 -05:00
Ok((self.name, self.global_speak))
2024-12-18 16:34:50 -05:00
}
}
2024-12-21 06:35:44 -05:00
2024-12-17 19:44:37 -05:00
impl Handler<PlayerConnected> for ProximityPlayer {
type Return = ();
2024-12-18 16:34:50 -05:00
async fn handle(&mut self, message: PlayerConnected, ctx: &mut xtra::Context<Self>) -> Self::Return {
let event = packet::Packet {
kind: packet::Kind::Connected,
data: packet::Connected {
id: message.id as u32,
name: message.name,
},
};
if let Err(error) = self.send.write_all(event.as_bytes()).await {
error!("error while sending player move {error}");
ctx.stop_self();
}
2024-12-17 19:44:37 -05:00
}
}
impl Handler<PlayerDisconnected> for ProximityPlayer {
type Return = ();
2024-12-18 16:34:50 -05:00
async fn handle(&mut self, message: PlayerDisconnected, ctx: &mut xtra::Context<Self>) -> Self::Return {
warn!("todo: implement player disconnected");
let event = packet::Packet {
kind: packet::Kind::Disconnected,
data: packet::Disconnected { id: message.id as u32 },
};
if let Err(error) = self.send.write_all(event.as_bytes()).await {
error!("error while sending player move {error}");
ctx.stop_self();
}
2024-12-17 19:44:37 -05:00
}
}
impl Handler<PlayerMoved> for ProximityPlayer {
type Return = ();
2024-12-18 16:34:50 -05:00
async fn handle(&mut self, message: PlayerMoved, ctx: &mut xtra::Context<Self>) -> Self::Return {
let event = packet::Packet {
kind: packet::Kind::Moved,
data: packet::Moved {
id: message.id as u32,
position: message.position,
},
};
if let Err(error) = self.connection.send_datagram(event.as_bytes()) {
error!("error while sending player move {error}");
ctx.stop_self();
}
2024-12-17 19:44:37 -05:00
}
}
impl Handler<ChangedStage> for ProximityPlayer {
type Return = ();
2024-12-18 16:34:50 -05:00
async fn handle(&mut self, message: ChangedStage, ctx: &mut xtra::Context<Self>) -> Self::Return {
let event = packet::Packet {
kind: packet::Kind::StageChanged,
data: packet::StageChanged {
id: message.id as u32,
stage_name: message.stage,
},
};
if let Err(error) = self.send.write_all(event.as_bytes()).await {
error!("error while sending player move {error}");
ctx.stop_self();
}
}
}
pub mod packet {
2024-12-20 05:32:26 -05:00
use std::string::String as StdString;
use anyhow::bail;
use newtype_enum::newtype_enum;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
2024-12-20 05:32:26 -05:00
use wtransport::{RecvStream, SendStream};
use zerocopy::{FromZeros, Immutable, IntoBytes};
2024-12-21 06:35:44 -05:00
use Event_variants::{Answer, Candidate, Offer, TargetChanged};
2024-12-18 16:34:50 -05:00
use crate::{
packet::{CLIENT_NAME_SIZE, STAGE_GAME_NAME_SIZE},
protocol::String,
2024-12-21 06:35:44 -05:00
server::UuidString,
2024-12-18 16:34:50 -05:00
};
pub const HYP_UUID_SIZE: usize = 36;
2024-12-18 16:34:50 -05:00
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
pub struct Packet<T> {
pub kind: Kind,
pub data: T,
}
2024-12-21 06:35:44 -05:00
#[derive(Clone, Copy, IntoBytes, Immutable)]
2024-12-18 16:34:50 -05:00
#[repr(u8)]
pub enum Kind {
Connected = 0,
Disconnected = 1,
Moved = 2,
StageChanged = 3,
PeerConnectionChanged = 4,
Offer = 5,
Answer = 6,
Candidate = 7,
2024-12-18 16:34:50 -05:00
}
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
pub struct Connected {
pub id: u32,
pub name: String<CLIENT_NAME_SIZE>,
}
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
pub struct Disconnected {
pub id: u32,
}
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
pub struct Moved {
pub id: u32,
pub position: [f32; 3],
}
#[derive(IntoBytes, Immutable)]
#[repr(C, packed)]
pub struct StageChanged {
pub id: u32,
pub stage_name: String<STAGE_GAME_NAME_SIZE>,
}
2024-12-21 06:35:44 -05:00
#[derive(Clone, Copy, IntoBytes, Immutable)]
2024-12-18 16:34:50 -05:00
#[repr(C, packed)]
pub struct PeerConnectionChanged {
2024-12-21 06:35:44 -05:00
pub id: UuidString,
2024-12-18 16:34:50 -05:00
pub connected: bool,
2024-12-21 06:35:44 -05:00
pub name: String<CLIENT_NAME_SIZE>,
2025-01-02 20:03:58 -05:00
pub global_speak: bool,
2024-12-17 19:44:37 -05:00
}
#[newtype_enum]
#[derive(Debug)]
pub enum Event {
Offer {
2024-12-21 06:35:44 -05:00
pub id: UuidString,
pub sdp: StdString,
},
Answer {
2024-12-21 06:35:44 -05:00
pub id: UuidString,
pub sdp: StdString,
},
Candidate {
2024-12-21 06:35:44 -05:00
pub id: UuidString,
pub candidate: StdString,
},
2024-12-21 06:35:44 -05:00
TargetChanged {
pub name: String<CLIENT_NAME_SIZE>,
2025-01-02 20:03:58 -05:00
pub global_speak: bool,
2024-12-21 06:35:44 -05:00
},
}
impl Event {
pub async fn serialize(self, send: &mut SendStream) -> anyhow::Result<()> {
async fn write_string(send: &mut SendStream, string: StdString) -> anyhow::Result<()> {
send.write_u32_le(string.len() as u32).await?;
send.write_all(string.as_bytes()).await?;
Ok(())
}
match self {
2024-12-21 06:35:44 -05:00
Self::Offer(offer) => {
send.write_u8(Kind::Offer as u8).await?;
send.write_all(offer.id.as_bytes()).await?;
write_string(send, offer.sdp).await?;
}
2024-12-21 06:35:44 -05:00
Self::Answer(answer) => {
send.write_u8(Kind::Answer as u8).await?;
send.write_all(answer.id.as_bytes()).await?;
write_string(send, answer.sdp).await?;
}
2024-12-21 06:35:44 -05:00
Self::Candidate(candidate) => {
send.write_u8(Kind::Candidate as u8).await?;
send.write_all(candidate.id.as_bytes()).await?;
write_string(send, candidate.candidate).await?;
}
2024-12-21 06:35:44 -05:00
Self::TargetChanged(_) => unimplemented!(),
}
Ok(())
}
pub async fn deserialize(recv: &mut RecvStream) -> anyhow::Result<Self> {
async fn read_string(recv: &mut RecvStream) -> anyhow::Result<StdString> {
let size = recv.read_u32_le().await?;
let mut data = vec![0; size as usize];
recv.read_exact(&mut data).await?;
Ok(StdString::from_utf8(data)?)
}
async fn read_fixed_string<const N: usize>(recv: &mut RecvStream) -> anyhow::Result<String<N>> {
let mut str = String::new_zeroed();
recv.read_exact(str.as_mut_bytes()).await?;
Ok(str)
}
let kind = recv.read_u8().await?;
let event = match kind {
2024-12-21 06:35:44 -05:00
0 => Self::Offer(Offer {
id: read_fixed_string(recv).await?,
sdp: read_string(recv).await?,
}),
2024-12-21 06:35:44 -05:00
1 => Self::Answer(Answer {
id: read_fixed_string(recv).await?,
sdp: read_string(recv).await?,
}),
2024-12-21 06:35:44 -05:00
2 => Self::Candidate(Candidate {
id: read_fixed_string(recv).await?,
candidate: read_string(recv).await?,
}),
2024-12-21 06:35:44 -05:00
3 => Self::TargetChanged(TargetChanged {
name: read_fixed_string(recv).await?,
2025-01-02 20:03:58 -05:00
global_speak: recv.read_u8().await? != 0
2024-12-21 06:35:44 -05:00
}),
kind => bail!("invalid kind: {kind}"),
};
Ok(event)
}
}
2024-12-17 19:44:37 -05:00
}