feat: basic channel-based messaging
This commit is contained in:
parent
463c9c06da
commit
0d6447ae01
13 changed files with 295 additions and 42 deletions
72
src/channels.rs
Normal file
72
src/channels.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use tokio::{io::BufWriter, net::TcpStream};
|
||||||
|
|
||||||
|
use crate::{sender::IrcResponseCodes, user::User};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub struct Channel {
|
||||||
|
pub name: String,
|
||||||
|
pub joined_users: BTreeSet<User>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Channel {
|
||||||
|
pub fn add_user(&mut self, user: User) {
|
||||||
|
self.joined_users.insert(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_channel(name: String, user: User) -> Self {
|
||||||
|
Channel {
|
||||||
|
name,
|
||||||
|
joined_users: BTreeSet::from([user]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn names_list_send(
|
||||||
|
&self,
|
||||||
|
user: User,
|
||||||
|
writer: &mut BufWriter<TcpStream>,
|
||||||
|
hostname: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut members = Vec::new();
|
||||||
|
|
||||||
|
for member in self.clone().joined_users {
|
||||||
|
members.push(member.nickname.unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
IrcResponseCodes::NameReply
|
||||||
|
.into_irc_response(
|
||||||
|
user.nickname.clone().unwrap(),
|
||||||
|
format!("= {} :{}", self.name.clone(), members.join(" ")),
|
||||||
|
)
|
||||||
|
.send(hostname, writer, false)
|
||||||
|
.await?;
|
||||||
|
IrcResponseCodes::EndOfNames
|
||||||
|
.into_irc_response(
|
||||||
|
user.nickname.clone().unwrap(),
|
||||||
|
format!("{} :End of /NAMES list", self.name.clone()),
|
||||||
|
)
|
||||||
|
.send(hostname, writer, false)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_topic(
|
||||||
|
&self,
|
||||||
|
user: User,
|
||||||
|
writer: &mut BufWriter<TcpStream>,
|
||||||
|
hostname: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
IrcResponseCodes::NoTopic
|
||||||
|
.into_irc_response(
|
||||||
|
user.nickname.clone().unwrap(),
|
||||||
|
format!("{} :No topic is set", self.name.clone()),
|
||||||
|
)
|
||||||
|
.send(hostname, writer, false)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{IrcAction, IrcHandler},
|
commands::{IrcAction, IrcHandler},
|
||||||
|
messages::Message,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,6 +16,7 @@ impl IrcHandler for Cap {
|
||||||
_arguments: Vec<String>,
|
_arguments: Vec<String>,
|
||||||
_authenticated: bool,
|
_authenticated: bool,
|
||||||
_user_state: &mut User,
|
_user_state: &mut User,
|
||||||
|
_sender: Sender<Message>,
|
||||||
) -> super::IrcAction {
|
) -> super::IrcAction {
|
||||||
IrcAction::DoNothing
|
IrcAction::DoNothing
|
||||||
}
|
}
|
||||||
|
|
|
||||||
69
src/commands/join.rs
Normal file
69
src/commands/join.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
JOINED_CHANNELS,
|
||||||
|
channels::Channel,
|
||||||
|
commands::{IrcAction, IrcHandler},
|
||||||
|
messages::{JoinMessage, Message},
|
||||||
|
user::User,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Join;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl IrcHandler for Join {
|
||||||
|
async fn handle(
|
||||||
|
&self,
|
||||||
|
arguments: Vec<String>,
|
||||||
|
authenticated: bool,
|
||||||
|
user_state: &mut User,
|
||||||
|
sender: Sender<Message>,
|
||||||
|
) -> super::IrcAction {
|
||||||
|
let mut joined_channels = JOINED_CHANNELS.lock().await;
|
||||||
|
let mut channels = Vec::new();
|
||||||
|
|
||||||
|
for channel in arguments[0].clone().split(',') {
|
||||||
|
let mut maybe_existing_channel: Option<Channel> = None;
|
||||||
|
|
||||||
|
if !channel.starts_with("#") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !authenticated {
|
||||||
|
return IrcAction::ErrorAuthenticateFirst;
|
||||||
|
}
|
||||||
|
|
||||||
|
for existing_channel in joined_channels.clone() {
|
||||||
|
if existing_channel.name == channel {
|
||||||
|
maybe_existing_channel = Some(existing_channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut new_channel) = maybe_existing_channel.clone() {
|
||||||
|
new_channel.joined_users.insert(user_state.clone());
|
||||||
|
|
||||||
|
joined_channels.remove(&maybe_existing_channel.clone().unwrap());
|
||||||
|
joined_channels.insert(new_channel.clone());
|
||||||
|
|
||||||
|
channels.push(new_channel.clone());
|
||||||
|
} else {
|
||||||
|
let new_channel = Channel::new_channel(channel.into(), user_state.clone());
|
||||||
|
|
||||||
|
joined_channels.insert(new_channel.clone());
|
||||||
|
|
||||||
|
channels.push(new_channel.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for channel in channels.clone() {
|
||||||
|
let join_message = JoinMessage {
|
||||||
|
sender: user_state.clone().unwrap_all(),
|
||||||
|
channel: channel.clone(),
|
||||||
|
};
|
||||||
|
sender.send(Message::JoinMessage(join_message)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
IrcAction::JoinChannels(channels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,15 +3,21 @@ use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use tokio::{io::BufWriter, net::TcpStream};
|
use tokio::{io::BufWriter, net::TcpStream, sync::broadcast::Sender};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{cap::Cap, nick::Nick, ping::Ping, privmsg::PrivMsg, user::User as UserHandler},
|
SENDER,
|
||||||
|
channels::Channel,
|
||||||
|
commands::{
|
||||||
|
cap::Cap, join::Join, nick::Nick, ping::Ping, privmsg::PrivMsg, user::User as UserHandler,
|
||||||
|
},
|
||||||
|
messages::Message,
|
||||||
sender::IrcResponse,
|
sender::IrcResponse,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod cap;
|
mod cap;
|
||||||
|
mod join;
|
||||||
mod nick;
|
mod nick;
|
||||||
mod ping;
|
mod ping;
|
||||||
mod privmsg;
|
mod privmsg;
|
||||||
|
|
@ -29,8 +35,8 @@ pub struct IrcMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum IrcAction {
|
pub enum IrcAction {
|
||||||
MultipleActions(Vec<Self>),
|
|
||||||
SendText(IrcResponse),
|
SendText(IrcResponse),
|
||||||
|
JoinChannels(Vec<Channel>),
|
||||||
ErrorAuthenticateFirst,
|
ErrorAuthenticateFirst,
|
||||||
DoNothing,
|
DoNothing,
|
||||||
}
|
}
|
||||||
|
|
@ -44,6 +50,7 @@ pub trait IrcHandler: Send + Sync {
|
||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
authenticated: bool,
|
authenticated: bool,
|
||||||
user_state: &mut User,
|
user_state: &mut User,
|
||||||
|
sender: Sender<Message>,
|
||||||
) -> IrcAction;
|
) -> IrcAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,6 +96,7 @@ impl IrcCommand {
|
||||||
user_state: &mut User,
|
user_state: &mut User,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut command_map: HashMap<String, &dyn IrcHandler> = HashMap::new();
|
let mut command_map: HashMap<String, &dyn IrcHandler> = HashMap::new();
|
||||||
|
let broadcast_sender = SENDER.lock().await.clone().unwrap();
|
||||||
|
|
||||||
// Command map is defined here
|
// Command map is defined here
|
||||||
command_map.insert("CAP".to_owned(), &Cap);
|
command_map.insert("CAP".to_owned(), &Cap);
|
||||||
|
|
@ -96,6 +104,7 @@ impl IrcCommand {
|
||||||
command_map.insert("USER".to_owned(), &UserHandler);
|
command_map.insert("USER".to_owned(), &UserHandler);
|
||||||
command_map.insert("PRIVMSG".to_owned(), &PrivMsg);
|
command_map.insert("PRIVMSG".to_owned(), &PrivMsg);
|
||||||
command_map.insert("PING".to_owned(), &Ping);
|
command_map.insert("PING".to_owned(), &Ping);
|
||||||
|
command_map.insert("JOIN".to_owned(), &Join);
|
||||||
|
|
||||||
println!("{self:#?}");
|
println!("{self:#?}");
|
||||||
|
|
||||||
|
|
@ -109,21 +118,41 @@ impl IrcCommand {
|
||||||
self.arguments.clone(),
|
self.arguments.clone(),
|
||||||
user_state.is_populated(),
|
user_state.is_populated(),
|
||||||
user_state,
|
user_state,
|
||||||
|
broadcast_sender,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
action.execute(writer, hostname).await;
|
action.execute(writer, hostname, &user_state).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrcAction {
|
impl IrcAction {
|
||||||
pub async fn execute(&self, writer: &mut BufWriter<TcpStream>, hostname: &str) {
|
pub async fn execute(
|
||||||
|
&self,
|
||||||
|
writer: &mut BufWriter<TcpStream>,
|
||||||
|
hostname: &str,
|
||||||
|
user_state: &User,
|
||||||
|
) {
|
||||||
match self {
|
match self {
|
||||||
IrcAction::SendText(msg) => {
|
IrcAction::SendText(msg) => {
|
||||||
msg.send(hostname, writer, false).await.unwrap();
|
msg.send(hostname, writer, false).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IrcAction::JoinChannels(channels) => {
|
||||||
|
for channel in channels {
|
||||||
|
channel
|
||||||
|
.send_topic(user_state.clone(), writer, hostname)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
channel
|
||||||
|
.names_list_send(user_state.clone(), writer, hostname)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{IrcAction, IrcHandler},
|
commands::{IrcAction, IrcHandler},
|
||||||
|
messages::Message,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,6 +16,7 @@ impl IrcHandler for Nick {
|
||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
_authenticated: bool,
|
_authenticated: bool,
|
||||||
user_state: &mut User,
|
user_state: &mut User,
|
||||||
|
_sender: Sender<Message>,
|
||||||
) -> IrcAction {
|
) -> IrcAction {
|
||||||
user_state.nickname = Some(command[0].clone());
|
user_state.nickname = Some(command[0].clone());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{IrcAction, IrcHandler},
|
commands::{IrcAction, IrcHandler},
|
||||||
|
messages::Message,
|
||||||
sender::IrcResponse,
|
sender::IrcResponse,
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
|
@ -15,13 +17,15 @@ impl IrcHandler for Ping {
|
||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
authenticated: bool,
|
authenticated: bool,
|
||||||
user_state: &mut User,
|
user_state: &mut User,
|
||||||
|
_sender: Sender<Message>,
|
||||||
) -> IrcAction {
|
) -> IrcAction {
|
||||||
if authenticated {
|
if authenticated {
|
||||||
IrcAction::SendText(IrcResponse {
|
IrcAction::SendText(IrcResponse {
|
||||||
sender: None,
|
sender: None,
|
||||||
command: "PONG".into(),
|
command: "PONG".into(),
|
||||||
receiver: user_state.nickname.clone().unwrap(),
|
arguments: Vec::new(),
|
||||||
message: command[0].clone(),
|
receiver: Some(user_state.username.clone().unwrap()),
|
||||||
|
message: format!(":{}", command[0].clone()),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
IrcAction::DoNothing
|
IrcAction::DoNothing
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CONNECTED_USERS, SENDER,
|
CONNECTED_USERS,
|
||||||
commands::{IrcAction, IrcHandler},
|
commands::{IrcAction, IrcHandler},
|
||||||
messages::Message,
|
messages::{Message, PrivMessage},
|
||||||
user::User,
|
user::User,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -16,23 +17,23 @@ impl IrcHandler for PrivMsg {
|
||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
authenticated: bool,
|
authenticated: bool,
|
||||||
user_state: &mut User,
|
user_state: &mut User,
|
||||||
|
sender: Sender<Message>,
|
||||||
) -> IrcAction {
|
) -> IrcAction {
|
||||||
if !authenticated {
|
if !authenticated {
|
||||||
return IrcAction::ErrorAuthenticateFirst;
|
return IrcAction::ErrorAuthenticateFirst;
|
||||||
}
|
}
|
||||||
let connected_users = CONNECTED_USERS.lock().await;
|
let connected_users = CONNECTED_USERS.lock().await;
|
||||||
let sender = SENDER.lock().await.clone().unwrap();
|
|
||||||
|
|
||||||
println!("{connected_users:#?}");
|
println!("{connected_users:#?}");
|
||||||
drop(connected_users);
|
drop(connected_users);
|
||||||
|
|
||||||
let message = Message {
|
let message = PrivMessage {
|
||||||
sender: user_state.clone().unwrap_all(),
|
sender: user_state.clone().unwrap_all(),
|
||||||
receiver: command[0].clone(),
|
receiver: command[0].clone(),
|
||||||
text: command[1].clone(),
|
text: command[1].clone(),
|
||||||
};
|
};
|
||||||
println!("SENDING: {message:#?}");
|
println!("SENDING: {message:#?}");
|
||||||
sender.send(message).unwrap();
|
sender.send(Message::PrivMessage(message)).unwrap();
|
||||||
|
|
||||||
IrcAction::DoNothing
|
IrcAction::DoNothing
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use tokio::sync::broadcast::Sender;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commands::{IrcAction, IrcHandler},
|
commands::{IrcAction, IrcHandler},
|
||||||
|
messages::Message,
|
||||||
user::User as UserState,
|
user::User as UserState,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,7 +16,11 @@ impl IrcHandler for User {
|
||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
_authenticated: bool,
|
_authenticated: bool,
|
||||||
user_state: &mut UserState,
|
user_state: &mut UserState,
|
||||||
|
_sender: Sender<Message>,
|
||||||
) -> IrcAction {
|
) -> IrcAction {
|
||||||
|
if command.len() < 4 {
|
||||||
|
return IrcAction::DoNothing; // XXX: return an error
|
||||||
|
}
|
||||||
user_state.username = Some(command[0].clone());
|
user_state.username = Some(command[0].clone());
|
||||||
user_state.realname = Some(command[3].clone());
|
user_state.realname = Some(command[3].clone());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,19 +26,19 @@ pub async fn send_motd(
|
||||||
);
|
);
|
||||||
|
|
||||||
IrcResponseCodes::Welcome
|
IrcResponseCodes::Welcome
|
||||||
.into_irc_response(user_info.username.clone(), welcome_text)
|
.into_irc_response(user_info.nickname.clone(), welcome_text)
|
||||||
.send(&server_info.server_hostname, writer, true)
|
.send(&server_info.server_hostname, writer, true)
|
||||||
.await?;
|
.await?;
|
||||||
IrcResponseCodes::YourHost
|
IrcResponseCodes::YourHost
|
||||||
.into_irc_response(user_info.username.clone(), yourhost_text)
|
.into_irc_response(user_info.nickname.clone(), yourhost_text)
|
||||||
.send(&server_info.server_hostname, writer, true)
|
.send(&server_info.server_hostname, writer, true)
|
||||||
.await?;
|
.await?;
|
||||||
IrcResponseCodes::MyInfo
|
IrcResponseCodes::MyInfo
|
||||||
.into_irc_response(user_info.username.clone(), myinfo_text)
|
.into_irc_response(user_info.nickname.clone(), myinfo_text)
|
||||||
.send(&server_info.server_hostname, writer, false)
|
.send(&server_info.server_hostname, writer, false)
|
||||||
.await?;
|
.await?;
|
||||||
IrcResponseCodes::ISupport
|
IrcResponseCodes::ISupport
|
||||||
.into_irc_response(user_info.username.clone(), isupport_text)
|
.into_irc_response(user_info.nickname.clone(), isupport_text)
|
||||||
.send(&server_info.server_hostname, writer, false)
|
.send(&server_info.server_hostname, writer, false)
|
||||||
.await?;
|
.await?;
|
||||||
IrcResponseCodes::NoMotd
|
IrcResponseCodes::NoMotd
|
||||||
|
|
|
||||||
65
src/main.rs
65
src/main.rs
|
|
@ -19,12 +19,14 @@ use tokio::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
channels::Channel,
|
||||||
login::send_motd,
|
login::send_motd,
|
||||||
messages::Message,
|
messages::Message,
|
||||||
sender::{IrcResponse, IrcResponseCodes},
|
sender::{IrcResponse, IrcResponseCodes},
|
||||||
user::{User, UserUnwrapped},
|
user::{User, UserUnwrapped},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod channels;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod login;
|
mod login;
|
||||||
mod messages;
|
mod messages;
|
||||||
|
|
@ -33,6 +35,8 @@ mod user;
|
||||||
|
|
||||||
pub static CONNECTED_USERS: Lazy<Mutex<HashSet<UserUnwrapped>>> =
|
pub static CONNECTED_USERS: Lazy<Mutex<HashSet<UserUnwrapped>>> =
|
||||||
Lazy::new(|| Mutex::new(HashSet::new()));
|
Lazy::new(|| Mutex::new(HashSet::new()));
|
||||||
|
pub static JOINED_CHANNELS: Lazy<Mutex<HashSet<Channel>>> =
|
||||||
|
Lazy::new(|| Mutex::new(HashSet::new()));
|
||||||
pub static SENDER: Lazy<Mutex<Option<Sender<Message>>>> = Lazy::new(|| Mutex::new(None));
|
pub static SENDER: Lazy<Mutex<Option<Sender<Message>>>> = Lazy::new(|| Mutex::new(None));
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -178,21 +182,60 @@ async fn message_listener(
|
||||||
bail!("user has not registered yet, returning...");
|
bail!("user has not registered yet, returning...");
|
||||||
}
|
}
|
||||||
|
|
||||||
let user = user_wrapped.unwrap_all();
|
let user = user_wrapped.clone().unwrap_all();
|
||||||
|
|
||||||
let message: Message = receiver.recv().await.unwrap();
|
let message: Message = receiver.recv().await.unwrap();
|
||||||
|
let joined_channels = JOINED_CHANNELS.lock().await;
|
||||||
|
|
||||||
|
let mut channel_name: Option<String> = None;
|
||||||
|
|
||||||
println!("{message:#?}");
|
println!("{message:#?}");
|
||||||
|
|
||||||
if user.nickname.clone().to_ascii_lowercase() == message.receiver.to_ascii_lowercase() {
|
match message {
|
||||||
IrcResponse {
|
Message::PrivMessage(message) => {
|
||||||
sender: Some(message.sender.hostmask()),
|
for channel in joined_channels.clone() {
|
||||||
command: "PRIVMSG".into(),
|
if channel.joined_users.contains(user_wrapped) && channel.name == message.receiver {
|
||||||
message: message.text,
|
channel_name = Some(channel.name.clone());
|
||||||
receiver: user.username.clone(),
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if user.nickname.clone().to_ascii_lowercase() == message.receiver.to_ascii_lowercase() {
|
||||||
|
IrcResponse {
|
||||||
|
sender: Some(message.sender.hostmask()),
|
||||||
|
command: "PRIVMSG".into(),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
message: message.text,
|
||||||
|
receiver: Some(user.username.clone()),
|
||||||
|
}
|
||||||
|
.send("", writer, true)
|
||||||
|
.await?;
|
||||||
|
} else if let Some(channel_name) = channel_name {
|
||||||
|
if message.sender != user {
|
||||||
|
IrcResponse {
|
||||||
|
sender: Some(message.sender.hostmask()),
|
||||||
|
command: "PRIVMSG".into(),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
message: message.text,
|
||||||
|
receiver: Some(channel_name),
|
||||||
|
}
|
||||||
|
.send("", writer, true)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::JoinMessage(message) => {
|
||||||
|
if message.channel.joined_users.contains(user_wrapped) || message.sender == user {
|
||||||
|
IrcResponse {
|
||||||
|
sender: Some(message.sender.hostmask().clone()),
|
||||||
|
command: "JOIN".into(),
|
||||||
|
arguments: Vec::new(),
|
||||||
|
message: message.channel.name.clone(),
|
||||||
|
receiver: None,
|
||||||
|
}
|
||||||
|
.send("", writer, true)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.send("", writer, true)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
use crate::user::UserUnwrapped;
|
use crate::{channels::Channel, user::UserUnwrapped};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Message {
|
||||||
|
PrivMessage(PrivMessage),
|
||||||
|
JoinMessage(JoinMessage),
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Message {
|
pub struct JoinMessage {
|
||||||
|
pub sender: UserUnwrapped,
|
||||||
|
pub channel: Channel,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct PrivMessage {
|
||||||
pub sender: UserUnwrapped,
|
pub sender: UserUnwrapped,
|
||||||
pub receiver: String,
|
pub receiver: String,
|
||||||
pub text: String,
|
pub text: String,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ use tokio::{
|
||||||
pub struct IrcResponse {
|
pub struct IrcResponse {
|
||||||
pub sender: Option<String>,
|
pub sender: Option<String>,
|
||||||
pub command: String,
|
pub command: String,
|
||||||
pub receiver: String,
|
pub receiver: Option<String>,
|
||||||
|
pub arguments: Vec<String>,
|
||||||
pub message: String,
|
pub message: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,6 +21,9 @@ pub enum IrcResponseCodes {
|
||||||
MyInfo,
|
MyInfo,
|
||||||
ISupport,
|
ISupport,
|
||||||
NoMotd,
|
NoMotd,
|
||||||
|
NoTopic,
|
||||||
|
NameReply,
|
||||||
|
EndOfNames,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrcResponse {
|
impl IrcResponse {
|
||||||
|
|
@ -29,20 +33,22 @@ impl IrcResponse {
|
||||||
writer: &mut BufWriter<TcpStream>,
|
writer: &mut BufWriter<TcpStream>,
|
||||||
prepend_column: bool,
|
prepend_column: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut response = format!(
|
let sender = format!(":{}", self.sender.clone().unwrap_or(hostname.to_string()));
|
||||||
":{} {} {} ",
|
let mut full_response = Vec::new();
|
||||||
self.sender.clone().unwrap_or(hostname.to_string()),
|
|
||||||
self.command,
|
|
||||||
self.receiver
|
|
||||||
);
|
|
||||||
|
|
||||||
|
full_response.push(sender);
|
||||||
|
full_response.extend_from_slice(&self.arguments);
|
||||||
|
full_response.push(self.command.clone());
|
||||||
|
if let Some(receiver) = self.receiver.clone() {
|
||||||
|
full_response.push(receiver);
|
||||||
|
}
|
||||||
if prepend_column {
|
if prepend_column {
|
||||||
response.push_str(&format!(":{}\r\n", self.message.trim_end()));
|
full_response.push(format!(":{}\r\n", self.message.trim_end()));
|
||||||
} else {
|
} else {
|
||||||
response.push_str(&format!("{}\r\n", self.message.trim_end()));
|
full_response.push(format!("{}\r\n", self.message.trim_end()));
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.write_all(response.as_bytes()).await?;
|
writer.write_all(full_response.join(" ").as_bytes()).await?;
|
||||||
writer.flush().await?;
|
writer.flush().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -58,6 +64,9 @@ impl From<IrcResponseCodes> for &str {
|
||||||
IrcResponseCodes::MyInfo => "004",
|
IrcResponseCodes::MyInfo => "004",
|
||||||
IrcResponseCodes::ISupport => "005",
|
IrcResponseCodes::ISupport => "005",
|
||||||
IrcResponseCodes::NoMotd => "422",
|
IrcResponseCodes::NoMotd => "422",
|
||||||
|
IrcResponseCodes::NoTopic => "331",
|
||||||
|
IrcResponseCodes::NameReply => "353",
|
||||||
|
IrcResponseCodes::EndOfNames => "366",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +82,8 @@ impl IrcResponseCodes {
|
||||||
IrcResponse {
|
IrcResponse {
|
||||||
sender: None,
|
sender: None,
|
||||||
command: (*self).into(),
|
command: (*self).into(),
|
||||||
receiver,
|
arguments: Vec::new(),
|
||||||
|
receiver: Some(receiver),
|
||||||
message,
|
message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
|
#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub nickname: Option<String>,
|
pub nickname: Option<String>,
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
|
|
@ -47,7 +47,7 @@ impl UserUnwrapped {
|
||||||
format!(
|
format!(
|
||||||
"{}!~{}@{}",
|
"{}!~{}@{}",
|
||||||
self.nickname.clone(),
|
self.nickname.clone(),
|
||||||
self.realname.clone(),
|
self.username.clone(),
|
||||||
"unimplement.ed"
|
"unimplement.ed"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue