Skip to content

Commit

Permalink
Handle errors in data::Client::handle
Browse files Browse the repository at this point in the history
For simplicity's sake, the returned type is a `Result<T, anyhow::Error>`
. Errors are displayed in a modal text box on top of the IRC client.

Test plan:
Added code which returns an error from `data::Clients::receive` with a
1% chance, and observed that the error shows up.

Resolves #627
  • Loading branch information
4e554c4c committed Oct 26, 2024
1 parent c02ccd1 commit 05fda52
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 167 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ tokio-stream = { version = "0.1.16", features = ["fs"] }

# change to 1.2.0 when it is released https://github.com/frewsxcv/rust-dark-light/issues/38
dark-light = { git = "https://github.com/frewsxcv/rust-dark-light", rev = "3eb3e93dd0fa30733c3e93082dd9517fb580ae95" }
anyhow = "1.0.91"

[dependencies.uuid]
version = "1.0"
Expand Down
1 change: 1 addition & 0 deletions data/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ nom = "7.1"
const_format = "0.2.32"
strum = { version = "0.26.3", features = ["derive"] }
derive_more = { version = "1.0.0", features = ["full"] }
anyhow = "1.0.91"

[dependencies.irc]
path = "../irc"
Expand Down
319 changes: 168 additions & 151 deletions data/src/client.rs

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion data/src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,17 @@ async fn connect(

let (sender, receiver) = mpsc::channel(100);

let mut client = Client::new(server, config, sender);
if let Err(e) = client.connect() {
log::error!("Error when connecting client: {:?}", e);
}

Ok((
Stream {
connection,
receiver,
},
Client::new(server, config, sender),
client,
))
}

Expand Down
18 changes: 14 additions & 4 deletions data/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ use std::collections::HashSet;
use std::fmt;
use std::hash::Hash;

use thiserror::Error;

use irc::proto;
use itertools::sorted;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -49,26 +51,34 @@ impl PartialOrd for User {
}
}

#[derive(Error, Debug)]
pub enum TryFromUserError {
#[error("nickname can't be empty")]
NicknameEmpty,
#[error("nickname must start with alphabetic or [ \\ ] ^ _ ` {{ | }} *")]
NicknameInvalidCharacter,
}

impl TryFrom<String> for User {
type Error = &'static str;
type Error = TryFromUserError;

fn try_from(value: String) -> Result<Self, Self::Error> {
Self::try_from(value.as_str())
}
}

impl<'a> TryFrom<&'a str> for User {
type Error = &'static str;
type Error = TryFromUserError;

fn try_from(value: &'a str) -> Result<Self, Self::Error> {
if value.is_empty() {
return Err("nickname can't be empty");
return Err(Self::Error::NicknameEmpty);
}

let Some(index) =
value.find(|c: char| c.is_alphabetic() || "[\\]^_`{|}*".find(c).is_some())
else {
return Err("nickname must start with alphabetic or [ \\ ] ^ _ ` { | } *");
return Err(Self::Error::NicknameInvalidCharacter);
};

let (access_levels, rest) = (&value[..index], &value[index..]);
Expand Down
19 changes: 15 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ pub enum Message {
AppearanceReloaded(data::appearance::Appearance),
ScreenConfigReloaded(Result<Config, config::Error>),
Dashboard(dashboard::Message),
IrcError(anyhow::Error),
Stream(stream::Update),
Help(help::Message),
Welcome(welcome::Message),
Expand Down Expand Up @@ -345,6 +346,7 @@ impl Halloy {
self.clients.quit(&server, None);
Task::none()
}
Some(dashboard::Event::IrcError(e)) => Task::done(Message::IrcError(e)),
Some(dashboard::Event::Exit) => {
let pending_exit = self.clients.exit();

Expand Down Expand Up @@ -489,9 +491,14 @@ impl Halloy {
let commands = messages
.into_iter()
.flat_map(|message| {
let events = match self.clients.receive(&server, message) {
Ok(events) => events,
Err(e) => return vec![Task::done(Message::IrcError(e))],
};

let mut commands = vec![];

for event in self.clients.receive(&server, message) {
for event in events {
// Resolve a user using client state which stores attributes
let resolve_user_attributes = |user: &User, channel: &str| {
self.clients
Expand Down Expand Up @@ -816,9 +823,9 @@ impl Halloy {
Task::none()
}
Message::Tick(now) => {
self.clients.tick(now);

if let Screen::Dashboard(dashboard) = &mut self.screen {
if let Err(e) = self.clients.tick(now) {
Task::done(Message::IrcError(e))
} else if let Screen::Dashboard(dashboard) = &mut self.screen {
dashboard.tick(now).map(Message::Dashboard)
} else {
Task::none()
Expand Down Expand Up @@ -938,6 +945,10 @@ impl Halloy {
)
.map(Message::Dashboard)
}
Message::IrcError(e) => {
self.modal = Some(Modal::IrcError(e));
Task::none()
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions src/modal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ use crate::widget::Element;
use data::{config, Server};

pub mod connect_to_server;
pub mod reload_configuration_error;
pub mod error;

#[derive(Debug)]
pub enum Modal {
ReloadConfigurationError(config::Error),
IrcError(anyhow::Error),
ServerConnect {
url: String,
server: Server,
Expand Down Expand Up @@ -43,7 +44,8 @@ impl Modal {

pub fn view(&self) -> Element<Message> {
match self {
Modal::ReloadConfigurationError(error) => reload_configuration_error::view(error),
Modal::ReloadConfigurationError(error) => error::view("Error reloading configuration file", error),
Modal::IrcError(error) => error::view("IRC Error", &**error),
Modal::ServerConnect {
url: raw, config, ..
} => connect_to_server::view(raw, config),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use data::config;
use std::error;

use iced::{
alignment,
widget::{button, column, container, text},
Expand All @@ -8,10 +9,10 @@ use iced::{
use super::Message;
use crate::{theme, widget::Element};

pub fn view<'a>(error: &config::Error) -> Element<'a, Message> {
pub fn view<'a>(title: &'a str, error: impl error::Error) -> Element<'a, Message> {
container(
column![
text("Error reloading configuration file"),
text(title),
text(error.to_string()).style(theme::text::error),
button(
container(text("Close"))
Expand Down
9 changes: 7 additions & 2 deletions src/screen/dashboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub enum Event {
ConfigReloaded(Result<Config, config::Error>),
ReloadThemes,
QuitServer(Server),
IrcError(anyhow::Error),
Exit,
}

Expand Down Expand Up @@ -593,15 +594,19 @@ impl Dashboard {
if let Some(((server, target), read_marker)) =
kind.server().zip(kind.target()).zip(read_marker)
{
clients.send_markread(server, target, read_marker);
if let Err(e) = clients.send_markread(server, target, read_marker) {
return (Task::none(), Some(Event::IrcError(e)));
};
}
}
history::manager::Event::Exited(results) => {
for (kind, read_marker) in results {
if let Some(((server, target), read_marker)) =
kind.server().zip(kind.target()).zip(read_marker)
{
clients.send_markread(server, target, read_marker);
if let Err(e) = clients.send_markread(server, target, read_marker) {
return (Task::none(), Some(Event::IrcError(e)));
};
}
}

Expand Down

0 comments on commit 05fda52

Please sign in to comment.