Create message log struct
This commit is contained in:
parent
ad5d2f3b37
commit
8dddabc0e6
3 changed files with 165 additions and 138 deletions
21
src/irc_message.rs
Normal file
21
src/irc_message.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
pub enum IrcMessage {
|
||||||
|
Join {
|
||||||
|
nickname: String,
|
||||||
|
},
|
||||||
|
Part {
|
||||||
|
nickname: String,
|
||||||
|
reason: Option<String>,
|
||||||
|
},
|
||||||
|
Nick {
|
||||||
|
old: String,
|
||||||
|
new: String,
|
||||||
|
},
|
||||||
|
Quit {
|
||||||
|
nickname: String,
|
||||||
|
reason: Option<String>,
|
||||||
|
},
|
||||||
|
Privmsg {
|
||||||
|
nickname: String,
|
||||||
|
message: String,
|
||||||
|
},
|
||||||
|
}
|
218
src/main.rs
218
src/main.rs
|
@ -1,5 +1,9 @@
|
||||||
|
mod irc_message;
|
||||||
|
mod message_log;
|
||||||
|
|
||||||
|
use crate::irc_message::IrcMessage;
|
||||||
|
use crate::message_log::MessageLog;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
@ -66,38 +70,6 @@ async fn main() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
enum IrcMessage {
|
|
||||||
Join {
|
|
||||||
nickname: String,
|
|
||||||
},
|
|
||||||
Part {
|
|
||||||
nickname: String,
|
|
||||||
reason: Option<String>,
|
|
||||||
},
|
|
||||||
Nick {
|
|
||||||
old: String,
|
|
||||||
new: String,
|
|
||||||
},
|
|
||||||
Quit {
|
|
||||||
nickname: String,
|
|
||||||
reason: Option<String>,
|
|
||||||
},
|
|
||||||
Privmsg {
|
|
||||||
nickname: String,
|
|
||||||
message: String,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cri {
|
|
||||||
message_rx: RefCell<Option<UnboundedReceiver<irc::proto::Message>>>,
|
|
||||||
input_tx: RefCell<UnboundedSender<irc::proto::Message>>,
|
|
||||||
|
|
||||||
active_channel: Option<String>,
|
|
||||||
|
|
||||||
message_log: HashMap<Option<String>, Vec<IrcMessage>>,
|
|
||||||
input_value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CriFlags {
|
struct CriFlags {
|
||||||
pub message_rx: UnboundedReceiver<irc::proto::Message>,
|
pub message_rx: UnboundedReceiver<irc::proto::Message>,
|
||||||
pub input_tx: UnboundedSender<irc::proto::Message>,
|
pub input_tx: UnboundedSender<irc::proto::Message>,
|
||||||
|
@ -111,6 +83,16 @@ enum UiMessage {
|
||||||
HandleChannelPress(Option<String>),
|
HandleChannelPress(Option<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Cri {
|
||||||
|
message_rx: RefCell<Option<UnboundedReceiver<irc::proto::Message>>>,
|
||||||
|
input_tx: RefCell<UnboundedSender<irc::proto::Message>>,
|
||||||
|
|
||||||
|
active_channel: Option<String>,
|
||||||
|
|
||||||
|
message_log: MessageLog,
|
||||||
|
input_value: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl Application for Cri {
|
impl Application for Cri {
|
||||||
type Executor = executor::Default;
|
type Executor = executor::Default;
|
||||||
type Message = UiMessage;
|
type Message = UiMessage;
|
||||||
|
@ -118,9 +100,6 @@ impl Application for Cri {
|
||||||
type Flags = CriFlags;
|
type Flags = CriFlags;
|
||||||
|
|
||||||
fn new(flags: Self::Flags) -> (Self, iced::Command<Self::Message>) {
|
fn new(flags: Self::Flags) -> (Self, iced::Command<Self::Message>) {
|
||||||
let mut message_log = HashMap::new();
|
|
||||||
message_log.insert(None, Vec::new());
|
|
||||||
|
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
message_rx: RefCell::new(Some(flags.message_rx)),
|
message_rx: RefCell::new(Some(flags.message_rx)),
|
||||||
|
@ -128,7 +107,7 @@ impl Application for Cri {
|
||||||
|
|
||||||
active_channel: None,
|
active_channel: None,
|
||||||
|
|
||||||
message_log,
|
message_log: MessageLog::new(),
|
||||||
input_value: String::new(),
|
input_value: String::new(),
|
||||||
},
|
},
|
||||||
iced::Command::none(),
|
iced::Command::none(),
|
||||||
|
@ -140,74 +119,41 @@ impl Application for Cri {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
|
fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
|
||||||
|
use irc::proto::Command;
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
UiMessage::IrcMessageReceived(message) => {
|
UiMessage::IrcMessageReceived(message) => {
|
||||||
let message = *message;
|
|
||||||
|
|
||||||
// TODO use actual nickname
|
// TODO use actual nickname
|
||||||
let source_nickname = message.source_nickname().unwrap_or("cri").to_string();
|
let source_nickname = message.source_nickname().unwrap_or("cri").to_string();
|
||||||
|
|
||||||
match &message.command {
|
match &message.command {
|
||||||
irc::proto::Command::JOIN(chanlist, _, _) => {
|
Command::JOIN(chanlist, _, _) => {
|
||||||
|
self.message_log.on_join(chanlist.clone(), &source_nickname);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::PART(chanlist, comment) => {
|
||||||
|
self.message_log.on_part(
|
||||||
|
chanlist.clone(),
|
||||||
|
&source_nickname,
|
||||||
|
comment.as_deref(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::NICK(new) => {
|
||||||
|
self.message_log.on_nick(&source_nickname, new);
|
||||||
|
}
|
||||||
|
|
||||||
|
Command::QUIT(comment) => {
|
||||||
self.message_log
|
self.message_log
|
||||||
.entry(Some(chanlist.to_string()))
|
.on_quit(&source_nickname, comment.as_deref());
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push(IrcMessage::Join {
|
|
||||||
nickname: source_nickname,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
irc::proto::Command::PART(chanlist, comment) => {
|
|
||||||
|
Command::PRIVMSG(msgtarget, content) => {
|
||||||
|
let channel = message.response_target().unwrap_or(msgtarget).to_string();
|
||||||
self.message_log
|
self.message_log
|
||||||
.entry(Some(chanlist.to_string()))
|
.on_privmsg(channel, &source_nickname, content);
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push(IrcMessage::Part {
|
|
||||||
nickname: source_nickname,
|
|
||||||
reason: comment.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
irc::proto::Command::NICK(new) => {
|
|
||||||
let channels = self.message_log.keys().cloned().collect::<Vec<_>>();
|
|
||||||
for channel in channels {
|
|
||||||
if channel.is_some() {
|
|
||||||
self.message_log
|
|
||||||
.get_mut(&channel)
|
|
||||||
.unwrap()
|
|
||||||
.push(IrcMessage::Nick {
|
|
||||||
old: source_nickname.clone(),
|
|
||||||
new: new.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irc::proto::Command::QUIT(comment) => {
|
|
||||||
let channels = self.message_log.keys().cloned().collect::<Vec<_>>();
|
|
||||||
for channel in channels {
|
|
||||||
if channel.is_some() {
|
|
||||||
self.message_log
|
|
||||||
.get_mut(&channel)
|
|
||||||
.unwrap()
|
|
||||||
.push(IrcMessage::Quit {
|
|
||||||
nickname: source_nickname.clone(),
|
|
||||||
reason: comment.clone(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
irc::proto::Command::PRIVMSG(msgtarget, content) => {
|
|
||||||
let channel = message.response_target().unwrap_or(msgtarget);
|
|
||||||
|
|
||||||
self.message_log
|
|
||||||
.entry(Some(channel.to_string()))
|
|
||||||
.or_insert_with(Vec::new)
|
|
||||||
.push(IrcMessage::Privmsg {
|
|
||||||
nickname: source_nickname,
|
|
||||||
message: content.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,13 +166,12 @@ impl Application for Cri {
|
||||||
);
|
);
|
||||||
let message: irc::proto::Message = command.into();
|
let message: irc::proto::Message = command.into();
|
||||||
|
|
||||||
self.message_log
|
self.message_log.get_mut(self.active_channel.clone()).push(
|
||||||
.get_mut(&self.active_channel)
|
IrcMessage::Privmsg {
|
||||||
.unwrap()
|
|
||||||
.push(IrcMessage::Privmsg {
|
|
||||||
nickname: String::from("cri"),
|
nickname: String::from("cri"),
|
||||||
message: self.input_value.clone(),
|
message: self.input_value.clone(),
|
||||||
});
|
},
|
||||||
|
);
|
||||||
self.input_tx.borrow().send(message.clone()).unwrap();
|
self.input_tx.borrow().send(message.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,38 +199,39 @@ impl Application for Cri {
|
||||||
let _darker_grey = Color::new(0.498, 0.549, 0.553, 1.0);
|
let _darker_grey = Color::new(0.498, 0.549, 0.553, 1.0);
|
||||||
|
|
||||||
let log = scrollable(column(
|
let log = scrollable(column(
|
||||||
self.message_log[&self.active_channel]
|
self.message_log
|
||||||
|
.get(&self.active_channel)
|
||||||
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|message| {
|
.flat_map(|message| match message {
|
||||||
match message {
|
IrcMessage::Join { nickname } => {
|
||||||
IrcMessage::Join { nickname } => {
|
Some(text(format!("* {nickname} joined the channel")).style(dark_green))
|
||||||
Some(text(format!("* {nickname} joined the channel")).style(dark_green))
|
}
|
||||||
}
|
IrcMessage::Part { nickname, reason } => {
|
||||||
IrcMessage::Part { nickname, reason } => {
|
let reason = match reason {
|
||||||
let reason = match reason {
|
Some(reason) => format!(" ({reason})"),
|
||||||
Some(reason) => format!(" ({reason})"),
|
None => String::new(),
|
||||||
None => String::new(),
|
};
|
||||||
};
|
Some(
|
||||||
Some(
|
text(format!("* {nickname} left the channel{reason}"))
|
||||||
text(format!("* {nickname} left the channel{reason}"))
|
.style(dark_green),
|
||||||
.style(dark_green),
|
)
|
||||||
)
|
}
|
||||||
}
|
IrcMessage::Nick { old, new } => Some(
|
||||||
IrcMessage::Nick { old, new } => {
|
text(format!("* {old} changed their nickname to {new}")).style(dark_green),
|
||||||
Some(text(format!("* {old} changed their nickname to {new}")).style(dark_green))
|
),
|
||||||
}
|
IrcMessage::Quit { nickname, reason } => {
|
||||||
IrcMessage::Quit { nickname, reason }=> {
|
let reason = match reason {
|
||||||
let reason = match reason {
|
Some(reason) => format!(" ({reason})"),
|
||||||
Some(reason) => format!(" ({reason})"),
|
None => String::new(),
|
||||||
None => String::new(),
|
};
|
||||||
};
|
|
||||||
|
|
||||||
Some(text(format!("* {nickname} quit the server{reason}"))
|
Some(
|
||||||
.style(dark_green))
|
text(format!("* {nickname} quit the server{reason}")).style(dark_green),
|
||||||
},
|
)
|
||||||
IrcMessage::Privmsg { nickname, message } => {
|
}
|
||||||
Some(text(format!("<{nickname}> {message}")))
|
IrcMessage::Privmsg { nickname, message } => {
|
||||||
}
|
Some(text(format!("<{nickname}> {message}")))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map(|element| element.into())
|
.map(|element| element.into())
|
||||||
|
@ -301,15 +247,11 @@ impl Application for Cri {
|
||||||
|
|
||||||
let channels = column(
|
let channels = column(
|
||||||
self.message_log
|
self.message_log
|
||||||
.keys()
|
.get_channels()
|
||||||
|
.iter()
|
||||||
.map(|channel| {
|
.map(|channel| {
|
||||||
let channel_name = channel
|
let text = text(channel);
|
||||||
.as_ref()
|
let is_active = self.active_channel.as_ref() == Some(channel);
|
||||||
.unwrap_or(&String::from("Server"))
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let text = text(channel_name);
|
|
||||||
let is_active = &self.active_channel == channel;
|
|
||||||
let container = container(text)
|
let container = container(text)
|
||||||
.style(move |_: &_| {
|
.style(move |_: &_| {
|
||||||
let background = if is_active {
|
let background = if is_active {
|
||||||
|
@ -326,7 +268,7 @@ impl Application for Cri {
|
||||||
.width(Length::Fill);
|
.width(Length::Fill);
|
||||||
|
|
||||||
mouse_area(container)
|
mouse_area(container)
|
||||||
.on_press(UiMessage::HandleChannelPress(channel.clone()))
|
.on_press(UiMessage::HandleChannelPress(Some(channel.to_string())))
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
|
|
64
src/message_log.rs
Normal file
64
src/message_log.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::irc_message::IrcMessage;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct MessageLog(HashMap<Option<String>, Vec<IrcMessage>>);
|
||||||
|
|
||||||
|
impl<'a> MessageLog {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut log = HashMap::new();
|
||||||
|
log.insert(None, Vec::new());
|
||||||
|
Self(log)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_channels(&'a self) -> Vec<&String> {
|
||||||
|
let mut keys = self.0.keys().flatten().collect::<Vec<_>>();
|
||||||
|
keys.sort_unstable();
|
||||||
|
keys
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, channel: &Option<String>) -> Option<&Vec<IrcMessage>> {
|
||||||
|
self.0.get(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut(&mut self, channel: Option<String>) -> &mut Vec<IrcMessage> {
|
||||||
|
self.0.entry(channel).or_insert_with(Vec::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_join(&mut self, channel: String, nickname: &str) {
|
||||||
|
self.get_mut(Some(channel)).push(IrcMessage::Join {
|
||||||
|
nickname: nickname.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_part(&mut self, channel: String, nickname: &str, comment: Option<&str>) {
|
||||||
|
self.get_mut(Some(channel)).push(IrcMessage::Part {
|
||||||
|
nickname: nickname.to_string(),
|
||||||
|
reason: comment.map(str::to_string),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_nick(&mut self, old: &str, new: &str) {
|
||||||
|
for log in self.0.values_mut() {
|
||||||
|
log.push(IrcMessage::Nick {
|
||||||
|
old: old.to_string(),
|
||||||
|
new: new.to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_quit(&mut self, nickname: &str, reason: Option<&str>) {
|
||||||
|
for log in self.0.values_mut() {
|
||||||
|
log.push(IrcMessage::Quit {
|
||||||
|
nickname: nickname.to_string(),
|
||||||
|
reason: reason.map(str::to_string),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_privmsg(&mut self, channel: String, nickname: &str, message: &str) {
|
||||||
|
self.get_mut(Some(channel)).push(IrcMessage::Privmsg {
|
||||||
|
nickname: nickname.to_string(),
|
||||||
|
message: message.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue