[irc] used nonempty prefixed nicks in 353 reply (#9)

Reviewed-on: lavina/lavina#9
Co-authored-by: JustTestingV <JustTestingV@gmail.com>
Co-committed-by: JustTestingV <JustTestingV@gmail.com>
This commit is contained in:
JustTestingV 2023-09-15 16:33:25 +00:00 committed by Nikita Vilunov
parent 298245f3f5
commit 87d73af811
8 changed files with 58 additions and 14 deletions

7
Cargo.lock generated
View File

@ -761,6 +761,7 @@ dependencies = [
"hyper 1.0.0-rc.3", "hyper 1.0.0-rc.3",
"lazy_static", "lazy_static",
"nom", "nom",
"nonempty",
"prometheus", "prometheus",
"quick-xml", "quick-xml",
"regex", "regex",
@ -887,6 +888,12 @@ dependencies = [
"minimal-lexical", "minimal-lexical",
] ]
[[package]]
name = "nonempty"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aeaf4ad7403de93e699c191202f017118df734d3850b01e13a3a8b2e6953d3c9"
[[package]] [[package]]
name = "nu-ansi-term" name = "nu-ansi-term"
version = "0.46.0" version = "0.46.0"

View File

@ -19,6 +19,7 @@ prometheus = { version = "0.13.3", default-features = false }
regex = "1.7.1" regex = "1.7.1"
lazy_static = "1.4.0" lazy_static = "1.4.0"
nom = "7.1.3" nom = "7.1.3"
nonempty = "0.8.1"
tokio-rustls = "0.24.1" tokio-rustls = "0.24.1"
rustls-pemfile = "1.0.2" rustls-pemfile = "1.0.2"
quick-xml = { version = "0.30.0", features = ["async-tokio"] } quick-xml = { version = "0.30.0", features = ["async-tokio"] }

View File

@ -302,7 +302,7 @@ impl Player {
player_id, player_id,
connections: AnonTable::new(), connections: AnonTable::new(),
my_rooms: HashMap::new(), my_rooms: HashMap::new(),
banned_from: HashSet::from([RoomId::from("empty").unwrap()]), banned_from: HashSet::from([RoomId::from("Empty").unwrap()]),
rx, rx,
handle, handle,
rooms, rooms,

View File

@ -2,6 +2,8 @@ use std::collections::HashMap;
use std::net::SocketAddr; use std::net::SocketAddr;
use futures_util::future::join_all; use futures_util::future::join_all;
use nonempty::nonempty;
use nonempty::NonEmpty;
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry}; use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
use serde::Deserialize; use serde::Deserialize;
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter}; use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
@ -16,6 +18,7 @@ use crate::prelude::*;
use crate::protos::irc::client::{client_message, ClientMessage}; use crate::protos::irc::client::{client_message, ClientMessage};
use crate::protos::irc::server::{AwayStatus, ServerMessage, ServerMessageBody}; use crate::protos::irc::server::{AwayStatus, ServerMessage, ServerMessageBody};
use crate::protos::irc::{Chan, Recipient}; use crate::protos::irc::{Chan, Recipient};
use crate::protos::irc::user::PrefixedNick;
use crate::util::Terminator; use crate::util::Terminator;
#[cfg(test)] #[cfg(test)]
@ -666,22 +669,16 @@ async fn produce_on_join_cmd_messages(
} }
.write_async(writer) .write_async(writer)
.await?; .await?;
let mut members: String = if let Some(head) = room_info.members.first() { let prefixed_members: Vec<PrefixedNick> = room_info.members.iter().map(|member| PrefixedNick::from_player_id(member.clone())).collect();
head.as_inner().clone() let non_empty_members: NonEmpty<PrefixedNick> = NonEmpty::from_vec(prefixed_members).unwrap_or(nonempty![PrefixedNick::from_str(user.nickname.clone())]);
} else {
user.nickname.clone()
}.as_ref().into();
for i in &room_info.members[1..] {
members.push(' ');
members.push_str(i.as_inner());
}
ServerMessage { ServerMessage {
tags: vec![], tags: vec![],
sender: Some(config.server_name.clone()), sender: Some(config.server_name.clone()),
body: ServerMessageBody::N353NamesReply { body: ServerMessageBody::N353NamesReply {
client: user.nickname.clone(), client: user.nickname.clone(),
chan: chan.clone(), chan: chan.clone(),
members: members.into(), members: non_empty_members.into(),
}, },
} }
.write_async(writer) .write_async(writer)

View File

@ -1,6 +1,7 @@
//! Client-to-Server IRC protocol. //! Client-to-Server IRC protocol.
pub mod client; pub mod client;
pub mod server; pub mod server;
pub mod user;
use std::io::Result; use std::io::Result;
use crate::prelude::Str; use crate::prelude::Str;

View File

@ -1,7 +1,9 @@
use nonempty::NonEmpty;
use tokio::io::AsyncWrite; use tokio::io::AsyncWrite;
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
use super::*; use super::*;
use crate::protos::irc::user::PrefixedNick;
/// Server-to-client message. /// Server-to-client message.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@ -121,7 +123,7 @@ pub enum ServerMessageBody {
N353NamesReply { N353NamesReply {
client: Str, client: Str,
chan: Chan, chan: Chan,
members: Str, // TODO make this a non-empty list with prefixes members: NonEmpty<PrefixedNick>,
}, },
N366NamesReplyEnd { N366NamesReplyEnd {
client: Str, client: Str,
@ -284,7 +286,11 @@ impl ServerMessageBody {
writer.write_all(b" = ").await?; writer.write_all(b" = ").await?;
chan.write_async(writer).await?; chan.write_async(writer).await?;
writer.write_all(b" :").await?; writer.write_all(b" :").await?;
writer.write_all(members.as_bytes()).await?; for member in members {
writer.write_all(member.prefix.to_string().as_bytes()).await?;
writer.write_all(member.nick.as_bytes()).await?;
writer.write_all(b" ").await?;
}
} }
ServerMessageBody::N366NamesReplyEnd { client, chan } => { ServerMessageBody::N366NamesReplyEnd { client, chan } => {
writer.write_all(b"366 ").await?; writer.write_all(b"366 ").await?;

32
src/protos/irc/user.rs Normal file
View File

@ -0,0 +1,32 @@
use super::*;
use std::fmt;
use crate::core::player::PlayerId;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Prefix {
Empty,
}
impl fmt::Display for Prefix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Prefix::Empty => write!(f, ""),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PrefixedNick {
pub prefix: Prefix,
pub nick: Str,
}
impl PrefixedNick {
pub fn from_str(nick: Str) -> PrefixedNick {
PrefixedNick { prefix: Prefix::Empty, nick }
}
pub fn from_player_id(id: PlayerId) -> PrefixedNick {
PrefixedNick { prefix: Prefix::Empty, nick: id.into_inner() }
}
}

View File

@ -21,7 +21,7 @@ impl<V> AnonTable<V> {
pub fn insert(&mut self, value: V) -> Key { pub fn insert(&mut self, value: V) -> Key {
let id = self.next; let id = self.next;
self.next += 1; self.next += 1;
self.inner.insert(id, value); // should be always empty self.inner.insert(id, value); // should be always Empty
Key(id) Key(id)
} }