implement WHO irc command for queries on self

This commit is contained in:
Nikita Vilunov 2023-02-16 18:39:54 +01:00
parent 30db029390
commit 81ee1c1044
4 changed files with 150 additions and 19 deletions

View File

@ -79,7 +79,12 @@ impl PlayerConnection {
pub async fn leave_room(&mut self, room_id: RoomId) -> Result<()> {
let (promise, deferred) = oneshot();
self.player_handle.send(PlayerCommand::Cmd(Cmd::LeaveRoom { room_id, promise }, self.connection_id.clone())).await;
self.player_handle
.send(PlayerCommand::Cmd(
Cmd::LeaveRoom { room_id, promise },
self.connection_id.clone(),
))
.await;
Ok(deferred.await?)
}
@ -346,7 +351,8 @@ impl Player {
}
promise.send(());
let update = Updates::RoomLeft {
room_id, former_member_id: self.player_id.clone(),
room_id,
former_member_id: self.player_id.clone(),
};
self.broadcast_update(update, connection_id).await;
}

View File

@ -11,7 +11,7 @@ use crate::core::player::{PlayerConnection, PlayerId, PlayerRegistry, Updates};
use crate::core::room::{RoomId, RoomInfo, RoomRegistry};
use crate::prelude::*;
use crate::protos::irc::client::{client_message, ClientMessage};
use crate::protos::irc::server::{ServerMessage, ServerMessageBody};
use crate::protos::irc::server::{AwayStatus, ServerMessage, ServerMessageBody};
use crate::protos::irc::{Chan, Recipient};
use crate::util::Terminator;
@ -244,10 +244,13 @@ async fn handle_update(
player_id: &PlayerId,
writer: &mut (impl AsyncWrite + Unpin),
rooms: &RoomRegistry,
update: Updates
update: Updates,
) -> Result<()> {
match update {
Updates::RoomJoined { new_member_id, room_id } => {
Updates::RoomJoined {
new_member_id,
room_id,
} => {
if player_id == &new_member_id {
if let Some(room) = rooms.get_room(&room_id) {
let room_info = room.get_room_info().await;
@ -262,26 +265,42 @@ async fn handle_update(
tags: vec![],
sender: Some(new_member_id.as_bytes().clone()),
body: ServerMessageBody::Join(Chan::Global(room_id.as_bytes().clone())),
}.write_async(writer).await?;
}
.write_async(writer)
.await?;
writer.flush().await?
}
},
Updates::RoomLeft { room_id, former_member_id } => {
}
Updates::RoomLeft {
room_id,
former_member_id,
} => {
ServerMessage {
tags: vec![],
sender: Some(former_member_id.as_bytes().clone()),
body: ServerMessageBody::Part(Chan::Global(room_id.as_bytes().clone())),
}.write_async(writer).await?;
}
.write_async(writer)
.await?;
writer.flush().await?
},
Updates::NewMessage { author_id, room_id, body } => {
}
Updates::NewMessage {
author_id,
room_id,
body,
} => {
ServerMessage {
tags: vec![],
sender: Some(author_id.as_bytes().clone()),
body: ServerMessageBody::PrivateMessage { target: Recipient::Chan(Chan::Global(room_id.as_bytes().clone())), body: body.as_bytes().to_vec() }
}.write_async(writer).await?;
body: ServerMessageBody::PrivateMessage {
target: Recipient::Chan(Chan::Global(room_id.as_bytes().clone())),
body: body.as_bytes().to_vec(),
},
}
.write_async(writer)
.await?;
writer.flush().await?
},
}
Updates::RoomTopicChanged { room_id, new_topic } => {
ServerMessage {
tags: vec![],
@ -291,9 +310,11 @@ async fn handle_update(
chat: Chan::Global(room_id.as_bytes().clone()),
topic: new_topic,
},
}.write_async(writer).await?;
}
.write_async(writer)
.await?;
writer.flush().await?
},
}
}
Ok(())
}
@ -360,6 +381,46 @@ async fn handle_incoming_message(
Chan::Local(_) => {}
};
}
ClientMessage::Who { target } => match &target {
Recipient::Nick(nick) => {
if nick == &user.nickname {
let mut username = Vec::with_capacity(user.username.len() + 1);
username.push(b'~');
username.extend_from_slice(user.username.as_slice());
ServerMessage {
tags: vec![],
sender: Some(config.server_name.as_bytes().to_vec()),
body: ServerMessageBody::N352WhoReply {
client: user.nickname.clone(),
username,
host: b"*".to_vec(), // TODO need to decide what to send as user's host
server: config.server_name.as_bytes().to_vec(),
flags: AwayStatus::Here,
hops: 0,
realname: user.realname.clone(),
},
}
.write_async(writer)
.await?;
ServerMessage {
tags: vec![],
sender: Some(config.server_name.as_bytes().to_vec()),
body: ServerMessageBody::N315EndOfWho {
client: user.nickname.clone(),
mask: target.clone(),
msg: b"End of WHO list".to_vec(),
},
}
.write_async(writer)
.await?;
writer.flush().await?;
}
log::warn!("WHO for other users is not implemented")
}
Recipient::Chan(_) => {
log::warn!("WHO for chans not implemented")
}
},
cmd => {
log::warn!("Not implemented handler for client command: {cmd:?}");
}

View File

@ -29,7 +29,9 @@ pub enum ClientMessage {
/// MODE <target>
Mode(Chan), // TODO support not only chan
/// WHO <target>
Who(Chan), // TODO support not only chan
Who {
target: Recipient, // aka mask
},
/// TOPIC <chan> :<topic>
Topic {
chan: Chan,
@ -144,9 +146,9 @@ fn client_message_mode(input: &[u8]) -> IResult<&[u8], ClientMessage> {
fn client_message_who(input: &[u8]) -> IResult<&[u8], ClientMessage> {
let (input, _) = tag("WHO ")(input)?;
let (input, chan) = chan(input)?;
let (input, target) = recipient(input)?;
Ok((input, ClientMessage::Who(chan)))
Ok((input, ClientMessage::Who { target }))
}
fn client_message_topic(input: &[u8]) -> IResult<&[u8], ClientMessage> {

View File

@ -83,11 +83,32 @@ pub enum ServerMessageBody {
client: ByteVec,
params: ByteVec, // TODO make this a datatype
},
/// Final reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request.
N315EndOfWho {
client: ByteVec,
mask: Recipient,
/// Usually `b"End of WHO list"`
msg: ByteVec,
},
N332Topic {
client: ByteVec,
chat: Chan,
topic: ByteVec,
},
/// A reply to a client's [Who](crate::protos::irc::client::ClientMessage::Who) request.
N352WhoReply {
client: ByteVec,
// chan = *
username: ByteVec,
/// User's hostname
host: ByteVec,
/// Hostname of the server the user is connected to
server: ByteVec,
/// Flags
flags: AwayStatus,
hops: u8,
realname: ByteVec,
},
N353NamesReply {
client: ByteVec,
chan: Chan,
@ -177,6 +198,14 @@ impl ServerMessageBody {
writer.write_all(&params).await?;
writer.write_all(b" :are supported by this server").await?;
}
ServerMessageBody::N315EndOfWho { client, mask, msg } => {
writer.write_all(b"315 ").await?;
writer.write_all(&client).await?;
writer.write_all(b" ").await?;
mask.write_async(writer).await?;
writer.write_all(b" :").await?;
writer.write_all(&msg).await?;
}
ServerMessageBody::N332Topic {
client,
chat,
@ -189,6 +218,33 @@ impl ServerMessageBody {
writer.write_all(b" :").await?;
writer.write_all(&topic).await?;
}
ServerMessageBody::N352WhoReply {
client,
username,
host,
server,
flags,
hops,
realname,
} => {
writer.write_all(b"352 ").await?;
writer.write_all(&client).await?;
writer.write_all(b" * ").await?;
writer.write_all(&username).await?;
writer.write_all(b" ").await?;
writer.write_all(&host).await?;
writer.write_all(b" ").await?;
writer.write_all(&server).await?;
writer.write_all(b" ").await?;
match flags {
AwayStatus::Here => writer.write_all(b"H").await?,
AwayStatus::Gone => writer.write_all(b"G").await?,
}
writer.write_all(b" :").await?;
writer.write_all(hops.to_string().as_bytes()).await?;
writer.write_all(b" ").await?;
writer.write_all(&realname).await?;
}
ServerMessageBody::N353NamesReply {
client,
chan,
@ -213,6 +269,12 @@ impl ServerMessageBody {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AwayStatus {
Here,
Gone,
}
fn server_message_body(input: &[u8]) -> IResult<&[u8], ServerMessageBody> {
alt((
server_message_body_notice,