aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJokler <jokler.contact@gmail.com>2018-02-28 01:21:25 +0100
committerJokler <jokler.contact@gmail.com>2018-02-28 01:21:25 +0100
commitb40a984ed9b6a948265e1287ecc08f4e16c64ecd (patch)
tree6b94762899961de9da57e426785c29d401b48442
parent8ea98aab1ea34e0213380082577e2a3ff2d3aa2e (diff)
downloadfrippy-b40a984ed9b6a948265e1287ecc08f4e16c64ecd.tar.gz
frippy-b40a984ed9b6a948265e1287ecc08f4e16c64ecd.zip
Create errors with failure
The plugins are mostly not using the new errors yet and the error handling in the Factoids plugin is just temporary.
-rw-r--r--Cargo.lock1
-rw-r--r--Cargo.toml1
-rw-r--r--src/error.rs98
-rw-r--r--src/lib.rs26
-rw-r--r--src/main.rs28
-rw-r--r--src/plugins/factoids/mod.rs174
-rw-r--r--src/plugins/factoids/utils.rs4
-rw-r--r--src/plugins/url.rs37
-rw-r--r--src/utils.rs101
9 files changed, 262 insertions, 208 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d823d90..dcbaad5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -391,6 +391,7 @@ dependencies = [
"diesel_infer_schema 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"diesel_migrations 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"frippy_derive 0.1.0",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index 961ffb9..2d4087a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,6 +37,7 @@ serde = "1.0.27"
serde_json = "1.0.9"
chrono = "0.4.0"
glob = "0.2.11"
+failure = "0.1.1"
frippy_derive = { path = "frippy_derive" }
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 0000000..9ada5b6
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,98 @@
+//! Errors for `frippy` crate using `failure`.
+
+use std::io::Error as IoError;
+use std::str::Utf8Error;
+use irc::error::IrcError;
+use reqwest::Error as ReqwestError;
+
+/// The main crate-wide error type.
+#[derive(Debug, Fail)]
+pub enum FrippyError {
+ /// A plugin error
+ #[fail(display = "A plugin error occured")]
+ Plugin(#[cause] PluginError),
+
+ /// An IRC error
+ #[fail(display = "An IRC error occured")]
+ Irc(#[cause] IrcError),
+
+ /// Missing config error
+ #[fail(display = "No config file was found")]
+ MissingConfig,
+
+ /// A reqwest error
+ #[fail(display = "A reqwest error occured")]
+ Reqwest(#[cause] ReqwestError),
+
+ /// An I/O error
+ #[fail(display = "An I/O error occured")]
+ Io(#[cause] IoError),
+
+ /// A UTF8 error
+ #[fail(display = "A UTF8 error occured")]
+ Utf8(#[cause] Utf8Error),
+
+ /// Reached download limit error
+ #[fail(display = "Reached download limit of {} KiB", limit)]
+ DownloadLimit { limit: usize },
+}
+
+/// Errors related to plugins
+#[derive(Debug, Fail)]
+pub enum PluginError {
+ /// A Url error
+ #[fail(display = "A Url error occured")]
+ Url(#[cause] UrlError),
+
+ /// A Factoids error
+ #[fail(display = "{}", error)]
+ Factoids { error: String },
+}
+
+/// A URL plugin error
+#[derive(Debug, Fail)]
+pub enum UrlError {
+ /// Missing URL error
+ #[fail(display = "No URL was found")]
+ MissingUrl,
+
+ /// Missing title error
+ #[fail(display = "No title was found")]
+ MissingTitle,
+}
+
+impl From<UrlError> for FrippyError {
+ fn from(e: UrlError) -> FrippyError {
+ FrippyError::Plugin(PluginError::Url(e))
+ }
+}
+
+impl From<PluginError> for FrippyError {
+ fn from(e: PluginError) -> FrippyError {
+ FrippyError::Plugin(e)
+ }
+}
+
+impl From<IrcError> for FrippyError {
+ fn from(e: IrcError) -> FrippyError {
+ FrippyError::Irc(e)
+ }
+}
+
+impl From<ReqwestError> for FrippyError {
+ fn from(e: ReqwestError) -> FrippyError {
+ FrippyError::Reqwest(e)
+ }
+}
+
+impl From<IoError> for FrippyError {
+ fn from(e: IoError) -> FrippyError {
+ FrippyError::Io(e)
+ }
+}
+
+impl From<Utf8Error> for FrippyError {
+ fn from(e: Utf8Error) -> FrippyError {
+ FrippyError::Utf8(e)
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 657b0eb..42b0089 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,6 +38,8 @@ extern crate r2d2;
extern crate r2d2_diesel;
#[macro_use]
+extern crate failure;
+#[macro_use]
extern crate frippy_derive;
#[macro_use]
extern crate lazy_static;
@@ -47,11 +49,13 @@ extern crate log;
extern crate chrono;
extern crate humantime;
extern crate irc;
+extern crate reqwest;
extern crate time;
pub mod plugin;
pub mod plugins;
pub mod utils;
+pub mod error;
use std::collections::HashMap;
use std::fmt;
@@ -60,6 +64,7 @@ use std::sync::Arc;
pub use irc::client::prelude::*;
pub use irc::error::IrcError;
+use error::FrippyError;
use plugin::*;
@@ -142,20 +147,15 @@ impl Bot {
/// reactor.run().unwrap();
/// # }
/// ```
- pub fn connect(&self, reactor: &mut IrcReactor, config: &Config) -> Result<(), String> {
+ pub fn connect(&self, reactor: &mut IrcReactor, config: &Config) -> Result<(), FrippyError> {
info!("Plugins loaded: {}", self.plugins);
- let client = match reactor.prepare_client_and_connect(config) {
- Ok(v) => v,
- Err(e) => return Err(format!("Failed to connect: {}", e)),
- };
+ let client = reactor.prepare_client_and_connect(config)?;
info!("Connected to IRC server");
- match client.identify() {
- Ok(_) => info!("Identified"),
- Err(e) => return Err(format!("Failed to identify: {}", e)),
- };
+ client.identify()?;
+ info!("Identified");
// TODO Verify if we actually need to clone plugins twice
let plugins = self.plugins.clone();
@@ -253,10 +253,10 @@ impl ThreadedPlugins {
&mut self,
server: &IrcClient,
mut command: PluginCommand,
- ) -> Result<(), IrcError> {
+ ) -> Result<(), FrippyError> {
if !command.tokens.iter().any(|s| !s.is_empty()) {
let help = format!("Use \"{} help\" to get help", server.current_nickname());
- return server.send_notice(&command.source, &help);
+ server.send_notice(&command.source, &help)?;
}
// Check if the command is for this plugin
@@ -284,7 +284,7 @@ impl ThreadedPlugins {
command.tokens[0]
);
- server.send_notice(&command.source, &help)
+ Ok(server.send_notice(&command.source, &help)?)
}
}
}
@@ -293,7 +293,7 @@ impl fmt::Display for ThreadedPlugins {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let plugin_names = self.plugins
.iter()
- .map(|(_, p)| p.name().to_string())
+ .map(|(_, p)| p.name().to_owned())
.collect::<Vec<String>>();
write!(f, "{}", plugin_names.join(", "))
}
diff --git a/src/main.rs b/src/main.rs
index ec04d33..461387d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@ extern crate frippy;
extern crate glob;
extern crate irc;
extern crate time;
+extern crate failure;
#[cfg(feature = "mysql")]
extern crate diesel;
@@ -26,9 +27,11 @@ use log::{Level, LevelFilter, Metadata, Record};
use irc::client::reactor::IrcReactor;
use glob::glob;
+use failure::Fail;
use frippy::plugins;
use frippy::Config;
+use frippy::error::FrippyError;
#[cfg(feature = "mysql")]
embed_migrations!();
@@ -67,6 +70,18 @@ impl log::Log for Logger {
static LOGGER: Logger = Logger;
fn main() {
+ // Print any errors that caused frippy to shut down
+ if let Err(e) = run() {
+ let mut causes = e.causes();
+
+ error!("{}", causes.next().unwrap());
+ for cause in causes {
+ error!("caused by: {}", cause);
+ }
+ };
+}
+
+fn run() -> Result<(), FrippyError> {
log::set_max_level(if cfg!(debug_assertions) {
LevelFilter::Debug
} else {
@@ -92,12 +107,11 @@ fn main() {
// Without configs the bot would just idle
if configs.is_empty() {
- error!("No config file found");
- return;
+ return Err(FrippyError::MissingConfig);
}
// Create an event loop to run the connections on.
- let mut reactor = IrcReactor::new().unwrap();
+ let mut reactor = IrcReactor::new()?;
// Open a connection and add work for each config
for config in configs {
@@ -127,8 +141,7 @@ fn main() {
let manager = ConnectionManager::<MysqlConnection>::new(url.clone());
match r2d2::Pool::builder().build(manager) {
- Ok(pool) => match embedded_migrations::run(&*pool.get()
- .expect("Failed to get connection"))
+ Ok(pool) => match embedded_migrations::run(&*pool.get()?)
{
Ok(_) => {
let pool = Arc::new(pool);
@@ -166,10 +179,9 @@ fn main() {
}
}
- bot.connect(&mut reactor, &config)
- .expect("Failed to connect");
+ bot.connect(&mut reactor, &config)?;
}
// Run the bots until they throw an error - an error could be loss of connection
- reactor.run().unwrap();
+ Ok(reactor.run()?)
}
diff --git a/src/plugins/factoids/mod.rs b/src/plugins/factoids/mod.rs
index d6abb1d..3f89943 100644
--- a/src/plugins/factoids/mod.rs
+++ b/src/plugins/factoids/mod.rs
@@ -6,6 +6,9 @@ use std::sync::Mutex;
use self::rlua::prelude::*;
use irc::client::prelude::*;
use irc::error::IrcError;
+use error::FrippyError;
+use error::PluginError;
+use failure::Fail;
use time;
use chrono::NaiveDateTime;
@@ -40,8 +43,8 @@ impl<T: Database> Factoids<T> {
}
}
- fn create_factoid(&self, name: &str, content: &str, author: &str) -> Result<&str, &str> {
- let count = try_lock!(self.factoids).count_factoids(name)?;
+ fn create_factoid(&self, name: &str, content: &str, author: &str) -> Result<&str, FrippyError> {
+ let count = try_lock!(self.factoids).count_factoids(name).map_err(|e| PluginError::Factoids { error: e.to_owned() })?;
let tm = time::now().to_timespec();
let factoid = database::NewFactoid {
@@ -54,74 +57,60 @@ impl<T: Database> Factoids<T> {
match try_lock!(self.factoids).insert_factoid(&factoid) {
DbResponse::Success => Ok("Successfully added"),
- DbResponse::Failed(e) => Err(e),
+ DbResponse::Failed(e) => Err(PluginError::Factoids { error: e.to_owned() })?,
}
}
- fn add(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<(), IrcError> {
+ fn add(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<&str, FrippyError> {
if command.tokens.len() < 2 {
- return self.invalid_command(client, command);
+ return Ok(self.invalid_command(client, command).map(|()| "")?);
}
let name = command.tokens.remove(0);
let content = command.tokens.join(" ");
- match self.create_factoid(&name, &content, &command.source) {
- Ok(v) => client.send_notice(&command.source, v),
- Err(e) => client.send_notice(&command.source, e),
- }
+ Ok(self.create_factoid(&name, &content, &command.source)?)
}
- fn save_from_url(
+ fn add_from_url(
&self,
client: &IrcClient,
command: &mut PluginCommand,
- ) -> Result<(), IrcError> {
+ ) -> Result<&str, FrippyError> {
if command.tokens.len() < 2 {
- return self.invalid_command(client, command);
+ return Ok(self.invalid_command(client, command).map(|()| "")?);
}
let name = command.tokens.remove(0);
let url = &command.tokens[0];
- if let Some(content) = ::utils::download(1024, url) {
- match self.create_factoid(&name, &content, &command.source) {
- Ok(v) => client.send_notice(&command.source, v),
- Err(e) => client.send_notice(&command.source, e),
- }
- } else {
- client.send_notice(&command.source, "Failed to download.")
- }
+ let content = ::utils::download(1024, url)?;
+
+ Ok(self.create_factoid(&name, &content, &command.source)?)
}
- fn remove(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<(), IrcError> {
+ fn remove(&self, client: &IrcClient, command: &mut PluginCommand) -> Result<&str, FrippyError> {
if command.tokens.len() < 1 {
- return self.invalid_command(client, command);
+ return Ok(self.invalid_command(client, command).map(|()| "")?);
}
let name = command.tokens.remove(0);
- let count = match try_lock!(self.factoids).count_factoids(&name) {
- Ok(c) => c,
- Err(e) => return client.send_notice(&command.source, e),
- };
+ let count = try_lock!(self.factoids).count_factoids(&name).map_err(|e| PluginError::Factoids { error: e.to_owned() } )?;
match try_lock!(self.factoids).delete_factoid(&name, count - 1) {
- DbResponse::Success => client.send_notice(&command.source, "Successfully removed"),
- DbResponse::Failed(e) => client.send_notice(&command.source, e),
+ DbResponse::Success => Ok("Successfully removed"),
+ DbResponse::Failed(e) => Err(PluginError::Factoids { error: e.to_owned() })?,
}
}
- fn get(&self, client: &IrcClient, command: &PluginCommand) -> Result<(), IrcError> {
+ fn get(&self, client: &IrcClient, command: &PluginCommand) -> Result<String, FrippyError> {
let (name, idx) = match command.tokens.len() {
- 0 => return self.invalid_command(client, command),
+ 0 => return Ok(self.invalid_command(client, command).map(|()| String::new())?),
1 => {
let name = &command.tokens[0];
- let count = match try_lock!(self.factoids).count_factoids(name) {
- Ok(c) => c,
- Err(e) => return client.send_notice(&command.source, e),
- };
+ let count = try_lock!(self.factoids).count_factoids(name).map_err(|e| PluginError::Factoids { error: e.to_owned() } )?;
if count < 1 {
- return client.send_notice(&command.source, &format!("{} does not exist", name));
+ Err(PluginError::Factoids { error: format!("{} does not exist", name) })?;
}
(name, count - 1)
@@ -130,7 +119,7 @@ impl<T: Database> Factoids<T> {
let name = &command.tokens[0];
let idx = match i32::from_str(&command.tokens[1]) {
Ok(i) => i,
- Err(_) => return client.send_notice(&command.source, "Invalid index"),
+ Err(_) => Err(PluginError::Factoids { error: String::from("Invalid index") })?,
};
(name, idx)
@@ -139,61 +128,37 @@ impl<T: Database> Factoids<T> {
let factoid = match try_lock!(self.factoids).get_factoid(name, idx) {
Some(v) => v,
- None => {
- return client
- .send_notice(&command.source, &format!("{}~{} does not exist", name, idx))
- }
+ None => Err(PluginError::Factoids { error: format!("{}~{} does not exist", name, idx) })?,
};
let message = factoid.content.replace("\n", "|").replace("\r", "");
- client.send_privmsg(&command.target, &format!("{}: {}", factoid.name, message))
+ Ok(format!("{}: {}", factoid.name, message))
}
- fn info(&self, client: &IrcClient, command: &PluginCommand) -> Result<(), IrcError> {
+ fn info(&self, client: &IrcClient, command: &PluginCommand) -> Result<String, FrippyError> {
match command.tokens.len() {
- 0 => self.invalid_command(client, command),
+ 0 => Ok(self.invalid_command(client, command).map(|()| String::new())?),
1 => {
let name = &command.tokens[0];
- let count = match try_lock!(self.factoids).count_factoids(name) {
- Ok(c) => c,
- Err(e) => return client.send_notice(&command.source, e),
- };
+ let count = try_lock!(self.factoids).count_factoids(name).map_err(|e| PluginError::Factoids { error: e.to_owned() } )?;
- match count {
- 0 => client.send_notice(&command.source, &format!("{} does not exist", name)),
- 1 => client
- .send_privmsg(&command.target, &format!("There is 1 version of {}", name)),
- _ => client.send_privmsg(
- &command.target,
- &format!("There are {} versions of {}", count, name),
- ),
- }
+ Ok(match count {
+ 0 => Err(PluginError::Factoids { error: format!("{} does not exist", name) })?,
+ 1 => format!("There is 1 version of {}", name),
+ _ => format!("There are {} versions of {}", count, name),
+ })
}
_ => {
let name = &command.tokens[0];
- let idx = match i32::from_str(&command.tokens[1]) {
- Ok(i) => i,
- Err(_) => return client.send_notice(&command.source, "Invalid index"),
- };
+ let idx = i32::from_str(&command.tokens[1]).map_err(|_| PluginError::Factoids { error: String::from("Invalid index") })?;
let factoid = match try_lock!(self.factoids).get_factoid(name, idx) {
Some(v) => v,
- None => {
- return client.send_notice(
- &command.source,
- &format!("{}~{} does not exist", name, idx),
- )
- }
+ None => return Ok(format!("{}~{} does not exist", name, idx)),
};
- client.send_privmsg(
- &command.target,
- &format!(
- "{}: Added by {} at {} UTC",
- name, factoid.author, factoid.created
- ),
- )
+ Ok(format!("{}: Added by {} at {} UTC", name, factoid.author, factoid.created))
}
}
}
@@ -202,39 +167,31 @@ impl<T: Database> Factoids<T> {
&self,
client: &IrcClient,
mut command: PluginCommand,
- error: bool,
- ) -> Result<(), IrcError> {
+ ) -> Result<String, FrippyError> {
if command.tokens.len() < 1 {
- self.invalid_command(client, &command)
+ Ok(self.invalid_command(client, &command).map(|()| String::new())?)
} else {
let name = command.tokens.remove(0);
- let count = match try_lock!(self.factoids).count_factoids(&name) {
- Ok(c) => c,
- Err(e) => return client.send_notice(&command.source, e),
- };
-
- let factoid = match try_lock!(self.factoids).get_factoid(&name, count - 1) {
- Some(v) => v.content,
- None if error => return self.invalid_command(client, &command),
- None => return Ok(()),
- };
+ let count = try_lock!(self.factoids).count_factoids(&name).map_err(|e| PluginError::Factoids { error: e.to_owned() } )?;
+ let factoid = try_lock!(self.factoids).get_factoid(&name, count - 1).ok_or(PluginError::Factoids { error: format!("The factoid \"{}\" does not exist", name) })?;
- let value = &if factoid.starts_with('>') {
- let factoid = String::from(&factoid[1..]);
+ let content = factoid.content;
+ let value = if content.starts_with('>') {
+ let content = String::from(&content[1..]);
- if factoid.starts_with('>') {
- factoid
+ if content.starts_with('>') {
+ content
} else {
- match self.run_lua(&name, &factoid, &command) {
+ match self.run_lua(&name, &content, &command) {
Ok(v) => v,
Err(e) => format!("\"{}\"", e),
}
}
} else {
- factoid
+ content
};
- client.send_privmsg(&command.target, &value.replace("\n", "|").replace("\r", ""))
+ Ok(value.replace("\n", "|").replace("\r", ""))
}
}
@@ -293,12 +250,15 @@ impl<T: Database> Plugin for Factoids<T> {
let t: Vec<String> = content.split(' ').map(ToOwned::to_owned).collect();
let c = PluginCommand {
- source: message.source_nickname().unwrap().to_string(),
- target: message.response_target().unwrap().to_string(),
+ source: message.source_nickname().unwrap().to_owned(),
+ target: message.response_target().unwrap().to_owned(),
tokens: t,
};
- self.exec(client, c, false)
+ match self.exec(client, c) {
+ Ok(f) => client.send_privmsg(&message.response_target().unwrap(), &f),
+ Err(_) => Ok(()),
+ }
} else {
Ok(())
}
@@ -309,16 +269,24 @@ impl<T: Database> Plugin for Factoids<T> {
return self.invalid_command(client, &command);
}
+ let target = command.target.clone();
+ let source = command.source.clone();
+
let sub_command = command.tokens.remove(0);
- match sub_command.as_ref() {
- "add" => self.add(client, &mut command),
- "fromurl" => self.save_from_url(client, &mut command),
- "remove" => self.remove(client, &mut command),
+ let result = match sub_command.as_ref() {
+ "add" => self.add(client, &mut command).map(|s| s.to_owned()),
+ "fromurl" => self.add_from_url(client, &mut command).map(|s| s.to_owned()),
+ "remove" => self.remove(client, &mut command).map(|s| s.to_owned()),
"get" => self.get(client, &command),
"info" => self.info(client, &command),
- "exec" => self.exec(client, command, true),
- _ => self.invalid_command(client, &command),
- }
+ "exec" => self.exec(client, command),
+ _ => self.invalid_command(client, &command).map(|()| String::new()).map_err(|e| e.into()),
+ };
+
+ Ok(match result {
+ Ok(v) => client.send_privmsg(&target, &v),
+ Err(e) => client.send_notice(&source, &e.cause().unwrap().to_string()),
+ }?)
}
fn evaluate(&self, _: &IrcClient, _: PluginCommand) -> Result<String, String> {
diff --git a/src/plugins/factoids/utils.rs b/src/plugins/factoids/utils.rs
index fc86fb3..036dcc6 100644
--- a/src/plugins/factoids/utils.rs
+++ b/src/plugins/factoids/utils.rs
@@ -10,8 +10,8 @@ use self::LuaError::RuntimeError;
pub fn download(_: &Lua, url: String) -> Result<String, LuaError> {
match utils::download(1024, &url) {
- Some(v) => Ok(v),
- None => Err(RuntimeError(format!("Failed to download {}", url))),
+ Ok(v) => Ok(v),
+ Err(e) => Err(RuntimeError(format!("Failed to download {} - {}", url, e.to_string()))),
}
}
diff --git a/src/plugins/url.rs b/src/plugins/url.rs
index b19d4e5..af6f36f 100644
--- a/src/plugins/url.rs
+++ b/src/plugins/url.rs
@@ -11,6 +11,9 @@ use self::select::predicate::Name;
use plugin::*;
use utils;
+use error::FrippyError;
+use error::UrlError;
+use failure::Fail;
lazy_static! {
static ref RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
@@ -28,14 +31,10 @@ impl Url {
}
fn grep_url(&self, msg: &str) -> Option<String> {
- match RE.captures(msg) {
- Some(captures) => {
- debug!("Url captures: {:?}", captures);
+ let captures = RE.captures(msg)?;
+ debug!("Url captures: {:?}", captures);
- Some(captures.get(2)?.as_str().to_string())
- }
- None => None,
- }
+ Some(captures.get(2)?.as_str().to_owned())
}
fn get_title(&self, body: &str) -> Option<String> {
@@ -49,21 +48,11 @@ impl Url {
Some(title_text)
}
- fn url(&self, text: &str) -> Result<String, &str> {
- let url = match self.grep_url(text) {
- Some(url) => url,
- None => return Err("No Url was found."),
- };
-
- match utils::download(self.max_kib, &url) {
- Some(body) => {
- match self.get_title(&body) {
- Some(title) => Ok(title),
- None => Err("No title was found.")
- }
- }
- None => Err("Failed to download document."),
- }
+ fn url(&self, text: &str) -> Result<String, FrippyError> {
+ let url = self.grep_url(text).ok_or(UrlError::MissingUrl)?;
+ let body = utils::download(self.max_kib, &url)?;
+
+ Ok(self.get_title(&body).ok_or(UrlError::MissingTitle)?)
}
}
@@ -86,7 +75,7 @@ impl Plugin for Url {
Err(e) => {
error!("Url plugin error: {}", e);
Ok(())
- },
+ }
},
_ => Ok(()),
}
@@ -100,7 +89,7 @@ impl Plugin for Url {
}
fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
- self.url(&command.tokens[0]).map_err(String::from)
+ self.url(&command.tokens[0]).map_err(|e| e.cause().unwrap().to_string())
}
}
diff --git a/src/utils.rs b/src/utils.rs
index 99b04c4..68ad4d8 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,73 +1,58 @@
-extern crate reqwest;
-
use std::str;
use std::io::{self, Read};
-use self::reqwest::Client;
-use self::reqwest::header::Connection;
+use reqwest::Client;
+use reqwest::header::Connection;
-pub fn download(max_kib: usize, url: &str) -> Option<String> {
- let response = Client::new().get(url).header(Connection::close()).send();
+use error::FrippyError;
- match response {
- Ok(mut response) => {
- let mut body = String::new();
+pub fn download(max_kib: usize, url: &str) -> Result<String, FrippyError> {
+ let mut response = Client::new().get(url).header(Connection::close()).send()?;
- // 100 kibibyte buffer
- let mut buf = [0; 100 * 1024];
- let mut written = 0;
- let mut vec = Vec::new();
- let mut end_of_valid = None;
+ let mut body = String::new();
- // Read until we reach EOF or max_kib KiB
- loop {
- if let Some(eov) = end_of_valid {
- vec = vec[..eov].to_vec();
- }
+ // 100 kibibyte buffer
+ let mut buf = [0; 100 * 1024];
+ let mut written = 0;
+ let mut vec = Vec::new();
+ let mut end_of_valid = None;
- let len = match response.read(&mut buf) {
- Ok(0) => break,
- Ok(len) => len,
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
- Err(e) => {
- debug!("Download from {:?} failed: {}", url, e);
- return None;
- }
- };
- vec.extend_from_slice(&buf);
+ // Read until we reach EOF or max_kib KiB
+ loop {
+ if let Some(eov) = end_of_valid {
+ vec = vec[..eov].to_vec();
+ }
- end_of_valid = None;
- let body_slice = match str::from_utf8(&vec[..len]) {
- Ok(slice) => slice,
- Err(e) => {
- let valid = e.valid_up_to();
- if valid == 0 {
- error!("Failed to read bytes from {:?} as UTF8: {}", url, e);
- return None;
- }
- end_of_valid = Some(valid);
+ let len = match response.read(&mut buf) {
+ Ok(0) => break,
+ Ok(len) => len,
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => continue,
+ Err(e) => Err(e)?,
+ };
+ vec.extend_from_slice(&buf);
+
+ end_of_valid = None;
+ let body_slice = match str::from_utf8(&vec[..len]) {
+ Ok(slice) => slice,
+ Err(e) => {
+ let valid = e.valid_up_to();
+ if valid == 0 {
+ Err(e)?;
+ }
+ end_of_valid = Some(valid);
- str::from_utf8(&buf[..valid]).unwrap()
- }
- };
+ str::from_utf8(&buf[..valid])?
+ }
+ };
- body.push_str(body_slice);
- written += len;
+ body.push_str(body_slice);
+ written += len;
- // Check if the file is too large to download
- if written > max_kib * 1024 {
- debug!(
- "Stopping download - File from {:?} is larger than {} KiB",
- url, max_kib
- );
- return None;
- }
- }
- Some(body)
- }
- Err(e) => {
- debug!("Bad response from {:?}: ({})", url, e);
- None
+ // Check if the file is too large to download
+ if written > max_kib * 1024 {
+ Err(FrippyError::DownloadLimit { limit: max_kib })?;
}
}
+
+ Ok(body)
}