add display names which currently do nothing

main
_ 2025-02-24 04:45:39 +00:00
parent c4de3ad00d
commit 54560e118f
5 changed files with 78 additions and 25 deletions

View File

@ -1,6 +1,7 @@
use crate::prelude::*; use crate::prelude::*;
pub(crate) struct Args { pub(crate) struct Args {
pub(crate) name: String,
pub(crate) period_ms: u32, pub(crate) period_ms: u32,
pub(crate) port: u16, pub(crate) port: u16,
} }
@ -8,6 +9,7 @@ pub(crate) struct Args {
impl Default for Args { impl Default for Args {
fn default() -> Self { fn default() -> Self {
Self { Self {
name: "anon".to_string(),
period_ms: 1_000, period_ms: 1_000,
port: 9000, port: 9000,
} }
@ -27,7 +29,7 @@ impl App {
let mut timer = tokio::time::interval(Duration::from_millis(args.period_ms.into())); let mut timer = tokio::time::interval(Duration::from_millis(args.period_ms.into()));
timer.set_missed_tick_behavior(MissedTickBehavior::Skip); timer.set_missed_tick_behavior(MissedTickBehavior::Skip);
Ok(Self { Ok(Self {
client: Default::default(), client: Client::new(args.name)?,
stream, stream,
timer, timer,
}) })
@ -88,27 +90,49 @@ struct Client {
} }
impl Client { impl Client {
fn new(name: String) -> Result<Self> {
let mut this = Self {
outbox: Default::default(),
sequence: 0,
};
this.handle_set_name(name)?;
Ok(this)
}
fn enqueue(&mut self, msg: &ToServer) -> Result<()> {
if !self.outbox.is_empty() {
bail!("Dropped message, outbox is full");
}
let frame = rmp_serde::to_vec(&msg)?;
self.outbox.push_back(frame.into());
Ok(())
}
fn handle_frame(&self, frame: Bytes) -> Result<()> { fn handle_frame(&self, frame: Bytes) -> Result<()> {
match rmp_serde::from_slice(&frame)? { let ToClient { id, name, event } = rmp_serde::from_slice(&frame)?;
ToClient::ChatLine { id, line } => tracing::info!(?id, ?line), match event {
ToClient::ClientConnected { id } => tracing::info!(?id, "Connected"), ToClientEvent::ChatLine { line } => tracing::info!(?name, ?line),
ToClient::ClientDisconnected { id } => tracing::info!(?id, "Disconnected"), ToClientEvent::Connected => tracing::info!(?id, "Connected"),
ToClientEvent::Disconnected => tracing::info!(?id, ?name, "Disconnected"),
ToClientEvent::NameChanged { old_name } => {
tracing::info!(?id, ?old_name, new_name = name, "Name changed")
}
} }
Ok(()) Ok(())
} }
fn handle_timeout(&mut self) -> Result<()> { fn handle_set_name(&mut self, name: String) -> Result<()> {
if !self.outbox.is_empty() { self.enqueue(&ToServer::SetName { name })
bail!("Dropped message, outbox is full");
} }
fn handle_timeout(&mut self) -> Result<()> {
let msg = ToServer::ChatLine { let msg = ToServer::ChatLine {
line: "There was a time, in the era of great chaos, when the Earth and the Moon were at war with each other. A daredevil from the Moon piloted a bizarre aircraft. It was feared, and because of its shape, called EINHANDER.".to_string(), line: "There was a time, in the era of great chaos, when the Earth and the Moon were at war with each other. A daredevil from the Moon piloted a bizarre aircraft. It was feared, and because of its shape, called EINHANDER.".to_string(),
sequence: self.sequence, sequence: self.sequence,
}; };
let frame = rmp_serde::to_vec(&msg)?;
self.outbox.push_back(frame.into());
self.sequence += 1; self.sequence += 1;
self.enqueue(&msg)?;
Ok(()) Ok(())
} }

View File

@ -24,6 +24,9 @@ impl Args {
loop { loop {
match args.next().as_deref() { match args.next().as_deref() {
None => break, None => break,
Some("--name") => {
client_args.name = args.next().context("Missing arg")?.to_string()
}
Some("--period-ms") => { Some("--period-ms") => {
client_args.period_ms = client_args.period_ms =
u32::from_str(&args.next().context("Missing arg")?)? u32::from_str(&args.next().context("Missing arg")?)?

View File

@ -2,13 +2,22 @@ use crate::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub(crate) enum ToClient { pub(crate) struct ToClient {
ChatLine { id: Id, line: String }, pub(crate) id: Id,
ClientConnected { id: Id }, pub(crate) name: String,
ClientDisconnected { id: Id }, pub(crate) event: ToClientEvent,
}
#[derive(Deserialize, Serialize)]
pub(crate) enum ToClientEvent {
ChatLine { line: String },
Connected,
Disconnected,
NameChanged { old_name: String },
} }
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
pub(crate) enum ToServer { pub(crate) enum ToServer {
ChatLine { line: String, sequence: u64 }, ChatLine { line: String, sequence: u64 },
SetName { name: String },
} }

View File

@ -1,4 +1,4 @@
pub(crate) use crate::messages::{ToClient, ToServer}; pub(crate) use crate::messages::{ToClient, ToClientEvent, ToServer};
pub use anyhow::{Context as _, Result, bail}; pub use anyhow::{Context as _, Result, bail};
pub use bytes::Bytes; pub use bytes::Bytes;
pub use futures_core::stream::Stream; pub use futures_core::stream::Stream;

View File

@ -104,23 +104,30 @@ impl Server {
} }
fn handle_client_disconnected(&mut self, id: Id) -> Result<()> { fn handle_client_disconnected(&mut self, id: Id) -> Result<()> {
self.clients.remove(&id); let client = self
self.broadcast(&ToClient::ClientDisconnected { id })?; .clients
.remove(&id)
.context("Can't remove client who isn't there")?;
self.broadcast(&ToClient {
id,
name: client.name,
event: ToClientEvent::Disconnected,
})?;
Ok(()) Ok(())
} }
fn handle_client_frame(&mut self, id: Id, frame: Bytes) -> Result<()> { fn handle_client_frame(&mut self, id: Id, frame: Bytes) -> Result<()> {
let msg = { let (name, event) = {
let client = self let client = self
.clients .clients
.get_mut(&id) .get_mut(&id)
.context("Logic error: Stream has no associated client")?; .context("Logic error: Stream has no associated client")?;
let Some(msg) = client.handle_frame(frame).context("client.handle_frame")? else { let Some(event) = client.handle_frame(frame).context("client.handle_frame")? else {
return Ok(()); return Ok(());
}; };
msg (client.name.clone(), event)
}; };
self.broadcast(&msg)?; self.broadcast(&ToClient { id, name, event })?;
Ok(()) Ok(())
} }
@ -129,6 +136,7 @@ impl Server {
self.next_client_id += 1; self.next_client_id += 1;
let client = Client { let client = Client {
id, id,
name: "anon".to_string(),
outbox: Default::default(), outbox: Default::default(),
sequence: 0, sequence: 0,
}; };
@ -137,8 +145,12 @@ impl Server {
total = self.clients.len(), total = self.clients.len(),
"Accepted client" "Accepted client"
); );
self.broadcast(&ToClient {
id,
name: client.name.clone(),
event: ToClientEvent::Connected,
})?;
self.clients.insert(id, client); self.clients.insert(id, client);
self.broadcast(&ToClient::ClientConnected { id })?;
Ok(id) Ok(id)
} }
@ -153,12 +165,13 @@ impl Server {
struct Client { struct Client {
id: u64, id: u64,
name: String,
outbox: VecDeque<Bytes>, outbox: VecDeque<Bytes>,
sequence: u64, sequence: u64,
} }
impl Client { impl Client {
fn handle_frame(&mut self, frame: Bytes) -> Result<Option<ToClient>> { fn handle_frame(&mut self, frame: Bytes) -> Result<Option<ToClientEvent>> {
match rmp_serde::from_slice(&frame)? { match rmp_serde::from_slice(&frame)? {
ToServer::ChatLine { line, sequence } => { ToServer::ChatLine { line, sequence } => {
if sequence != self.sequence { if sequence != self.sequence {
@ -170,7 +183,11 @@ impl Client {
bail!("Sequence mismatch"); bail!("Sequence mismatch");
} }
self.sequence += 1; self.sequence += 1;
Ok(Some(ToClient::ChatLine { id: self.id, line })) Ok(Some(ToClientEvent::ChatLine { line }))
}
ToServer::SetName { name } => {
let old_name = std::mem::replace(&mut self.name, name);
Ok(Some(ToClientEvent::NameChanged { old_name }))
} }
} }
} }