diff --git a/Cargo.toml b/Cargo.toml index 68a30db..b5cd5f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,8 @@ authors = ["hodasemi "] [dependencies] typemap = "~0.3" serde_json = "*" -rand = "0.6" +utilities = { git = "http://dimov.cloud/hodasemi/utilities" } rusqlite = { version = "*", features = ["bundled"] } -serenity = { version = "0.6", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]} -lock_api = "0.2.0" +serenity = { version = "0.7", default-features = false, features = [ "builder", "cache", "client", "framework", "gateway", "model", "standard_framework", "utils", "voice", "rustls_backend"]} parking_lot = "*" +failure = "*" diff --git a/Penis1 b/Penis1 index 5ef5846..dbaef54 100644 Binary files a/Penis1 and b/Penis1 differ diff --git a/src/confighandler.rs b/src/confighandler.rs deleted file mode 100644 index ec1f502..0000000 --- a/src/confighandler.rs +++ /dev/null @@ -1,204 +0,0 @@ -#![allow(dead_code)] - -use std::fmt::Display; -use std::fs::File; -use std::io::{BufRead, BufReader, Write}; -use std::str::FromStr; - -use std::collections::HashMap; - -#[derive(Clone)] -pub enum Value { - Value(String), - Array(Vec), -} - -struct ConfigSection { - header: String, - body: HashMap, -} - -impl Value { - pub fn empty() -> Value { - Value::Value("".to_string()) - } - - pub fn value(value: &T) -> Value - where - T: Display, - { - Value::Value(format!("{}", value)) - } - - pub fn array(array: &Vec) -> Value - where - T: Display, - { - Value::Array(array.iter().map(|v| format!("{}", v)).collect()) - } - - pub fn set_value(&self, value: &mut T) -> Result<(), String> - where - T: FromStr, - { - match self { - Value::Value(value_string) => match value_string.parse::() { - Ok(val) => *value = val, - Err(_) => return Err(format!("error parsing value {}", value_string)), - }, - _ => return Err("key_value has wrong format".to_string()), - }; - - Ok(()) - } - - pub fn set_array(&self, array: &mut Vec) -> Result<(), String> - where - T: FromStr, - { - match self { - Value::Array(value_array) => { - for value_string in value_array { - match value_string.parse::() { - Ok(val) => array.push(val), - Err(_) => return Err(format!("error parsing value {}", value_string)), - } - } - } - _ => return Err("key_value has wrong format".to_string()), - }; - - Ok(()) - } -} - -pub fn read_config(file_name: &str) -> Result>, String> { - let file = match File::open(file_name) { - Ok(file) => file, - Err(msg) => return Err(format!("error opening config file({}): {}", file_name, msg)), - }; - - let mut infos = HashMap::new(); - let mut current_section: Option = 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 value_array = value_split.map(|v| v.trim().to_string()).collect(); - - 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) -} - -pub fn write_config( - file_name: &str, - sections: &Vec<(String, Vec<(String, Value)>)>, -) -> Result<(), String> { - let mut file = match File::create(file_name) { - Ok(file) => file, - Err(msg) => { - return Err(format!( - "error creating config file({}): {}", - file_name, msg - )) - } - }; - - for (header, body) in sections { - let fmt_header = format!("[{}]\n", header); - - if let Err(_) = file.write_all(fmt_header.as_bytes()) { - return Err(format!("failed writing section: {}", fmt_header)); - } - - for (key, value) in body { - 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) - } - } - ); - - if let Err(_) = file.write_all(fmt_key_value.as_bytes()) { - return Err(format!("failed writing key value: {}", fmt_key_value)); - } - } - - if let Err(_) = file.write_all("\n".as_bytes()) { - return Err("failed writing new line".to_string()); - } - } - - Ok(()) -} diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index a14e0b9..0000000 --- a/src/macros.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![macro_use] - -/// check result macro, where the Ok() is the type which should be returned -#[macro_export] -macro_rules! check_result { - ($v:expr) => { - match $v { - Ok(t) => t, - Err(msg) => return Err(msg), - } - }; -} - -/// check result macro, where the Ok() is the type which should be returned, else print error and return -#[macro_export] -macro_rules! check_result_return { - ($v:expr) => { - match $v { - Ok(t) => t, - Err(msg) => { - println!("{}", msg); - return; - } - } - }; -} - -/// check result macro, where the Ok() is the type which should be returned, else print error and return -#[macro_export] -macro_rules! check_result_return_ok { - ($v:expr) => { - match $v { - Ok(t) => t, - Err(msg) => { - println!("{}", msg); - return Ok(()); - } - } - }; -} - -// check result macro, where the Ok() is void -#[macro_export] -macro_rules! check_error { - ($v:expr) => { - if let Err(msg) = $v { - return Err(msg); - }; - }; -} - -/// check result macro, where the Ok() is void, but just print the error message -#[macro_export] -macro_rules! display_error { - ($v:expr) => { - if let Err(msg) = $v { - println!("{}", msg); - return; - }; - }; -} - -/// check result macro, where the Ok() is void, but just print the error message -#[macro_export] -macro_rules! display_error_ok { - ($v:expr) => { - if let Err(msg) = $v { - println!("{}", msg); - return Ok(()); - }; - }; -} - -macro_rules! print_error { - ($v:expr) => { - if let Err(msg) = $v { - println!("{}", msg); - }; - }; -} diff --git a/src/main.rs b/src/main.rs index 35269d8..80f6b5a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,12 +3,9 @@ extern crate serenity; extern crate parking_lot; -extern crate rand; extern crate serde_json; extern crate typemap; -mod confighandler; -mod macros; mod player; use serenity::{ @@ -31,10 +28,11 @@ use serenity::prelude::*; use std::sync::Arc; -use confighandler::*; use player::prelude::*; use std::collections::HashSet; +use utilities::prelude::*; + struct Config { token: String, prefix: String, @@ -55,9 +53,9 @@ group!({ commands: [ip, list, pause, play, remove, skip, stop] }); -fn main() { +fn main() -> VerboseResult<()> { // read config file - let config_file = check_result_return!(read_config("bot.conf")); + let config_file = ConfigHandler::read_config("bot.conf")?; let mut config = Config::default(); @@ -65,26 +63,23 @@ fn main() { Some(info) => { match info.get("token") { Some(token_pair) => { - display_error!(token_pair.set_value(&mut config.token)); + token_pair.set_value(&mut config.token)?; } None => { - println!("couldn't find token inside meta section"); - return; + create_error!("couldn't find token inside meta section"); } } match info.get("prefix") { Some(prefix_pair) => { - display_error!(prefix_pair.set_value(&mut config.prefix)); + prefix_pair.set_value(&mut config.prefix)?; } None => { - println!("couldn't find prefix inside meta section"); - return; + create_error!("couldn't find prefix inside meta section"); } } } None => { - println!("couldn't find Meta section in config file"); - return; + create_error!("couldn't find Meta section in config file"); } }; @@ -95,8 +90,10 @@ fn main() { // event handlers and framework commands. { let mut data = client.data.write(); - data.insert::(Arc::clone(&client.voice_manager)); - data.insert::(MediaData::new("Penis1").expect("failed to create media data handle")); + data.insert::( + MediaData::new("Penis1", Arc::clone(&client.voice_manager)) + .expect("failed to create media data handle"), + ); } // We will fetch your bot's owners and id @@ -161,4 +158,6 @@ fn main() { let _ = client .start() .map_err(|why| println!("Client ended: {:?}", why)); + + Ok(()) } diff --git a/src/player/commands/ip.rs b/src/player/commands/ip.rs index b0e47e9..811bd27 100644 --- a/src/player/commands/ip.rs +++ b/src/player/commands/ip.rs @@ -27,8 +27,8 @@ fn ip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { } match from_utf8(out.stdout.as_slice()) { - Ok(string) => print_error!(msg.author.direct_message(&ctx, |m| m.content(string))), - Err(_) => print_error!(msg.channel_id.say(&ctx.http, "error getting IP string")), + Ok(string) => msg.author.direct_message(&ctx, |m| m.content(string))?, + Err(_) => msg.channel_id.say(&ctx.http, "error getting IP string")?, }; Ok(()) diff --git a/src/player/commands/list.rs b/src/player/commands/list.rs index 73837ee..8a9e216 100644 --- a/src/player/commands/list.rs +++ b/src/player/commands/list.rs @@ -8,11 +8,8 @@ use serenity::{ #[command] fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + if let Err(err) = channel_contains_author(ctx, msg) { + msg.channel_id.say(&ctx.http, err)?; return Ok(()); } @@ -22,7 +19,7 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { let media = match data.get::() { Some(media) => media, None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); + msg.channel_id.say(&ctx.http, "could not find media data")?; return Ok(()); } }; @@ -46,7 +43,7 @@ fn list(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { } } - print_error!(msg.channel_id.say(&ctx.http, output)); + msg.channel_id.say(&ctx.http, output)?; Ok(()) } diff --git a/src/player/commands/pause.rs b/src/player/commands/pause.rs index 0afb3f5..2441f99 100644 --- a/src/player/commands/pause.rs +++ b/src/player/commands/pause.rs @@ -10,11 +10,8 @@ use serenity::{ #[command] fn pause(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + if let Err(err) = channel_contains_author(ctx, msg) { + msg.channel_id.say(&ctx.http, err)?; return Ok(()); } @@ -22,7 +19,7 @@ fn pause(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { let media = match data.get::() { Some(media) => media, None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); + msg.channel_id.say(&ctx.http, "could not find media data")?; return Ok(()); } }; diff --git a/src/player/commands/play.rs b/src/player/commands/play.rs index 498c05d..ca912da 100644 --- a/src/player/commands/play.rs +++ b/src/player/commands/play.rs @@ -1,13 +1,9 @@ -use lock_api::RawMutex; - -use std::sync::Arc; - -use rand::{seq::SliceRandom, thread_rng}; - use super::super::prelude::*; use rusqlite::params; +use rand::{seq::SliceRandom, thread_rng}; + use serenity::prelude::*; use serenity::voice::LockedAudio; use serenity::{ @@ -15,13 +11,12 @@ use serenity::{ model::channel::Message, }; +use utilities::prelude::*; + #[command] fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + if let Err(err) = channel_contains_author(ctx, msg) { + msg.channel_id.say(&ctx.http, err)?; return Ok(()); } @@ -29,33 +24,32 @@ fn play(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { let media = match data.get_mut::() { Some(media) => media, None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); + msg.channel_id.say(&ctx.http, "could not find media data")?; return Ok(()); } }; if args.len() == 0 { if !check_for_continue(media.song_mut()) { - print_error!(msg - .channel_id - .say(&ctx.http, "Must provide a URL to a video or audio")); - } - } else if args.len() == 1 { - let arg = match args.single::() { - Ok(arg) => arg, - // can't happen, since we tested for length == 1 - Err(_) => return Ok(()), - }; - - if arg == "--local" { - handle_local_request(media, ctx, msg)?; - } else if arg.starts_with("http") { - handle_http_request(media, ctx, msg, &arg)?; - } else { - handle_song_request(media, ctx, msg, &arg)?; + msg.channel_id + .say(&ctx.http, "Must provide a URL to a video or audio")?; } } else { - print_error!(msg.channel_id.say(&ctx.http, "Unsupported argument list")); + let first_arg = args.current().unwrap(); + + if first_arg == "--local" { + handle_local_request(media, ctx, msg)?; + } else if first_arg.starts_with("http") { + handle_http_request(media, ctx, msg, first_arg)?; + } else { + let mut arg_list = String::new(); + + for arg in args.iter::() { + arg_list += &format!(" {}", arg?.trim()); + } + + handle_song_request(media, ctx, msg, &arg_list)?; + } } Ok(()) @@ -74,63 +68,15 @@ fn check_for_continue(song_lock: &Option) -> bool { } } -fn check_join_channel( - manager_lock: &Arc>, - ctx: &Context, - msg: &Message, -) { - let guild = check_result_return!(guild(ctx, msg)); - let guild_id = check_result_return!(guild_id(ctx, msg)); - - let channel_id = guild - .read() - .voice_states - .get(&msg.author.id) - .and_then(|voice_state| voice_state.channel_id); - - let connect_to = match channel_id { - Some(channel) => channel, - None => { - display_error!(msg.reply(ctx, "Not in a voice channel")); - - return; - } - }; - - let mut manager = manager_lock.lock(); - manager.join(guild_id, connect_to); -} - fn append_songs( media: &mut MediaData, ctx: &Context, msg: &Message, mut source: Vec, -) -> Result<(), String> { +) -> VerboseResult<()> { media.playlist_mut().append(&mut source); - if let Some(manager_lock) = ctx.data.read().get::().cloned() { - check_join_channel(&manager_lock, ctx, msg); - - // let check_finished = { - // let channel_id = msg.channel_id; - // let manager_lock_clone = manager_lock.clone(); - - // Arc::new(move || { - // let callback = match media.next_callback.borrow().deref() { - // Some(callback) => callback.clone(), - // None => { - // println!("next_callback not set!"); - // return; - // } - // }; - - // MediaData::next_song(&media_clone, channel_id, &manager_lock_clone, callback); - // }) - // }; - - MediaData::start_playing(ctx, media, msg, &manager_lock); - } + MediaData::start_playing(ctx, media, msg)?; Ok(()) } @@ -139,8 +85,8 @@ fn handle_http_request( media: &mut MediaData, ctx: &serenity::client::Context, msg: &serenity::model::channel::Message, - url: &String, -) -> Result<(), String> { + url: &str, +) -> VerboseResult<()> { let mut names = Vec::new(); { @@ -148,18 +94,18 @@ fn handle_http_request( let mut stmt = match sql.prepare("SELECT name FROM Vulva3 WHERE link = ?") { Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), + Err(_) => create_error!("failed preparing data base access"), }; let rows = match stmt.query_map(&[url], |row| row.get(0) as rusqlite::Result) { Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), + Err(_) => create_error!("failed querying rows"), }; for name_result in rows { let name = match name_result { Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), + Err(_) => create_error!("failed getting name from row"), }; names.push(name); @@ -167,7 +113,9 @@ fn handle_http_request( } if names.len() > 0 { - print_error!(msg.channel_id.say(&ctx.http, "song already loaded!")); + msg.channel_id + .say(&ctx.http, "song already loaded!") + .map_err(|err| format!("{}", err))?; append_songs( media, @@ -181,9 +129,9 @@ fn handle_http_request( Err(why) => { println!("Err starting source: {:?}", why); - print_error!(msg - .channel_id - .say(&ctx.http, format!("Error using youtube-dl: {}", why))); + msg.channel_id + .say(&ctx.http, format!("Error using youtube-dl: {}", why)) + .map_err(|err| format!("{}", err))?; return Ok(()); } @@ -209,12 +157,14 @@ fn handle_http_request( ) .is_err() { - return Err("failed inserting songs into db".to_string()); + create_error!("failed inserting songs into db"); } } } - print_error!(msg.channel_id.say(&ctx.http, info)); + msg.channel_id + .say(&ctx.http, info) + .map_err(|err| format!("{}", err))?; append_songs(media, ctx, msg, source)?; } @@ -226,7 +176,7 @@ fn handle_local_request( media: &mut MediaData, ctx: &serenity::client::Context, msg: &serenity::model::channel::Message, -) -> Result<(), String> { +) -> VerboseResult<()> { let mut songs = Vec::new(); { @@ -234,18 +184,18 @@ fn handle_local_request( let mut stmt = match sql.prepare("SELECT name FROM Vulva3") { Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), + Err(_) => create_error!("failed preparing data base access"), }; let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), + Err(_) => create_error!("failed querying rows"), }; for name_result in rows { let name = match name_result { Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), + Err(_) => create_error!("failed getting name from row"), }; songs.push(Song { name }); @@ -265,7 +215,7 @@ fn handle_song_request( ctx: &serenity::client::Context, msg: &serenity::model::channel::Message, pattern: &str, -) -> Result<(), String> { +) -> VerboseResult<()> { let mut songs = Vec::new(); { @@ -276,18 +226,18 @@ fn handle_song_request( pattern )) { Ok(statement) => statement, - Err(_) => return Err("failed preparing data base access".to_string()), + Err(_) => create_error!("failed preparing data base access"), }; let rows = match stmt.query_map(params![], |row| row.get(0) as rusqlite::Result) { Ok(rows) => rows, - Err(_) => return Err("failed querying rows".to_string()), + Err(_) => create_error!("failed querying rows"), }; for name_result in rows { let name = match name_result { Ok(name) => name, - Err(_) => return Err("failed getting name from row".to_string()), + Err(_) => create_error!("failed getting name from row"), }; songs.push(Song { name }); @@ -300,9 +250,9 @@ fn handle_song_request( append_songs(media, ctx, msg, songs)?; } else { - print_error!(msg - .channel_id - .say(&ctx.http, format!("no song found with pattern {}", pattern))); + msg.channel_id + .say(&ctx.http, format!("no song found with pattern {}", pattern)) + .map_err(|err| format!("{}", err))?; } Ok(()) diff --git a/src/player/commands/remove.rs b/src/player/commands/remove.rs index cafec6f..5658532 100644 --- a/src/player/commands/remove.rs +++ b/src/player/commands/remove.rs @@ -18,7 +18,7 @@ fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { let media = match data.get::() { Some(media) => media, None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); + msg.channel_id.say(&ctx.http, "could not find media data")?; return Ok(()); } }; @@ -34,14 +34,14 @@ fn remove(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { if !song_name.is_empty() { match fs::remove_file(&song_name) { - Ok(_) => print_error!(msg.channel_id.say( + Ok(_) => msg.channel_id.say( &ctx.http, - format!("Remove current song ({}) from local disk", song_name) - )), - Err(err) => print_error!(msg.channel_id.say( + format!("Remove current song ({}) from local disk", song_name), + )?, + Err(err) => msg.channel_id.say( &ctx.http, - format!("Error removing file ({}): {:?}", song_name, err.kind()) - )), + format!("Error removing file ({}): {:?}", song_name, err.kind()), + )?, }; } diff --git a/src/player/commands/skip.rs b/src/player/commands/skip.rs index e082273..de5769d 100644 --- a/src/player/commands/skip.rs +++ b/src/player/commands/skip.rs @@ -11,35 +11,24 @@ use serenity::{ #[command] fn skip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + if let Err(err) = channel_contains_author(ctx, msg) { + msg.channel_id.say(&ctx.http, err)?; return Ok(()); } let mut data = ctx.data.write(); - if let Some(manager_lock) = data.get_mut::().cloned() { - let mut manager = manager_lock.lock(); + if let Some(media) = data.get_mut::() { + let voice_manager = media.voice_manager.clone(); + let mut manager = voice_manager.lock(); - let guild_id = check_result_return_ok!(guild_id(ctx, msg)); + let guild_id = guild_id(ctx, msg)?; if let Some(handler) = handler(guild_id, &mut manager) { - let media = match data.get_mut::() { - Some(media) => media, - None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); - return Ok(()); - } - }; - // if current song is the last song in this playlist, just return if media.playlist().is_empty() { - print_error!(msg - .channel_id - .say(&ctx.http, "playlist is empty, no next song available")); + msg.channel_id + .say(&ctx.http, "playlist is empty, no next song available")?; return Ok(()); } else { @@ -78,10 +67,10 @@ fn skip(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { *media.song_mut() = Some(handler.play_returning(source)); *media.song_name_mut() = first.name.clone(); - print_error!(msg.channel_id.say( + msg.channel_id.say( &ctx.http, - format!("Skipped current song, now playing: {}", first.name) - )); + format!("Skipped current song, now playing: {}", first.name), + )?; } } } diff --git a/src/player/commands/stop.rs b/src/player/commands/stop.rs index 33cc5a7..9ecb3ae 100644 --- a/src/player/commands/stop.rs +++ b/src/player/commands/stop.rs @@ -8,11 +8,8 @@ use serenity::{ #[command] fn stop(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { - if !channel_contains_author(ctx, msg) { - println!( - "user {} is not in the same voice channel as the bot", - msg.author.name - ); + if let Err(err) = channel_contains_author(ctx, msg) { + msg.channel_id.say(&ctx.http, err)?; return Ok(()); } @@ -20,12 +17,12 @@ fn stop(ctx: &mut Context, msg: &Message, _: Args) -> CommandResult { let media = match data.get_mut::() { Some(media) => media, None => { - display_error_ok!(msg.channel_id.say(&ctx.http, "could not find media data")); + msg.channel_id.say(&ctx.http, "could not find media data")?; return Ok(()); } }; - print_error!(media.reset(ctx, msg)); + media.reset(ctx, msg)?; Ok(()) } diff --git a/src/player/mediadata.rs b/src/player/mediadata.rs index 1879f3b..d261304 100644 --- a/src/player/mediadata.rs +++ b/src/player/mediadata.rs @@ -4,12 +4,16 @@ use serenity::prelude::*; use serenity::voice::ffmpeg; use serenity::voice::LockedAudio; +use serenity::client::bridge::voice::ClientVoiceManager; +use serenity::prelude::Mutex; use std::sync::Arc; use super::prelude::*; use rusqlite::{params, Connection}; +use utilities::prelude::*; + pub struct Song { pub name: String, } @@ -18,13 +22,18 @@ pub struct MediaData { playlist: Vec, current_song: Option, song_name: String, - pub next_callback: Option ()>>, + pub next_callback: Option ()>>, sql_data_base: Connection, + + pub voice_manager: Arc>, } impl MediaData { - pub fn new(file: &str) -> Result { + pub fn new( + file: &str, + voice_manager: Arc>, + ) -> Result { let connection = match Connection::open(file) { Ok(file) => file, Err(_) => return Err(format!("can't open {}", file)), @@ -51,6 +60,8 @@ impl MediaData { next_callback: None, sql_data_base: connection, + + voice_manager, }) } @@ -64,8 +75,8 @@ impl MediaData { self.song_name = String::new(); self.next_callback = None; - if let Some(manager_lock) = ctx.data.read().get::().cloned() { - let mut manager = manager_lock.lock(); + if let Some(media) = ctx.data.read().get::() { + let mut manager = media.voice_manager.lock(); let guild_id = guild_id(ctx, msg)?; @@ -118,30 +129,23 @@ impl MediaData { ctx: &Context, mediadata: &mut MediaData, msg: &Message, - manager_lock: &Arc< - serenity::prelude::Mutex, - >, - ) { + ) -> VerboseResult<()> { // check if there is already playing - let already_started = { mediadata.song().is_some() }; + let already_started = mediadata.song().is_some(); // if there isnt already a song playing, start a new one if !already_started { - Self::next_song(ctx, mediadata, msg, manager_lock); + Self::next_song(ctx, mediadata, msg)?; } + + Ok(()) } - pub fn next_song( - ctx: &Context, - mediadata: &mut MediaData, - msg: &Message, - manager_lock: &Arc< - serenity::prelude::Mutex, - >, - ) { - let mut manager = manager_lock.lock(); + pub fn next_song(ctx: &Context, mediadata: &mut MediaData, msg: &Message) -> VerboseResult<()> { + let voice_manager = mediadata.voice_manager.clone(); + let mut manager = voice_manager.lock(); - let guild_id = check_result_return!(guild_id(ctx, msg)); + let guild_id = guild_id(ctx, msg)?; let mut need_to_leave = false; @@ -150,8 +154,7 @@ impl MediaData { match handler(guild_id, &mut manager) { Some(handler) => handler, None => { - println!("error getting handler"); - return; + create_error!("error getting handler"); } } }; @@ -171,22 +174,24 @@ impl MediaData { Err(_) => { mediadata.playlist_mut().clear(); - return; + return Ok(()); } }; *mediadata.song_mut() = Some(handler.play_returning(source)); *mediadata.song_name_mut() = first.name.clone(); - print_error!(msg - .channel_id - .say(&ctx.http, format!("Playing song: {}", first.name))); + msg.channel_id + .say(&ctx.http, format!("Playing song: {}", first.name)) + .map_err(|err| format!("{}", err))?; } } if need_to_leave { manager.remove(guild_id); } + + Ok(()) } } diff --git a/src/player/mod.rs b/src/player/mod.rs index fb79e12..b89a4d4 100644 --- a/src/player/mod.rs +++ b/src/player/mod.rs @@ -1,7 +1,6 @@ pub mod eventhandler; pub mod mediadata; pub mod player; -pub mod voicemanager; mod youtube; pub mod commands; diff --git a/src/player/player.rs b/src/player/player.rs index c25e24e..3a2b4c7 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -1,4 +1,4 @@ -use lock_api::{MutexGuard, RawMutex}; +use parking_lot::lock_api::{MutexGuard, RawMutex}; use serenity; use serenity::model::channel::Message; use serenity::model::guild::Guild; @@ -8,6 +8,8 @@ use serenity::voice::Handler; use std::sync::Arc; +use utilities::prelude::*; + // This imports `typemap`'s `Key` as `TypeMapKey`. use serenity::prelude::*; @@ -45,64 +47,39 @@ pub fn handler<'a, T: RawMutex>( pub fn channel_contains_author( ctx: &mut serenity::client::Context, msg: &serenity::model::channel::Message, -) -> bool { - let (guild_id, voice_channel_id_bot) = { - match ctx.data.read().get::().cloned() { - Some(manager_lock) => { - let mut manager = manager_lock.lock(); - let guild_id = match guild_id(ctx, msg) { - Ok(id) => id, - Err(_) => return true, - }; +) -> VerboseResult<()> { + let guild = guild(ctx, msg)?; + let guild_id = guild.read().id; - let handler = match handler(guild_id, &mut manager) { - Some(handler) => handler, - None => { - println!("error getting handler"); - return true; + let author_channel_id = match guild + .read() + .voice_states + .get(&msg.author.id) + .and_then(|voice_state| voice_state.channel_id) + { + Some(channel) => channel, + None => create_error!("author is not in a voice channel!"), + }; + + if let Some(media) = ctx.data.read().get::() { + let mut manager = media.voice_manager.lock(); + + match manager.get(guild_id) { + Some(handler) => match handler.channel_id { + Some(bot_channel_id) => { + if bot_channel_id != author_channel_id { + create_error!("author is not in the same voice channel as the bot!"); } - }; - - ( - guild_id, - match handler.channel_id { - Some(id) => id, - None => { - println!("error getting channel_id for bot"); - return true; - } - }, - ) + } + None => { + manager.join(guild_id, author_channel_id); + } + }, + None => { + manager.join(guild_id, author_channel_id); } - None => return false, - } - }; - - let author = &msg.author; - - let guild = match guild_id.to_guild_cached(&ctx) { - Some(guild) => guild, - None => { - println!("error getting guild from cache"); - return true; - } - }; - - let guild_lock = guild.read(); - - let voice_state = match guild_lock.voice_states.get(&author.id) { - Some(state) => state, - None => { - println!("error getting voice state from user {}", author.name); - return false; - } - }; - - if let Some(voice_channel_id_user) = voice_state.channel_id { - if voice_channel_id_bot != voice_channel_id_user { - return false; } } - true + Ok(()) } diff --git a/src/player/prelude.rs b/src/player/prelude.rs index a963b14..053ac23 100644 --- a/src/player/prelude.rs +++ b/src/player/prelude.rs @@ -9,7 +9,6 @@ pub use super::commands::skip::*; pub use super::commands::stop::*; pub use super::eventhandler::Handler; -pub use super::voicemanager::VoiceManager; pub use super::youtube::youtube_dl; diff --git a/src/player/voicemanager.rs b/src/player/voicemanager.rs deleted file mode 100644 index efaf758..0000000 --- a/src/player/voicemanager.rs +++ /dev/null @@ -1,10 +0,0 @@ -use serenity::client::bridge::voice::ClientVoiceManager; -use serenity::prelude::Mutex; -use std::sync::Arc; -use typemap::Key; - -pub struct VoiceManager; - -impl Key for VoiceManager { - type Value = Arc>; -} diff --git a/src/player/youtube.rs b/src/player/youtube.rs index e06b20c..ec773c8 100644 --- a/src/player/youtube.rs +++ b/src/player/youtube.rs @@ -72,7 +72,7 @@ pub fn youtube_dl(uri: &str) -> Result, String> { )); } - let files = check_result!(convert_output(&out)); + let files = convert_output(&out)?; for file in &files { println!("file: {}", file);