Merge pull request #185 from udoprog/thiserror

Switch to modern error handling
This commit is contained in:
Aaron Weiss 2019-12-27 16:50:57 -05:00 committed by GitHub
commit 8a6d8f4017
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 143 additions and 171 deletions

View file

@ -27,11 +27,11 @@ json = ["serde_json"]
yaml = ["serde_yaml"]
[dependencies]
thiserror = "1.0.2"
bufstream = "0.1"
bytes = "0.4"
chrono = "0.4"
encoding = "0.2"
failure = "0.1"
irc-proto = { version = "*", path = "irc-proto" }
log = "0.4"
native-tls = "0.2"
@ -46,7 +46,7 @@ toml = { version = "0.4", optional = true }
pin-utils = "0.1.0-alpha.4"
parking_lot = "0.9.0"
futures-channel = "0.3.1"
futures-util = "0.3.1"
futures-util = { version = "0.3.1", features = ["sink"] }
[dev-dependencies]
futures = "0.3.1"

View file

@ -8,6 +8,7 @@ keywords = ["irc", "protocol", "tokio"]
categories = ["network-programming"]
documentation = "https://docs.rs/irc-proto/"
repository = "https://github.com/aatxe/irc"
edition = "2018"
[badges]
travis-ci = { repository = "aatxe/irc" }
@ -18,6 +19,6 @@ default = ["tokio", "tokio-util", "bytes"]
[dependencies]
bytes = { version = "0.5", optional = true }
encoding = "0.2"
failure = "0.1"
thiserror = "1.0.2"
tokio-util = { version = "0.2.0", optional = true }
tokio = { version = "0.2.0", optional = true }

View file

@ -118,7 +118,7 @@ impl FormattedStringExt<'static> for String {
#[cfg(test)]
mod test {
use colors::FormattedStringExt;
use crate::colors::FormattedStringExt;
use std::borrow::Cow;
macro_rules! test_formatted_string_ext {

View file

@ -1,10 +1,10 @@
//! Enumeration of all available client commands.
use std::str::FromStr;
use chan::ChannelExt;
use error::MessageParseError;
use mode::{ChannelMode, Mode, UserMode};
use response::Response;
use crate::chan::ChannelExt;
use crate::error::MessageParseError;
use crate::mode::{ChannelMode, Mode, UserMode};
use crate::response::Response;
/// List of all client commands as defined in [RFC 2812](http://tools.ietf.org/html/rfc2812). This
/// also includes commands from the

View file

@ -1,57 +1,57 @@
//! IRC protocol errors using `failure`.
use std::io::Error as IoError;
use thiserror::Error;
/// A `Result` type for IRC `ProtocolErrors`.
pub type Result<T> = ::std::result::Result<T, ProtocolError>;
pub type Result<T, E = ProtocolError> = ::std::result::Result<T, E>;
/// An IRC protocol error.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum ProtocolError {
/// An internal I/O error.
#[fail(display = "an io error occurred")]
Io(#[cause] IoError),
#[error("an io error occurred")]
Io(#[source] std::io::Error),
/// Error for invalid messages.
#[fail(display = "invalid message: {}", string)]
#[error("invalid message: {}", string)]
InvalidMessage {
/// The string that failed to parse.
string: String,
/// The detailed message parsing error.
#[cause]
#[source]
cause: MessageParseError,
},
}
impl From<IoError> for ProtocolError {
fn from(e: IoError) -> ProtocolError {
impl From<std::io::Error> for ProtocolError {
fn from(e: std::io::Error) -> ProtocolError {
ProtocolError::Io(e)
}
}
/// Errors that occur when parsing messages.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum MessageParseError {
/// The message was empty.
#[fail(display = "empty message")]
#[error("empty message")]
EmptyMessage,
/// The command was invalid (i.e. missing).
#[fail(display = "invalid command")]
#[error("invalid command")]
InvalidCommand,
/// The mode string was malformed.
#[fail(display = "invalid mode string: {}", string)]
#[error("invalid mode string: {}", string)]
InvalidModeString {
/// The invalid mode string.
string: String,
/// The detailed mode parsing error.
#[cause]
#[source]
cause: ModeParseError,
},
/// The subcommand used was invalid.
#[fail(display = "invalid {} subcommand: {}", cmd, sub)]
#[error("invalid {} subcommand: {}", cmd, sub)]
InvalidSubcommand {
/// The command whose invalid subcommand was referenced.
cmd: &'static str,
@ -61,16 +61,16 @@ pub enum MessageParseError {
}
/// Errors that occur while parsing mode strings.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum ModeParseError {
/// Invalid modifier used in a mode string (only + and - are valid).
#[fail(display = "invalid mode modifier: {}", modifier)]
#[error("invalid mode modifier: {}", modifier)]
InvalidModeModifier {
/// The invalid mode modifier.
modifier: char,
},
/// Missing modifier used in a mode string.
#[fail(display = "missing mode modifier")]
#[error("missing mode modifier")]
MissingModeModifier,
}

View file

@ -2,9 +2,9 @@
use bytes::BytesMut;
use tokio_util::codec::{Decoder, Encoder};
use error;
use line::LineCodec;
use message::Message;
use crate::error;
use crate::line::LineCodec;
use crate::message::Message;
/// An IRC codec built around an inner codec.
pub struct IrcCodec {

View file

@ -2,16 +2,6 @@
#![warn(missing_docs)]
#[cfg(feature = "tokio")]
extern crate bytes;
extern crate encoding;
#[macro_use]
extern crate failure;
#[cfg(feature = "tokio")]
extern crate tokio;
#[cfg(feature = "tokio-util")]
extern crate tokio_util;
pub mod caps;
pub mod chan;
pub mod colors;

View file

@ -7,7 +7,7 @@ use encoding::label::encoding_from_whatwg_label;
use encoding::{DecoderTrap, EncoderTrap, EncodingRef};
use tokio_util::codec::{Decoder, Encoder};
use error;
use crate::error;
/// A line-based codec parameterized by an encoding.
pub struct LineCodec {

View file

@ -3,11 +3,11 @@ use std::borrow::ToOwned;
use std::fmt::{Display, Formatter, Result as FmtResult, Write};
use std::str::FromStr;
use chan::ChannelExt;
use command::Command;
use error;
use error::{MessageParseError, ProtocolError};
use prefix::Prefix;
use crate::chan::ChannelExt;
use crate::command::Command;
use crate::error;
use crate::error::{MessageParseError, ProtocolError};
use crate::prefix::Prefix;
/// A data structure representing an IRC message according to the protocol specification. It
/// consists of a collection of IRCv3 tags, a prefix (describing the source of the message), and
@ -276,7 +276,7 @@ pub struct Tag(pub String, pub Option<String>);
#[cfg(test)]
mod test {
use super::{Message, Tag};
use command::Command::{Raw, PRIVMSG, QUIT};
use crate::command::Command::{Raw, PRIVMSG, QUIT};
#[test]
fn new() {

View file

@ -1,10 +1,10 @@
//! A module defining an API for IRC user and channel modes.
use std::fmt;
use command::Command;
use error::MessageParseError;
use error::MessageParseError::InvalidModeString;
use error::ModeParseError::*;
use crate::command::Command;
use crate::error::MessageParseError;
use crate::error::MessageParseError::InvalidModeString;
use crate::error::ModeParseError::*;
/// A marker trait for different kinds of Modes.
pub trait ModeType: fmt::Display + fmt::Debug + Clone + PartialEq {

View file

@ -535,6 +535,7 @@ impl Config {
#[cfg(test)]
mod test {
use super::Config;
use anyhow::Result;
use std::collections::HashMap;
#[allow(unused)]
@ -601,7 +602,7 @@ mod test {
#[test]
#[cfg(feature = "json")]
fn load_from_json() -> Result<(), failure::Error> {
fn load_from_json() -> Result<()> {
const DATA: &str = include_str!("client_config.json");
assert_eq!(
Config::load_json("client_config.json", DATA)?.with_path("client_config.json"),
@ -612,7 +613,7 @@ mod test {
#[test]
#[cfg(feature = "toml")]
fn load_from_toml() -> Result<(), failure::Error> {
fn load_from_toml() -> Result<()> {
const DATA: &str = include_str!("client_config.toml");
assert_eq!(
Config::load_toml("client_config.toml", DATA)?.with_path("client_config.toml"),
@ -623,7 +624,7 @@ mod test {
#[test]
#[cfg(feature = "yaml")]
fn load_from_yaml() -> Result<(), failure::Error> {
fn load_from_yaml() -> Result<()> {
const DATA: &str = include_str!("client_config.yaml");
assert_eq!(
Config::load_yaml("client_config.yaml", DATA)?.with_path("client_config.yaml"),

View file

@ -1086,6 +1086,7 @@ mod test {
ChannelMode, IrcCodec, Mode,
},
};
use anyhow::Result;
use futures::prelude::*;
pub fn test_config() -> Config {
@ -1120,7 +1121,7 @@ mod test {
}
#[tokio::test]
async fn stream() -> Result<(), failure::Error> {
async fn stream() -> Result<()> {
let exp = "PRIVMSG test :Hi!\r\nPRIVMSG test :This is a test!\r\n\
:test!test@test JOIN #test\r\n";
@ -1136,7 +1137,7 @@ mod test {
}
#[tokio::test]
async fn handle_message() -> Result<(), failure::Error> {
async fn handle_message() -> Result<()> {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1152,7 +1153,7 @@ mod test {
}
#[tokio::test]
async fn handle_end_motd_with_nick_password() -> Result<(), failure::Error> {
async fn handle_end_motd_with_nick_password() -> Result<()> {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1171,7 +1172,7 @@ mod test {
}
#[tokio::test]
async fn handle_end_motd_with_chan_keys() -> Result<(), failure::Error> {
async fn handle_end_motd_with_chan_keys() -> Result<()> {
let value = ":irc.test.net 376 test :End of /MOTD command\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1194,7 +1195,7 @@ mod test {
}
#[tokio::test]
async fn handle_end_motd_with_ghost() -> Result<(), failure::Error> {
async fn handle_end_motd_with_ghost() -> Result<()> {
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
:irc.test.net 376 test2 :End of /MOTD command.\r\n";
let mut client = Client::from_config(Config {
@ -1217,7 +1218,7 @@ mod test {
}
#[tokio::test]
async fn handle_end_motd_with_ghost_seq() -> Result<(), failure::Error> {
async fn handle_end_motd_with_ghost_seq() -> Result<()> {
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
:irc.test.net 376 test2 :End of /MOTD command.\r\n";
let mut client = Client::from_config(Config {
@ -1242,7 +1243,7 @@ mod test {
}
#[tokio::test]
async fn handle_end_motd_with_umodes() -> Result<(), failure::Error> {
async fn handle_end_motd_with_umodes() -> Result<()> {
let value = ":irc.test.net 376 test :End of /MOTD command.\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1261,7 +1262,7 @@ mod test {
}
#[tokio::test]
async fn nickname_in_use() -> Result<(), failure::Error> {
async fn nickname_in_use() -> Result<()> {
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1274,7 +1275,7 @@ mod test {
}
#[tokio::test]
async fn ran_out_of_nicknames() -> Result<(), failure::Error> {
async fn ran_out_of_nicknames() -> Result<()> {
let value = ":irc.pdgn.co 433 * test :Nickname is already in use.\r\n\
:irc.pdgn.co 433 * test2 :Nickname is already in use.\r\n";
let mut client = Client::from_config(Config {
@ -1292,7 +1293,7 @@ mod test {
}
#[tokio::test]
async fn send() -> Result<(), failure::Error> {
async fn send() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
assert!(client
.send(PRIVMSG(format!("#test"), format!("Hi there!")))
@ -1306,7 +1307,7 @@ mod test {
}
#[tokio::test]
async fn send_no_newline_injection() -> Result<(), failure::Error> {
async fn send_no_newline_injection() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
assert!(client
.send(PRIVMSG(format!("#test"), format!("Hi there!\r\nJOIN #bad")))
@ -1320,7 +1321,7 @@ mod test {
}
#[tokio::test]
async fn send_raw_is_really_raw() -> Result<(), failure::Error> {
async fn send_raw_is_really_raw() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
assert!(client
.send(Raw("PASS".to_owned(), vec!["password".to_owned()], None))
@ -1338,7 +1339,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn channel_tracking_names() -> Result<(), failure::Error> {
async fn channel_tracking_names() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1355,7 +1356,7 @@ mod test {
/*
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn channel_tracking_names_part() -> Result<(), failure::Error> {
async fn channel_tracking_names_part() -> Result<()> {
use crate::proto::command::Command::PART;
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
@ -1373,7 +1374,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn user_tracking_names() -> Result<(), failure::Error> {
async fn user_tracking_names() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1390,7 +1391,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn user_tracking_names_join() -> Result<(), failure::Error> {
async fn user_tracking_names_join() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
:test2!test@test JOIN #test\r\n";
let mut client = Client::from_config(Config {
@ -1413,7 +1414,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn user_tracking_names_kick() -> Result<(), failure::Error> {
async fn user_tracking_names_kick() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
:owner!test@test KICK #test test\r\n";
let mut client = Client::from_config(Config {
@ -1431,7 +1432,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn user_tracking_names_part() -> Result<(), failure::Error> {
async fn user_tracking_names_part() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin\r\n\
:owner!test@test PART #test\r\n";
let mut client = Client::from_config(Config {
@ -1449,7 +1450,7 @@ mod test {
#[tokio::test]
#[cfg(not(feature = "nochanlists"))]
async fn user_tracking_names_mode() -> Result<(), failure::Error> {
async fn user_tracking_names_mode() -> Result<()> {
let value = ":irc.test.net 353 test = #test :+test ~owner &admin\r\n\
:test!test@test MODE #test +o test\r\n";
let mut client = Client::from_config(Config {
@ -1478,7 +1479,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "nochanlists")]
async fn no_user_tracking() -> Result<(), failure::Error> {
async fn no_user_tracking() -> Result<()> {
let value = ":irc.test.net 353 test = #test :test ~owner &admin";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1491,7 +1492,7 @@ mod test {
}
#[tokio::test]
async fn handle_single_soh() -> Result<(), failure::Error> {
async fn handle_single_soh() -> Result<()> {
let value = ":test!test@test PRIVMSG #test :\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1506,7 +1507,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn finger_response() -> Result<(), failure::Error> {
async fn finger_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}FINGER\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1523,7 +1524,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn version_response() -> Result<(), failure::Error> {
async fn version_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}VERSION\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1543,7 +1544,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn source_response() -> Result<(), failure::Error> {
async fn source_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}SOURCE\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1560,7 +1561,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn ctcp_ping_response() -> Result<(), failure::Error> {
async fn ctcp_ping_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}PING test\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1577,7 +1578,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn time_response() -> Result<(), failure::Error> {
async fn time_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}TIME\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1593,7 +1594,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn user_info_response() -> Result<(), failure::Error> {
async fn user_info_response() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}USERINFO\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1611,7 +1612,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn ctcp_ping_no_timestamp() -> Result<(), failure::Error> {
async fn ctcp_ping_no_timestamp() -> Result<()> {
let value = ":test!test@test PRIVMSG test :\u{001}PING\u{001}\r\n";
let mut client = Client::from_config(Config {
mock_initial_value: Some(value.to_owned()),
@ -1624,7 +1625,7 @@ mod test {
}
#[tokio::test]
async fn identify() -> Result<(), failure::Error> {
async fn identify() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.identify()?;
client.stream()?.collect().await?;
@ -1637,7 +1638,7 @@ mod test {
}
#[tokio::test]
async fn identify_with_password() -> Result<(), failure::Error> {
async fn identify_with_password() -> Result<()> {
let mut client = Client::from_config(Config {
nickname: Some(format!("test")),
password: Some(format!("password")),
@ -1655,7 +1656,7 @@ mod test {
}
#[tokio::test]
async fn send_pong() -> Result<(), failure::Error> {
async fn send_pong() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_pong("irc.test.net")?;
client.stream()?.collect().await?;
@ -1664,7 +1665,7 @@ mod test {
}
#[tokio::test]
async fn send_join() -> Result<(), failure::Error> {
async fn send_join() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_join("#test,#test2,#test3")?;
client.stream()?.collect().await?;
@ -1676,7 +1677,7 @@ mod test {
}
#[tokio::test]
async fn send_part() -> Result<(), failure::Error> {
async fn send_part() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_part("#test")?;
client.stream()?.collect().await?;
@ -1685,7 +1686,7 @@ mod test {
}
#[tokio::test]
async fn send_oper() -> Result<(), failure::Error> {
async fn send_oper() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_oper("test", "test")?;
client.stream()?.collect().await?;
@ -1694,7 +1695,7 @@ mod test {
}
#[tokio::test]
async fn send_privmsg() -> Result<(), failure::Error> {
async fn send_privmsg() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_privmsg("#test", "Hi, everybody!")?;
client.stream()?.collect().await?;
@ -1706,7 +1707,7 @@ mod test {
}
#[tokio::test]
async fn send_notice() -> Result<(), failure::Error> {
async fn send_notice() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_notice("#test", "Hi, everybody!")?;
client.stream()?.collect().await?;
@ -1718,7 +1719,7 @@ mod test {
}
#[tokio::test]
async fn send_topic_no_topic() -> Result<(), failure::Error> {
async fn send_topic_no_topic() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_topic("#test", "")?;
client.stream()?.collect().await?;
@ -1727,7 +1728,7 @@ mod test {
}
#[tokio::test]
async fn send_topic() -> Result<(), failure::Error> {
async fn send_topic() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_topic("#test", "Testing stuff.")?;
client.stream()?.collect().await?;
@ -1739,7 +1740,7 @@ mod test {
}
#[tokio::test]
async fn send_kill() -> Result<(), failure::Error> {
async fn send_kill() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_kill("test", "Testing kills.")?;
client.stream()?.collect().await?;
@ -1751,7 +1752,7 @@ mod test {
}
#[tokio::test]
async fn send_kick_no_message() -> Result<(), failure::Error> {
async fn send_kick_no_message() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_kick("#test", "test", "")?;
client.stream()?.collect().await?;
@ -1760,7 +1761,7 @@ mod test {
}
#[tokio::test]
async fn send_kick() -> Result<(), failure::Error> {
async fn send_kick() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_kick("#test", "test", "Testing kicks.")?;
client.stream()?.collect().await?;
@ -1772,7 +1773,7 @@ mod test {
}
#[tokio::test]
async fn send_mode_no_modeparams() -> Result<(), failure::Error> {
async fn send_mode_no_modeparams() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_mode("#test", &[Mode::Plus(ChannelMode::InviteOnly, None)])?;
client.stream()?.collect().await?;
@ -1781,7 +1782,7 @@ mod test {
}
#[tokio::test]
async fn send_mode() -> Result<(), failure::Error> {
async fn send_mode() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_mode(
"#test",
@ -1793,7 +1794,7 @@ mod test {
}
#[tokio::test]
async fn send_samode_no_modeparams() -> Result<(), failure::Error> {
async fn send_samode_no_modeparams() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_samode("#test", "+i", "")?;
client.stream()?.collect().await?;
@ -1802,7 +1803,7 @@ mod test {
}
#[tokio::test]
async fn send_samode() -> Result<(), failure::Error> {
async fn send_samode() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_samode("#test", "+o", "test")?;
client.stream()?.collect().await?;
@ -1811,7 +1812,7 @@ mod test {
}
#[tokio::test]
async fn send_sanick() -> Result<(), failure::Error> {
async fn send_sanick() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_sanick("test", "test2")?;
client.stream()?.collect().await?;
@ -1820,7 +1821,7 @@ mod test {
}
#[tokio::test]
async fn send_invite() -> Result<(), failure::Error> {
async fn send_invite() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_invite("test", "#test")?;
client.stream()?.collect().await?;
@ -1830,7 +1831,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_ctcp() -> Result<(), failure::Error> {
async fn send_ctcp() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_ctcp("test", "MESSAGE")?;
client.stream()?.collect().await?;
@ -1843,7 +1844,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_action() -> Result<(), failure::Error> {
async fn send_action() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_action("test", "tests.")?;
client.stream()?.collect().await?;
@ -1856,7 +1857,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_finger() -> Result<(), failure::Error> {
async fn send_finger() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_finger("test")?;
client.stream()?.collect().await?;
@ -1869,7 +1870,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_version() -> Result<(), failure::Error> {
async fn send_version() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_version("test")?;
client.stream()?.collect().await?;
@ -1882,7 +1883,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_source() -> Result<(), failure::Error> {
async fn send_source() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_source("test")?;
client.stream()?.collect().await?;
@ -1895,7 +1896,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_user_info() -> Result<(), failure::Error> {
async fn send_user_info() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_user_info("test")?;
client.stream()?.collect().await?;
@ -1908,7 +1909,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_ctcp_ping() -> Result<(), failure::Error> {
async fn send_ctcp_ping() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_ctcp_ping("test")?;
client.stream()?.collect().await?;
@ -1921,7 +1922,7 @@ mod test {
#[tokio::test]
#[cfg(feature = "ctcp")]
async fn send_time() -> Result<(), failure::Error> {
async fn send_time() -> Result<()> {
let mut client = Client::from_config(test_config()).await?;
client.send_time("test")?;
client.stream()?.collect().await?;

View file

@ -3,86 +3,77 @@
use std::io::Error as IoError;
use std::sync::mpsc::RecvError;
use failure;
use futures_channel::{
mpsc::{SendError, TrySendError},
oneshot::Canceled,
};
use native_tls::Error as TlsError;
#[cfg(feature = "json")]
use serde_json::Error as JsonError;
#[cfg(feature = "yaml")]
use serde_yaml::Error as YamlError;
#[cfg(feature = "toml")]
use toml::de::Error as TomlReadError;
#[cfg(feature = "toml")]
use toml::ser::Error as TomlWriteError;
use thiserror::Error;
use crate::proto::error::{MessageParseError, ProtocolError};
/// A specialized `Result` type for the `irc` crate.
pub type Result<T> = ::std::result::Result<T, Error>;
pub type Result<T, E = Error> = std::result::Result<T, E>;
/// The main crate-wide error type.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum Error {
/// An internal I/O error.
#[fail(display = "an io error occurred")]
Io(#[cause] IoError),
#[error("an io error occurred")]
Io(#[source] IoError),
/// An internal TLS error.
#[fail(display = "a TLS error occurred")]
Tls(#[cause] TlsError),
#[error("a TLS error occurred")]
Tls(#[source] native_tls::Error),
/// An internal synchronous channel closed.
#[fail(display = "a sync channel closed")]
SyncChannelClosed(#[cause] RecvError),
#[error("a sync channel closed")]
SyncChannelClosed(#[source] RecvError),
/// An internal asynchronous channel closed.
#[fail(display = "an async channel closed")]
AsyncChannelClosed(#[cause] SendError),
#[error("an async channel closed")]
AsyncChannelClosed(#[source] SendError),
/// An internal oneshot channel closed.
#[fail(display = "a oneshot channel closed")]
OneShotCanceled(#[cause] Canceled),
#[error("a oneshot channel closed")]
OneShotCanceled(#[source] Canceled),
/// Error for invalid configurations.
#[fail(display = "invalid config: {}", path)]
#[error("invalid config: {}", path)]
InvalidConfig {
/// The path to the configuration, or "<none>" if none specified.
path: String,
/// The detailed configuration error.
#[cause]
#[source]
cause: ConfigError,
},
/// Error for invalid messages.
#[fail(display = "invalid message: {}", string)]
#[error("invalid message: {}", string)]
InvalidMessage {
/// The string that failed to parse.
string: String,
/// The detailed message parsing error.
#[cause]
#[source]
cause: MessageParseError,
},
/// Mutex for a logged transport was poisoned making the log inaccessible.
#[fail(display = "mutex for a logged transport was poisoned")]
#[error("mutex for a logged transport was poisoned")]
PoisonedLog,
/// Ping timed out due to no response.
#[fail(display = "connection reset: no ping response")]
#[error("connection reset: no ping response")]
PingTimeout,
/// Failed to lookup an unknown codec.
#[fail(display = "unknown codec: {}", codec)]
#[error("unknown codec: {}", codec)]
UnknownCodec {
/// The attempted codec.
codec: String,
},
/// Failed to encode or decode something with the given codec.
#[fail(display = "codec {} failed: {}", codec, data)]
#[error("codec {} failed: {}", codec, data)]
CodecFailed {
/// The canonical codec name.
codec: &'static str,
@ -91,78 +82,69 @@ pub enum Error {
},
/// All specified nicknames were in use or unusable.
#[fail(display = "none of the specified nicknames were usable")]
#[error("none of the specified nicknames were usable")]
NoUsableNick,
/// Stream has already been configured.
#[fail(display = "stream has already been configured")]
#[error("stream has already been configured")]
StreamAlreadyConfigured,
/// This allows you to produce any `failure::Error` within closures used by
/// the irc crate. No errors of this kind will ever be produced by the crate
/// itself.
#[fail(display = "{}", inner)]
Custom {
/// The actual error that occurred.
inner: failure::Error,
},
}
/// Errors that occur with configurations.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum ConfigError {
/// Failed to parse as TOML.
#[cfg(feature = "toml")]
#[fail(display = "invalid toml")]
InvalidToml(#[cause] TomlError),
#[error("invalid toml")]
InvalidToml(#[source] TomlError),
/// Failed to parse as JSON.
#[cfg(feature = "json")]
#[fail(display = "invalid json")]
InvalidJson(#[cause] JsonError),
#[error("invalid json")]
InvalidJson(#[source] serde_json::Error),
/// Failed to parse as YAML.
#[cfg(feature = "yaml")]
#[fail(display = "invalid yaml")]
InvalidYaml(#[cause] YamlError),
#[error("invalid yaml")]
InvalidYaml(#[source] serde_yaml::Error),
/// Failed to parse the given format because it was disabled at compile-time.
#[fail(display = "config format disabled: {}", format)]
#[error("config format disabled: {}", format)]
ConfigFormatDisabled {
/// The disabled file format.
format: &'static str,
},
/// Could not identify the given file format.
#[fail(display = "config format unknown: {}", format)]
#[error("config format unknown: {}", format)]
UnknownConfigFormat {
/// The unknown file extension.
format: String,
},
/// File was missing an extension to identify file format.
#[fail(display = "missing format extension")]
#[error("missing format extension")]
MissingExtension,
/// Configuration does not specify a nickname.
#[fail(display = "nickname not specified")]
#[error("nickname not specified")]
NicknameNotSpecified,
/// Configuration does not specify a server.
#[fail(display = "server not specified")]
#[error("server not specified")]
ServerNotSpecified,
}
/// A wrapper that combines toml's serialization and deserialization errors.
#[cfg(feature = "toml")]
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
pub enum TomlError {
/// A TOML deserialization error.
#[fail(display = "deserialization failed")]
Read(#[cause] TomlReadError),
#[error("deserialization failed")]
Read(#[source] toml::de::Error),
/// A TOML serialization error.
#[fail(display = "serialization failed")]
Write(#[cause] TomlWriteError),
#[error("serialization failed")]
Write(#[source] toml::ser::Error),
}
impl From<ProtocolError> for Error {
@ -182,8 +164,8 @@ impl From<IoError> for Error {
}
}
impl From<TlsError> for Error {
fn from(e: TlsError) -> Error {
impl From<native_tls::Error> for Error {
fn from(e: native_tls::Error) -> Error {
Error::Tls(e)
}
}

View file

@ -43,9 +43,6 @@
#![warn(missing_docs)]
#[macro_use]
extern crate failure;
pub extern crate irc_proto as proto;
pub mod client;