Update deps and error handling

This commit is contained in:
hodasemi 2022-05-04 18:33:34 +02:00
parent 767ced2df0
commit 17d4a3e02a
7 changed files with 361 additions and 60 deletions

View file

@ -7,10 +7,9 @@ authors = ["hodasemi <michaelh.95@t-online.de>"]
[dependencies] [dependencies]
typemap = "~0.3" typemap = "~0.3"
serde_json = "*" serde_json = "*"
utilities = { git = "http://gavania.de/hodasemi/context" }
rusqlite = { version = "*", features = ["bundled"] } rusqlite = { version = "*", features = ["bundled"] }
serenity = { version = "0.8", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]} serenity = { version = "0.8", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]}
parking_lot = "*" parking_lot = "*"
failure = "*" anyhow = "*"
hey_listen = "*" hey_listen = "*"
white_rabbit = "*" rand = "*"

304
src/config_handler.rs Normal file
View file

@ -0,0 +1,304 @@
#![allow(unused)]
//! Config file handler
//! Cares about formatting and type conversion
use anyhow::{Context, Result};
use std::{
collections::HashMap,
fmt::Display,
fs::File,
io::{BufRead, BufReader, Write},
path::Path,
str::FromStr,
};
/// Value abstraction to convert to and from values
#[derive(Clone, Debug)]
pub enum Value {
Value(String),
Array(Vec<String>),
}
struct ConfigSection {
header: String,
body: HashMap<String, Value>,
}
impl Value {
/// Creates an empty value
pub fn empty() -> Value {
Value::Value("".to_string())
}
/// Creates an empty array value
pub fn empty_array() -> Value {
Value::Array(Vec::new())
}
/// Create a value `Value::Array(Vec<String>)`, internal conversion to string
///
/// # Arguments
///
/// `array` array of type, type has to implement `Display` trait
#[deprecated]
pub fn from_array<T: Display>(array: &[T]) -> Self {
Value::Array(array.iter().map(|v| format!("{}", v)).collect())
}
/// Creates a value `Value::Value(String)`, internal conversion to string
///
/// # Arguments
///
/// `value` type has to implement `Display` trait
#[deprecated]
pub fn from_value<T: Display>(value: &T) -> Self {
Value::Value(format!("{}", value))
}
pub fn to_array<T: FromStr>(&self) -> Result<Vec<T>> {
match self {
Value::Array(value_array) => {
let mut target_array = Vec::with_capacity(value_array.len());
for value_string in value_array {
match value_string.parse::<T>() {
Ok(val) => target_array.push(val),
Err(_) => {
return Err(anyhow::Error::msg(format!(
"ConfigHandler: Error while parsing Value Array: {}",
value_string
)));
}
}
}
Ok(target_array)
}
_ => Err(anyhow::Error::msg(
"ConfigHandler: Error when requesting the wrong value type",
)),
}
}
pub fn to_value<T: FromStr>(&self) -> Result<T> {
match self {
Value::Value(value_string) => match value_string.parse::<T>() {
Ok(val) => Ok(val),
Err(_) => Err(anyhow::Error::msg(format!(
"ConfigHandler: Error while parsing Value Array: {}",
value_string
))),
},
_ => Err(anyhow::Error::msg(
"ConfigHandler: Error when requesting the wrong value type",
)),
}
}
}
impl<'a, T: Display> From<&'a T> for Value {
fn from(v: &'a T) -> Self {
Value::Value(format!("{}", v))
}
}
impl<'a, T: Display> From<&'a [T]> for Value {
fn from(v: &'a [T]) -> Self {
Value::Array(v.iter().map(|v| format!("{}", v)).collect())
}
}
/// Handler struct
pub struct ConfigHandler {}
impl ConfigHandler {
/// Reads the given config file
///
/// # Arguments
///
/// `file_name` file that is going to be read
pub fn read_config(
file_name: impl AsRef<Path>,
) -> Result<HashMap<String, HashMap<String, Value>>> {
let file = File::open(&file_name).with_context({
let file_name = file_name.as_ref().to_str().unwrap().to_string();
|| file_name
})?;
let mut infos = HashMap::new();
let mut current_section: Option<ConfigSection> = None;
for line_res in BufReader::new(file).lines() {
if let Ok(line) = line_res {
let mut trimmed = line.trim().to_string();
if trimmed.starts_with('#') || trimmed.is_empty() {
continue;
} else if trimmed.starts_with('[') && trimmed.ends_with(']') {
trimmed.remove(0);
trimmed.pop();
if let Some(ref section) = current_section {
infos.insert(section.header.clone(), section.body.clone());
}
current_section = Some(ConfigSection {
header: trimmed,
body: HashMap::new(),
});
} else {
let mut split = trimmed.split('=');
let key = match split.nth(0) {
Some(key) => key.trim().to_string(),
None => {
println!("cannot get key from line: {}", trimmed);
continue;
}
};
let value = match split.last() {
Some(value) => value.trim().to_string(),
None => {
println!("cannot get value from line: {}", trimmed);
continue;
}
};
if value.starts_with('[') && value.ends_with(']') {
let mut trimmed_value = value;
trimmed_value.remove(0);
trimmed_value.pop();
let value_split = trimmed_value.split(',');
let mut value_array = Vec::new();
for v in value_split {
let trimmed = v.trim();
if !trimmed.is_empty() {
value_array.push(trimmed.to_string());
}
}
if let Some(ref mut section) = current_section {
section.body.insert(key, Value::Array(value_array));
}
} else if let Some(ref mut section) = current_section {
section.body.insert(key, Value::Value(value));
}
}
}
}
// also push the last section
if let Some(section) = current_section {
infos.insert(section.header, section.body);
}
Ok(infos)
}
/// writes a formatted config file
///
/// # Arguments
///
/// `file_name` the file to which the config gets written
/// `sections` the sections and keys that are going to be written
pub fn write_config(
file_name: impl AsRef<Path>,
sections: &[(&str, Vec<(&str, Value)>)],
) -> Result<()> {
let mut file = File::create(file_name)?;
for (header, body) in sections {
let fmt_header = format!("[{}]\n", header);
file.write_all(fmt_header.as_bytes())?;
for (key, value) in body.iter() {
let fmt_key_value = format!(
"{} = {}\n",
key,
match value {
Value::Value(val) => val.clone(),
Value::Array(array) => {
let mut array_value = "[".to_string();
for (i, val) in array.iter().enumerate() {
// if element is not the last one
if i != array.len() - 1 {
array_value = format!("{}{}, ", array_value, val);
} else {
array_value = format!("{}{}", array_value, val);
}
}
format!("{}]", array_value)
}
}
);
file.write_all(fmt_key_value.as_bytes())?;
}
file.write_all("\n".as_bytes())?;
}
Ok(())
}
}
#[macro_export]
macro_rules! create_settings_section {
($struct_name:ident, $section_key:expr, {$($var:ident: $var_type:ty,)* $([$array:ident: $array_type:ty],)*} $(,$($derive:ident,)*)?) => {
#[derive(Default, Debug, Clone, PartialEq $(, $($derive,)* )? )]
pub struct $struct_name {
$(
pub $var: $var_type,
)*
$(
pub $array: Vec<$array_type>,
)*
}
impl $struct_name {
const SECTION_KEY: &'static str = $section_key;
pub fn load(
parsed_config: &std::collections::HashMap<String, std::collections::HashMap<String, Value>>
) -> anyhow::Result<Self> {
let mut me = Self::default();
if let Some(section) = parsed_config.get(Self::SECTION_KEY) {
$(
if let Some(value) = section.get(stringify!($var)) {
me.$var = value.to_value()?;
}
)*
$(
if let Some(array) = section.get(stringify!($array)) {
me.$array = array.to_array()?;
}
)*
}
Ok(me)
}
pub fn store(&self) -> (&str, Vec<(&str, Value)>) {
(
Self::SECTION_KEY,
vec![
$(
(stringify!($var), Value::from(&self.$var)),
)*
$(
(stringify!($array), Value::from(self.$array.as_slice())),
)*
]
)
}
}
};
}
#[macro_export]
macro_rules! create_settings_container {
($struct_name:ident, {$($var:ident: $var_type:ty$(,)?)*} $(,$($derive:ident,)*)? ) => {
#[derive(Default, Debug, Clone, PartialEq $(, $($derive,)* )? )]
pub struct $struct_name {
pub file_name: assetpath::AssetPath,
$(
pub $var: $var_type,
)*
}
impl $struct_name {
pub fn load(file: impl Into<assetpath::AssetPath>) -> anyhow::Result<Self> {
let file = file.into();
let parsed_stats_settings = ConfigHandler::read_config(&file.full_path())?;
Ok($struct_name {
file_name: file,
$(
$var: <$var_type>::load(&parsed_stats_settings)?,
)*
})
}
pub fn load_with_default(&mut self, file: impl Into<assetpath::AssetPath>) -> anyhow::Result<()> {
let file = file.into();
let parsed_stats_settings = ConfigHandler::read_config(&file.full_path())?;
self.file_name = file;
$(
self.$var = <$var_type>::load(&parsed_stats_settings)?;
)*
Ok(())
}
pub fn store(&self) -> anyhow::Result<()> {
ConfigHandler::write_config(
&self.file_name.full_path(),
&[
$(
self.$var.store(),
)*
]
)
}
}
};
}

View file

@ -6,6 +6,7 @@ extern crate parking_lot;
extern crate serde_json; extern crate serde_json;
extern crate typemap; extern crate typemap;
mod config_handler;
mod player; mod player;
use serenity::{ use serenity::{
@ -18,15 +19,15 @@ use serenity::{
}; };
// This imports `typemap`'s `Key` as `TypeMapKey`. // This imports `typemap`'s `Key` as `TypeMapKey`.
use anyhow::Result;
use serenity::prelude::*; use serenity::prelude::*;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use config_handler::{ConfigHandler, Value};
use player::prelude::*; use player::prelude::*;
use std::collections::HashSet; use std::collections::HashSet;
use utilities::prelude::*;
create_settings_section!( create_settings_section!(
Config, Config,
"Meta", "Meta",
@ -53,7 +54,7 @@ fn my_help(
help_commands::with_embeds(context, msg, args, &help_options, groups, owners) help_commands::with_embeds(context, msg, args, &help_options, groups, owners)
} }
fn main() -> VerboseResult<()> { fn main() -> Result<()> {
// read config file // read config file
let config_file = ConfigHandler::read_config("bot.conf")?; let config_file = ConfigHandler::read_config("bot.conf")?;

View file

@ -11,7 +11,7 @@ use serenity::{
model::channel::Message, model::channel::Message,
}; };
use utilities::prelude::*; use anyhow::{anyhow, Result};
use std::sync::Once; use std::sync::Once;
use std::thread; use std::thread;
@ -127,7 +127,7 @@ fn append_songs(
ctx: &Context, ctx: &Context,
msg: &Message, msg: &Message,
mut source: Vec<Song>, mut source: Vec<Song>,
) -> VerboseResult<()> { ) -> Result<()> {
media.playlist_mut().append(&mut source); media.playlist_mut().append(&mut source);
println!("start playing"); println!("start playing");
@ -141,7 +141,7 @@ fn handle_http_request(
ctx: &serenity::client::Context, ctx: &serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
url: &str, url: &str,
) -> VerboseResult<()> { ) -> Result<()> {
let mut names = Vec::new(); let mut names = Vec::new();
{ {
@ -149,18 +149,18 @@ fn handle_http_request(
let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") { let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result<String>) { let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
for name_result in rows { for name_result in rows {
let name = match name_result { let name = match name_result {
Ok(name) => name, Ok(name) => name,
Err(_) => create_error!("failed getting name from row"), Err(_) => return Err(anyhow!("failed getting name from row")),
}; };
names.push(name); names.push(name);
@ -170,7 +170,7 @@ fn handle_http_request(
if names.len() > 0 { if names.len() > 0 {
msg.channel_id msg.channel_id
.say(&ctx.http, "song already loaded!") .say(&ctx.http, "song already loaded!")
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
append_songs( append_songs(
media, media,
@ -186,7 +186,7 @@ fn handle_http_request(
msg.channel_id msg.channel_id
.say(&ctx.http, format!("Error using youtube-dl: {}", why)) .say(&ctx.http, format!("Error using youtube-dl: {}", why))
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
return Ok(()); return Ok(());
} }
@ -212,14 +212,14 @@ fn handle_http_request(
) )
.is_err() .is_err()
{ {
create_error!("failed inserting songs into db"); return Err(anyhow!("failed inserting songs into db"));
} }
} }
} }
msg.channel_id msg.channel_id
.say(&ctx.http, info) .say(&ctx.http, info)
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
append_songs(media, ctx, msg, source)?; append_songs(media, ctx, msg, source)?;
} }
@ -231,7 +231,7 @@ fn handle_local_request(
media: &mut MediaData, media: &mut MediaData,
ctx: &serenity::client::Context, ctx: &serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
) -> VerboseResult<()> { ) -> Result<()> {
let mut songs = Vec::new(); let mut songs = Vec::new();
{ {
@ -239,18 +239,18 @@ fn handle_local_request(
let mut stmt = match sql.prepare("SELECT name FROM Vulva3") { let mut stmt = match sql.prepare("SELECT name FROM Vulva3") {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) { let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
for name_result in rows { for name_result in rows {
let name = match name_result { let name = match name_result {
Ok(name) => name, Ok(name) => name,
Err(_) => create_error!("failed getting name from row"), Err(_) => return Err(anyhow!("failed getting name from row")),
}; };
songs.push(Song { name }); songs.push(Song { name });
@ -270,7 +270,7 @@ fn handle_song_request(
ctx: &serenity::client::Context, ctx: &serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
pattern: &str, pattern: &str,
) -> VerboseResult<()> { ) -> Result<()> {
println!("song request ({})", pattern); println!("song request ({})", pattern);
let mut songs = Vec::new(); let mut songs = Vec::new();
@ -283,18 +283,18 @@ fn handle_song_request(
pattern pattern
)) { )) {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) { let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
for name_result in rows { for name_result in rows {
let name = match name_result { let name = match name_result {
Ok(name) => name, Ok(name) => name,
Err(_) => create_error!("failed getting name from row"), Err(_) => return Err(anyhow!("failed getting name from row")),
}; };
songs.push(Song { name }); songs.push(Song { name });
@ -313,7 +313,7 @@ fn handle_song_request(
} else { } else {
msg.channel_id msg.channel_id
.say(&ctx.http, format!("no song found with pattern {}", pattern)) .say(&ctx.http, format!("no song found with pattern {}", pattern))
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
} }
Ok(()) Ok(())
@ -324,7 +324,7 @@ fn handle_tag_request(
ctx: &serenity::client::Context, ctx: &serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
pattern: &str, pattern: &str,
) -> VerboseResult<()> { ) -> Result<()> {
let mut songs = Vec::new(); let mut songs = Vec::new();
{ {
@ -333,37 +333,37 @@ fn handle_tag_request(
pattern pattern
)) { )) {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let mut rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) let mut rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>)
{ {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
if let None = rows.next() { if let None = rows.next() {
msg.channel_id msg.channel_id
.say(&ctx.http, format!("tag ({}) not found", pattern)) .say(&ctx.http, format!("tag ({}) not found", pattern))
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
return Ok(()); return Ok(());
} }
let mut stmt = match media.db().prepare(&format!("SELECT name FROM {}", pattern)) { let mut stmt = match media.db().prepare(&format!("SELECT name FROM {}", pattern)) {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) { let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
for name_result in rows { for name_result in rows {
let name = match name_result { let name = match name_result {
Ok(name) => name, Ok(name) => name,
Err(_) => create_error!("failed getting name from row"), Err(_) => return Err(anyhow!("failed getting name from row")),
}; };
songs.push(Song { name }); songs.push(Song { name });

View file

@ -13,10 +13,9 @@ use super::prelude::*;
use std::fs; use std::fs;
use anyhow::{anyhow, Result};
use rusqlite::{params, Connection}; use rusqlite::{params, Connection};
use utilities::prelude::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Song { pub struct Song {
pub name: String, pub name: String,
@ -74,7 +73,7 @@ impl MediaData {
&mut self, &mut self,
ctx: &serenity::client::Context, ctx: &serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
) -> Result<(), String> { ) -> Result<()> {
self.playlist.clear(); self.playlist.clear();
self.current_song = None; self.current_song = None;
self.song_name = String::new(); self.song_name = String::new();
@ -124,11 +123,7 @@ impl MediaData {
&mut self.song_name &mut self.song_name
} }
pub fn start_playing( pub fn start_playing(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> Result<()> {
ctx: &Context,
mediadata: &mut MediaData,
msg: &Message,
) -> VerboseResult<()> {
// check if there is already playing // check if there is already playing
let already_started = mediadata.song().is_some(); let already_started = mediadata.song().is_some();
@ -141,7 +136,7 @@ impl MediaData {
Ok(()) Ok(())
} }
fn check_for_next(&mut self, ctx: &Context, msg: &Message) -> VerboseResult<String> { fn check_for_next(&mut self, ctx: &Context, msg: &Message) -> Result<String> {
println!("check for next"); println!("check for next");
while !self.playlist().is_empty() { while !self.playlist().is_empty() {
@ -158,7 +153,7 @@ impl MediaData {
&first &first
), ),
) )
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
let sql = self.db(); let sql = self.db();
@ -166,19 +161,19 @@ impl MediaData {
let mut stmt = let mut stmt =
match sql.prepare("SELECT name FROM sqlite_master WHERE type='table'") { match sql.prepare("SELECT name FROM sqlite_master WHERE type='table'") {
Ok(statement) => statement, Ok(statement) => statement,
Err(_) => create_error!("failed preparing data base access"), Err(_) => return Err(anyhow!("failed preparing data base access")),
}; };
let rows = let rows =
match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) { match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result<String>) {
Ok(rows) => rows, Ok(rows) => rows,
Err(_) => create_error!("failed querying rows"), Err(_) => return Err(anyhow!("failed querying rows")),
}; };
for row in rows { for row in rows {
let table_name = match row { let table_name = match row {
Ok(name) => name, Ok(name) => name,
Err(_) => create_error!("failed getting name from row"), Err(_) => return Err(anyhow!("failed getting name from row")),
}; };
if let Err(_) = sql.execute( if let Err(_) = sql.execute(
@ -194,14 +189,14 @@ impl MediaData {
} }
println!("no song found!"); println!("no song found!");
create_error!("no suitable song found!") Err(anyhow!("no suitable song found!"))
} }
fn check_for_channel<T: RawMutex>( fn check_for_channel<T: RawMutex>(
manager: &mut MutexGuard<T, ClientVoiceManager>, manager: &mut MutexGuard<T, ClientVoiceManager>,
ctx: &Context, ctx: &Context,
msg: &Message, msg: &Message,
) -> VerboseResult<()> { ) -> Result<()> {
println!("check for channel!"); println!("check for channel!");
let guild = guild(ctx, msg)?; let guild = guild(ctx, msg)?;
@ -216,7 +211,7 @@ impl MediaData {
.and_then(|voice_state| voice_state.channel_id) .and_then(|voice_state| voice_state.channel_id)
{ {
Some(channel) => channel, Some(channel) => channel,
None => create_error!("author is not in a voice channel!"), None => return Err(anyhow!("author is not in a voice channel!")),
}; };
println!("got author channel"); println!("got author channel");
@ -238,7 +233,7 @@ impl MediaData {
Ok(()) Ok(())
} }
pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> VerboseResult<()> { pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> Result<()> {
println!("start next song"); println!("start next song");
let voice_manager = mediadata.voice_manager.clone(); let voice_manager = mediadata.voice_manager.clone();
let mut manager = voice_manager.lock(); let mut manager = voice_manager.lock();
@ -269,7 +264,7 @@ impl MediaData {
Some(handler) => handler, Some(handler) => handler,
None => { None => {
println!("failed getting handler"); println!("failed getting handler");
create_error!("error getting handler"); return Err(anyhow!("error getting handler"));
} }
} }
}; };
@ -278,7 +273,7 @@ impl MediaData {
let source = match ffmpeg(first.clone()) { let source = match ffmpeg(first.clone()) {
Ok(mpeg) => mpeg, Ok(mpeg) => mpeg,
Err(_) => create_error!(format!("failed loading: {}", &first)), Err(_) => return Err(anyhow!(format!("failed loading: {}", &first))),
}; };
handler.stop(); handler.stop();
@ -295,7 +290,7 @@ impl MediaData {
msg.channel_id msg.channel_id
.say(&ctx.http, format!("Playing song: {}", first)) .say(&ctx.http, format!("Playing song: {}", first))
.map_err(|err| format!("{}", err))?; .map_err(|err| anyhow!("{}", err))?;
} }
if need_to_leave { if need_to_leave {

View file

@ -8,14 +8,14 @@ use serenity::voice::Handler;
use std::sync::Arc; use std::sync::Arc;
use utilities::prelude::*; use anyhow::{anyhow, Result};
// This imports `typemap`'s `Key` as `TypeMapKey`. // This imports `typemap`'s `Key` as `TypeMapKey`.
use serenity::prelude::*; use serenity::prelude::*;
use super::prelude::*; use super::prelude::*;
pub fn guild(ctx: &Context, msg: &Message) -> Result<Arc<SerRwLock<Guild>>, String> { pub fn guild(ctx: &Context, msg: &Message) -> Result<Arc<SerRwLock<Guild>>> {
match msg.guild(&ctx.cache) { match msg.guild(&ctx.cache) {
Some(guild) => Ok(guild), Some(guild) => Ok(guild),
None => { None => {
@ -25,12 +25,12 @@ pub fn guild(ctx: &Context, msg: &Message) -> Result<Arc<SerRwLock<Guild>>, Stri
.is_err() .is_err()
{} {}
Err("failed getting Guild".to_string()) Err(anyhow!("failed getting Guild"))
} }
} }
} }
pub fn guild_id(ctx: &Context, msg: &Message) -> Result<GuildId, String> { pub fn guild_id(ctx: &Context, msg: &Message) -> Result<GuildId> {
let guild = guild(ctx, msg)?; let guild = guild(ctx, msg)?;
let guild_read = guild.read(); let guild_read = guild.read();
@ -47,7 +47,7 @@ pub fn handler<'a, T: RawMutex>(
pub fn channel_contains_author( pub fn channel_contains_author(
ctx: &mut serenity::client::Context, ctx: &mut serenity::client::Context,
msg: &serenity::model::channel::Message, msg: &serenity::model::channel::Message,
) -> VerboseResult<()> { ) -> Result<()> {
let guild = guild(ctx, msg)?; let guild = guild(ctx, msg)?;
let guild_id = guild.read().id; let guild_id = guild.read().id;
@ -58,7 +58,7 @@ pub fn channel_contains_author(
.and_then(|voice_state| voice_state.channel_id) .and_then(|voice_state| voice_state.channel_id)
{ {
Some(channel) => channel, Some(channel) => channel,
None => create_error!("author is not in a voice channel!"), None => return Err(anyhow!("author is not in a voice channel!")),
}; };
if let Some(media) = ctx.data.read().get::<Media>() { if let Some(media) = ctx.data.read().get::<Media>() {
@ -69,7 +69,9 @@ pub fn channel_contains_author(
// check if the bot is in a channel // check if the bot is in a channel
if let Some(bot_channel_id) = handler.channel_id { if let Some(bot_channel_id) = handler.channel_id {
if bot_channel_id != author_channel_id { if bot_channel_id != author_channel_id {
create_error!("author is not in the same voice channel as the bot!"); return Err(anyhow!(
"author is not in the same voice channel as the bot!"
));
} }
} }
}; };

View file

@ -23,7 +23,7 @@ fn convert_output(out: &Output) -> Result<Vec<String>, String> {
let file_name = line.split_off(FIRST_LOAD_PREFIX.len()); let file_name = line.split_off(FIRST_LOAD_PREFIX.len());
files.push(file_name.trim().to_string()); files.push(file_name.trim().to_string());
} else if line.ends_with(RELOAD_SUFFIX) { } else if line.ends_with(RELOAD_SUFFIX) {
line.split_off(line_len - RELOAD_SUFFIX.len()); line.truncate(line_len - RELOAD_SUFFIX.len());
let file_name = line.split_off(PREFIX.len()); let file_name = line.split_off(PREFIX.len());
files.push(file_name.trim().to_string()); files.push(file_name.trim().to_string());
} }