Skip to content

Commit

Permalink
Merge pull request #109 from squidowl/feat/brodcast-quit
Browse files Browse the repository at this point in the history
brodcast quit and nick changes
  • Loading branch information
casperstorm authored Jul 6, 2023
2 parents 5f4d552 + 5b2a9eb commit 20dbb74
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 84 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Added:
- Previously sent messages can be accessed per buffer in the text input with up / down arrows
- Themes directory where users can add their own theme files
- Nickname completions in text input with <kbd>Tab</kbd>
- Broadcast nickname changes to relevant channels and queries.
- Broadcast quit messages to relevant channels and queries.

Changed:

Expand Down
89 changes: 67 additions & 22 deletions data/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap};
use irc::client::Client;
use itertools::Itertools;

use crate::user::NickRef;
use crate::user::{Nick, NickRef};
use crate::{message, Message, Server, User};

#[derive(Debug, Clone, Copy)]
Expand All @@ -25,6 +25,25 @@ pub enum State {
Ready(Connection),
}

#[derive(Debug)]
pub enum Brodcast {
Quit {
user: User,
comment: Option<String>,
},
Nickname {
old_user: User,
new_nick: Nick,
ourself: bool,
},
}

#[derive(Debug)]
pub enum Event {
Single(Message),
Brodcast(Brodcast),
}

#[derive(Debug)]
pub struct Connection {
client: Client,
Expand Down Expand Up @@ -60,37 +79,47 @@ impl Connection {
}
}

fn receive(&mut self, message: message::Encoded) -> Option<Message> {
fn receive(&mut self, message: message::Encoded) -> Option<Event> {
log::trace!("Message received => {:?}", *message);

self.handle(&message);

Message::received(message, self.nickname())
self.handle(message)
}

fn handle(&mut self, message: &message::Encoded) {
fn handle(&mut self, message: message::Encoded) -> Option<Event> {
use irc::proto::{Command, Response};

match &message.command {
Command::NICK(nick) => {
let Some(old_nick) = message.prefix.as_ref().and_then(|prefix| match prefix {
irc::proto::Prefix::ServerName(_) => None,
irc::proto::Prefix::Nickname(nick, _, _) => Some(nick),
}) else {
return;
};

if self.resolved_nick.as_ref() == Some(old_nick) {
self.resolved_nick = Some(nick.clone())
let old_user = message.user()?;
let ourself = self.nickname() == old_user.nickname();

if ourself {
self.resolved_nick = Some(nick.clone());
}

return Some(Event::Brodcast(Brodcast::Nickname {
old_user,
new_nick: Nick::from(nick.as_str()),
ourself,
}));
}
Command::Response(Response::RPL_WELCOME, args) => {
if let Some(nick) = args.first() {
self.resolved_nick = Some(nick.to_string());
}
}
Command::QUIT(comment) => {
let user = message.user()?;

return Some(Event::Brodcast(Brodcast::Quit {
user,
comment: comment.clone(),
}));
}
_ => {}
}

Some(Event::Single(Message::received(message, self.nickname())?))
}

fn sync(&mut self) {
Expand Down Expand Up @@ -183,17 +212,15 @@ impl Map {
self.connection(server).map(Connection::nickname)
}

pub fn receive(&mut self, server: &Server, message: message::Encoded) -> Option<Message> {
pub fn receive(&mut self, server: &Server, message: message::Encoded) -> Option<Event> {
self.connection_mut(server)
.and_then(|connection| connection.receive(message))
}

pub fn sync(&mut self) {
self.0.values_mut().for_each(|state| {
if let State::Ready(connection) = state {
connection.sync();
}
});
pub fn sync(&mut self, server: &Server) {
if let Some(State::Ready(connection)) = self.0.get_mut(server) {
connection.sync();
}
}

pub fn send(&mut self, server: &Server, message: message::Encoded) {
Expand All @@ -208,6 +235,24 @@ impl Map {
.unwrap_or_default()
}

pub fn get_user_channels(&self, server: &Server, nick: NickRef) -> Vec<String> {
self.connection(server)
.map(|connection| {
connection
.channels()
.iter()
.filter(|channel| {
connection
.users(channel)
.iter()
.any(|user| user.nickname() == nick)
})
.cloned()
.collect::<Vec<_>>()
})
.unwrap_or_default()
}

pub fn iter(&self) -> std::collections::btree_map::Iter<Server, State> {
self.0.iter()
}
Expand Down
57 changes: 50 additions & 7 deletions data/src/history/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::history::{self, History};
use crate::message::{self, Limit};
use crate::time::Posix;
use crate::user::{Nick, NickRef};
use crate::{server, Buffer, Input, Server};
use crate::{server, Buffer, Input, Server, User};

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Resource {
Expand Down Expand Up @@ -260,7 +260,7 @@ impl Manager {
}
})
.cloned();
let queries = map
let mut queries = map
.keys()
.filter_map(|kind| {
if let history::Kind::Query(nick) = kind {
Expand All @@ -272,11 +272,43 @@ impl Manager {
.cloned();

let messages = match broadcast {
Broadcast::Disconnected => {
message::broadcast::disconnected(channels, queries).collect::<Vec<_>>()
Broadcast::Disconnected => message::broadcast::disconnected(channels, queries),
Broadcast::Reconnected => message::broadcast::reconnected(channels, queries),
Broadcast::Quit {
user,
comment,
user_channels,
} => {
let user_query = queries.find(|nick| user.nickname() == *nick);

message::broadcast::quit(user_channels, user_query, &user, &comment)
}
Broadcast::Reconnected => {
message::broadcast::reconnected(channels, queries).collect::<Vec<_>>()
Broadcast::Nickname {
old_nick,
new_nick,
ourself,
user_channels,
} => {
if ourself {
// If ourself, broadcast to all query channels (since we are in all of them)
message::broadcast::nickname(
user_channels,
queries,
&old_nick,
&new_nick,
ourself,
)
} else {
// Otherwise just the query channel of the user w/ nick change
let user_query = queries.find(|nick| old_nick == *nick);
message::broadcast::nickname(
user_channels,
user_query,
&old_nick,
&new_nick,
ourself,
)
}
}
};

Expand Down Expand Up @@ -438,8 +470,19 @@ impl Data {
}
}

#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone)]
pub enum Broadcast {
Disconnected,
Reconnected,
Quit {
user: User,
comment: Option<String>,
user_channels: Vec<String>,
},
Nickname {
old_nick: Nick,
new_nick: Nick,
ourself: bool,
user_channels: Vec<String>,
},
}
Loading

0 comments on commit 20dbb74

Please sign in to comment.