From 6fd1dd7255b5172ad7ebf99b5f41d630e727ae97 Mon Sep 17 00:00:00 2001 From: Ryze Date: Sat, 4 Feb 2023 22:34:19 +0300 Subject: [PATCH] Implemented logging and error_handling --- src/basic_listener.rs | 43 +++++++++----- src/discord_client.rs | 0 src/lib.rs | 22 ++++--- src/logging.rs | 69 ++++++++++++++++++++++ src/logging/macros.rs | 26 ++++++++ src/mpv_event_handler.rs | 101 ++++++++++++++++++++------------ src/mpv_event_handler/events.rs | 2 +- 7 files changed, 203 insertions(+), 60 deletions(-) create mode 100644 src/discord_client.rs create mode 100644 src/logging.rs create mode 100644 src/logging/macros.rs diff --git a/src/basic_listener.rs b/src/basic_listener.rs index da8517f..34404a1 100644 --- a/src/basic_listener.rs +++ b/src/basic_listener.rs @@ -1,46 +1,61 @@ +use std::rc::Rc; use crate::mpv_event_handler::events::{MpvEvent, Listener, FileInfo}; +use crate::logging::{self, Logger}; -pub struct MpvListener; +pub struct MpvListener { + logger: Rc +} impl MpvListener { - fn print_file_info(&self, file_info: FileInfo) { + pub fn new(logger: Rc) -> Self { + Self { + logger + } + } + + + fn print_file_info(&self, file_info: FileInfo) -> Result<(), &'static str> { let FileInfo {filename, metadata} = file_info; - println!("[RPC] FILENAME: {filename}"); + logging::info!(self.logger, "FILENAME {}", filename); if let Some(artist) = metadata.artist { - println!("[RPC] ARTIST: {artist}"); + logging::info!(self.logger, "ARTIST: {artist}"); } if let Some(album) = metadata.album { - println!("[RPC] ALBUM: {album}"); + logging::info!(self.logger, "ALBUM: {album}"); } if let Some(title) = metadata.title { - println!("[RPC] TITLE: {title}"); + logging::info!(self.logger, "TITLE: {title}"); } if let Some(track) = metadata.track { - println!("[RPC] TRACK: {track}"); + logging::info!(self.logger, "TRACK: {track}"); } + Ok(()) } - fn print_seek_time(&self, time: i64) { - println!("[RPC] SEEKING: {time}"); + fn print_seek_time(&self, time: i64) -> Result<(), &'static str>{ + logging::info!(self.logger, "SEEKING: {time}"); + Ok(()) } - fn print_play(&self) { - println!("[RPC] PLAY"); + fn print_play(&self) -> Result<(), &'static str> { + logging::info!(self.logger, "PLAY"); + Ok(()) } - fn print_pause(&self) { - println!("[RPC] PAUSE"); + fn print_pause(&self) -> Result<(), &'static str> { + logging::info!(self.logger, "PAUSE"); + Ok(()) } } impl Listener for MpvListener { - fn handle_event(&self, event: MpvEvent) { + fn handle_event(&self, event: MpvEvent) -> Result<(), &'static str>{ match event { MpvEvent::FileLoaded(file_info) => self.print_file_info(file_info), MpvEvent::Seek(time) => self.print_seek_time(time), diff --git a/src/discord_client.rs b/src/discord_client.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/lib.rs b/src/lib.rs index 74b7d59..7e0f2f3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,25 @@ +use std::rc::Rc; + use mpv_client::mpv_handle; mod mpv_event_handler; +mod logging; mod basic_listener; // For testing purposes #[no_mangle] fn mpv_open_cplugin(handle: *mut mpv_handle) -> std::os::raw::c_int { - let listener = Box::new(basic_listener::MpvListener); - let client = mpv_event_handler::MpvEventHandler::from_ptr(handle, listener); + let logger = Rc::new(logging::Logger::from_env()); - if let Err(e) = client.initialize() { - println!("[RPC] Error initializing mpv client: {e}") - } + let listener = Box::new(basic_listener::MpvListener::new(Rc::clone(&logger))); + let result = mpv_event_handler::MpvEventHandler::from_ptr(handle, listener, Rc::clone(&logger)); + let client = match result { + Ok(v) => v, + Err(e) => { + logging::error!(logger, "Error initializing event_handling: {e}"); + return -1; + } + }; - while client.poll_events() { - - } + client.run(); return 0; } \ No newline at end of file diff --git a/src/logging.rs b/src/logging.rs new file mode 100644 index 0000000..d99f8b6 --- /dev/null +++ b/src/logging.rs @@ -0,0 +1,69 @@ +use std::env; + +pub mod macros; +pub use macros::{error, warning, info}; + +#[allow(dead_code)] +#[derive(PartialEq, PartialOrd)] +pub enum LogLevel { + None = 0, + Error = 1, + Warn = 2, + Info = 3 +} + +impl From for LogLevel { + fn from(num: u32) -> Self { + match num { + 0 => LogLevel::None, + 1 => LogLevel::Error, + 2 => LogLevel::Warn, + 3 => LogLevel::Info, + _ => LogLevel::None + } + } +} + + +#[allow(dead_code)] +pub struct Logger { + log_level: LogLevel +} + +#[allow(dead_code)] +impl Logger { + pub fn new(log_level: LogLevel) -> Self { + Self { + log_level + } + } + + pub fn from_env() -> Self { + let level = env::var("MPV_RPC_LOG").unwrap_or_default(); + let level: u32 = level.parse().unwrap_or_default(); + + let log_level = LogLevel::from(level); + Self { + log_level + } + } + + pub fn info(&self, message: &str) { + if self.log_level >= LogLevel::Info { + println!("[mpv-rpc (INFO)] {}", message); + } + } + + pub fn warning(&self, message: &str) { + if self.log_level >= LogLevel::Warn { + println!("[mpv-rpc (WARN)] {}", message); + } + } + + pub fn error(&self, message: &str) { + if self.log_level >= LogLevel::Error { + println!("[mpv-rpc (ERROR)] {}", message); + } + } + +} \ No newline at end of file diff --git a/src/logging/macros.rs b/src/logging/macros.rs new file mode 100644 index 0000000..064a065 --- /dev/null +++ b/src/logging/macros.rs @@ -0,0 +1,26 @@ +#[allow(unused_macros)] +#[macro_export] +macro_rules! error { + ($logger:expr, $($arg:tt)*) => { + $logger.error(&format!($($arg)*)) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! warning { + ($logger:expr, $($arg:tt)*) => { + $logger.warning(&format!($($arg)*)) + }; +} + +#[allow(unused_macros)] +#[macro_export] +macro_rules! info { + ($logger:expr, $($arg:tt)*) => { + $logger.info(&format!($($arg)*)) + }; +} + +#[allow(unused_imports)] +pub use {error, warning, info}; \ No newline at end of file diff --git a/src/mpv_event_handler.rs b/src/mpv_event_handler.rs index fe09b0d..97eb132 100644 --- a/src/mpv_event_handler.rs +++ b/src/mpv_event_handler.rs @@ -1,30 +1,37 @@ +use std::rc::Rc; + use mpv_client::{Handle, Event, Property, Format, mpv_handle}; +use crate::logging::{self, Logger}; pub mod events; use events::{MpvEvent, Listener, FileInfo, FileMetadata}; - const NAME_PAUSE_PROP: &str = "pause"; const REPL_PAUSE_PROP: u64 = 1; pub struct MpvEventHandler { mpv: Handle, - listener: Box + listener: Box, + logger: Rc } impl MpvEventHandler { - pub fn new<'a>(mpv: Handle, listener: Box) -> Self { - Self { + pub fn new(mpv: Handle, listener: Box, logger: Rc) -> Result { + let new_self = Self { mpv, - listener - } + listener, + logger + }; + + new_self.initialize()?; + Ok(new_self) } - pub fn from_ptr<'a>(handle: *mut mpv_handle, listener: Box) -> Self { - MpvEventHandler::new(Handle::from_ptr(handle), listener) + pub fn from_ptr<'a>(handle: *mut mpv_handle, listener: Box, logger: Rc) -> Result { + MpvEventHandler::new(Handle::from_ptr(handle), listener, logger) } - pub fn initialize(&self) -> Result<(), String> { + fn initialize(&self) -> Result<(), String> { self.observe_property(REPL_PAUSE_PROP, NAME_PAUSE_PROP, bool::MPV_FORMAT) } @@ -35,32 +42,40 @@ impl MpvEventHandler { } } - fn on_property_change(&self, prop_id: u64, prop: Property) { - println!("[RPC] Property changed: {prop_id}"); - match prop_id { - REPL_PAUSE_PROP => self.handle_pause_change(prop.data().unwrap()), - _ => () - } - } - - fn handle_event(&self, event: Event) { - println!("[RPC] Event: {event}"); + fn handle_event(&self, event: Event) -> Result<(), &'static str>{ + logging::info!(self.logger, "Event: {event}"); match event { Event::FileLoaded => self.handle_file_loaded(), Event::PlaybackRestart => self.handle_playback_restart(), - _ => () + _ => Ok(()) } } - // TODO - // Replace unwrap with error handling - fn handle_file_loaded(&self) { - let filename = self.mpv.get_property("filename").unwrap(); + fn on_property_change(&self, prop_id: u64, prop: Property) -> Result<(), &'static str> { + logging::info!(self.logger, "Property changed: {prop_id}"); + match prop_id { + REPL_PAUSE_PROP => { + match prop.data() { + Some(pause) => self.handle_pause_change(pause), + None => Err("property pause doesn't exist") + } + } + _ => Ok(()) + } + } + + fn handle_file_loaded(&self) -> Result<(), &'static str> { + let filename_res = self.mpv.get_property("filename"); let artist = self.mpv.get_property("metadata/by-key/artist").ok(); let album = self.mpv.get_property("metadata/by-key/album").ok(); let title = self.mpv.get_property("metadata/by-key/title").ok(); let track = self.mpv.get_property("metadata/by-key/Artist").ok(); + let filename = match filename_res { + Ok(name) => name, + Err(_) => return Err("filename property doesn't exist") + }; + let metadata = FileMetadata { artist, album, @@ -74,40 +89,52 @@ impl MpvEventHandler { }; let event = MpvEvent::FileLoaded(file_info); - self.listener.handle_event(event); + self.listener.handle_event(event) } - fn handle_playback_restart(&self) { + fn handle_playback_restart(&self) -> Result<(), &'static str>{ let res = self.mpv.get_property("playback-time").ok(); match res { Some(time) => { let event = MpvEvent::Seek(time); - self.listener.handle_event(event); + self.listener.handle_event(event) } None => { - println!("[RPC] Failed retrieving playback-time."); - println!("[RPC] This usually happens seeking into file end. Possibly mpv bug?"); + logging::warning!(self.logger, "Failed retrieving playback-time."); + logging::warning!(self.logger, "This usually happens seeking into file end. Possibly mpv bug?"); + Ok(()) }, } } - fn handle_pause_change(&self, pause: bool) { + fn handle_pause_change(&self, pause: bool) -> Result<(), &'static str> { let event = match pause { false => MpvEvent::Play, true => MpvEvent::Pause }; - self.listener.handle_event(event); + self.listener.handle_event(event) } - // TODO! - // Add logging and error handling, - // yes unwrap on property changes and events + + pub fn run(&self) { + while self.poll_events() { + // Wait for shutdown + } + } + + // Refactor to accept warnings as well pub fn poll_events(&self) -> bool { - match self.mpv.wait_event(0.0) { - Event::None => (), + let event = self.mpv.wait_event(0.0); + let event_name = event.to_string(); + let result = match event { + Event::None => Ok(()), Event::Shutdown => return false, Event::PropertyChange(prop_id, prop) => self.on_property_change(prop_id, prop), - event => self.handle_event(event) + e => self.handle_event(e) + }; + + if let Err(e) = result { + logging::error!(self.logger, "Error handling event {event_name}: {e}"); } true } diff --git a/src/mpv_event_handler/events.rs b/src/mpv_event_handler/events.rs index 684ba5d..c09e175 100644 --- a/src/mpv_event_handler/events.rs +++ b/src/mpv_event_handler/events.rs @@ -18,5 +18,5 @@ pub enum MpvEvent { } pub trait Listener { - fn handle_event(&self, event: MpvEvent); + fn handle_event(&self, event: MpvEvent) -> Result<(), &'static str>; } \ No newline at end of file