Update deps and error handling
This commit is contained in:
parent
767ced2df0
commit
17d4a3e02a
7 changed files with 361 additions and 60 deletions
|
@ -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
304
src/config_handler.rs
Normal 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(),
|
||||||
|
)*
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -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")?;
|
||||||
|
|
||||||
|
|
|
@ -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 });
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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!"
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue