use std::sync::Arc;
use tokio::sync::RwLock;
use crate::protocol::{Message, Reply};
use crate::state::ServerState;
use crate::utils::generate_message_id;
use crate::history::{HistoryItem, MessageType};
pub async fn handle_privmsg(
server_state: Arc<RwLock<ServerState>>,
connection_id: u64,
target: String,
message: String,
) -> Result<Vec<Message>, Box<dyn std::error::Error>> {
let (nick, user, host, has_echo_message, msg_id, privmsg) = {
let state = server_state.read().await;
let connection = state.connections.get(&connection_id)
.ok_or("Connection not found")?;
let nick = connection.nickname.clone()
.ok_or("No nickname set")?;
let user = connection.username.clone()
.unwrap_or(nick.clone());
let host = connection.hostname.clone();
let has_echo_message = connection.capabilities.contains(&"echo-message".to_string());
let prefix = format!("{}!{}@{}", nick, user, host);
let msg_id = generate_message_id();
let mut privmsg = Message::new("PRIVMSG")
.with_prefix(prefix)
.with_params(vec![target.clone(), message.clone()]);
if connection.capabilities.contains(&"message-tags".to_string()) {
privmsg = privmsg.with_tag("msgid".to_string(), Some(msg_id.clone()));
}
if connection.capabilities.contains(&"server-time".to_string()) {
let timestamp = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true);
privmsg = privmsg.with_tag("time".to_string(), Some(timestamp));
}
(nick, user, host, has_echo_message, msg_id, privmsg)
};
let history_item = HistoryItem::new(
msg_id.clone(),
MessageType::Privmsg,
nick.clone(),
"*".to_string(), message.clone(),
target.clone(),
);
{
let state = server_state.read().await;
state.history.store_message(history_item);
}
{
let state = server_state.read().await;
if target.starts_with('#') || target.starts_with('&') {
if let Some(channel) = state.channels.get(&target) {
for entry in channel.members.iter() {
let member_id = *entry.key();
if member_id != connection_id || has_echo_message {
if let Some(member_conn) = state.connections.get(&member_id) {
let _ = member_conn.tx.send(privmsg.clone()).await;
}
}
}
} else {
return Ok(vec![Message::from(Reply::NoSuchChannel {
nick: nick.clone(),
channel: target.clone(),
})]);
}
} else {
let target_nick = target.clone();
let mut target_connection = None;
for entry in state.connections.iter() {
if let Some(ref nickname) = entry.nickname {
if nickname == &target_nick {
target_connection = Some(entry.clone());
break;
}
}
}
if let Some(target_conn) = target_connection {
let _ = target_conn.tx.send(privmsg.clone()).await;
if has_echo_message {
if let Some(sender_conn) = state.connections.get(&connection_id) {
let _ = sender_conn.tx.send(privmsg.clone()).await;
}
}
} else {
return Ok(vec![Message::from(Reply::NoSuchNick {
nick: nick.clone(),
target: target_nick,
})]);
}
}
}
Ok(vec![]) }