Implemented logging and error_handling

This commit is contained in:
Ryze 2023-02-04 22:34:19 +03:00
parent b239baa7ff
commit 6fd1dd7255
7 changed files with 203 additions and 60 deletions

View file

@ -1,46 +1,61 @@
use std::rc::Rc;
use crate::mpv_event_handler::events::{MpvEvent, Listener, FileInfo}; use crate::mpv_event_handler::events::{MpvEvent, Listener, FileInfo};
use crate::logging::{self, Logger};
pub struct MpvListener; pub struct MpvListener {
logger: Rc<Logger>
}
impl MpvListener { impl MpvListener {
fn print_file_info(&self, file_info: FileInfo) { pub fn new(logger: Rc<Logger>) -> Self {
Self {
logger
}
}
fn print_file_info(&self, file_info: FileInfo) -> Result<(), &'static str> {
let FileInfo {filename, metadata} = file_info; let FileInfo {filename, metadata} = file_info;
println!("[RPC] FILENAME: {filename}"); logging::info!(self.logger, "FILENAME {}", filename);
if let Some(artist) = metadata.artist { if let Some(artist) = metadata.artist {
println!("[RPC] ARTIST: {artist}"); logging::info!(self.logger, "ARTIST: {artist}");
} }
if let Some(album) = metadata.album { if let Some(album) = metadata.album {
println!("[RPC] ALBUM: {album}"); logging::info!(self.logger, "ALBUM: {album}");
} }
if let Some(title) = metadata.title { if let Some(title) = metadata.title {
println!("[RPC] TITLE: {title}"); logging::info!(self.logger, "TITLE: {title}");
} }
if let Some(track) = metadata.track { if let Some(track) = metadata.track {
println!("[RPC] TRACK: {track}"); logging::info!(self.logger, "TRACK: {track}");
} }
Ok(())
} }
fn print_seek_time(&self, time: i64) { fn print_seek_time(&self, time: i64) -> Result<(), &'static str>{
println!("[RPC] SEEKING: {time}"); logging::info!(self.logger, "SEEKING: {time}");
Ok(())
} }
fn print_play(&self) { fn print_play(&self) -> Result<(), &'static str> {
println!("[RPC] PLAY"); logging::info!(self.logger, "PLAY");
Ok(())
} }
fn print_pause(&self) { fn print_pause(&self) -> Result<(), &'static str> {
println!("[RPC] PAUSE"); logging::info!(self.logger, "PAUSE");
Ok(())
} }
} }
impl Listener for MpvListener { impl Listener for MpvListener {
fn handle_event(&self, event: MpvEvent) { fn handle_event(&self, event: MpvEvent) -> Result<(), &'static str>{
match event { match event {
MpvEvent::FileLoaded(file_info) => self.print_file_info(file_info), MpvEvent::FileLoaded(file_info) => self.print_file_info(file_info),
MpvEvent::Seek(time) => self.print_seek_time(time), MpvEvent::Seek(time) => self.print_seek_time(time),

0
src/discord_client.rs Normal file
View file

View file

@ -1,19 +1,25 @@
use std::rc::Rc;
use mpv_client::mpv_handle; use mpv_client::mpv_handle;
mod mpv_event_handler; mod mpv_event_handler;
mod logging;
mod basic_listener; // For testing purposes mod basic_listener; // For testing purposes
#[no_mangle] #[no_mangle]
fn mpv_open_cplugin(handle: *mut mpv_handle) -> std::os::raw::c_int { fn mpv_open_cplugin(handle: *mut mpv_handle) -> std::os::raw::c_int {
let listener = Box::new(basic_listener::MpvListener); let logger = Rc::new(logging::Logger::from_env());
let client = mpv_event_handler::MpvEventHandler::from_ptr(handle, listener);
if let Err(e) = client.initialize() { let listener = Box::new(basic_listener::MpvListener::new(Rc::clone(&logger)));
println!("[RPC] Error initializing mpv client: {e}") 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; return 0;
} }

69
src/logging.rs Normal file
View file

@ -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<u32> 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);
}
}
}

26
src/logging/macros.rs Normal file
View file

@ -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};

View file

@ -1,30 +1,37 @@
use std::rc::Rc;
use mpv_client::{Handle, Event, Property, Format, mpv_handle}; use mpv_client::{Handle, Event, Property, Format, mpv_handle};
use crate::logging::{self, Logger};
pub mod events; pub mod events;
use events::{MpvEvent, Listener, FileInfo, FileMetadata}; use events::{MpvEvent, Listener, FileInfo, FileMetadata};
const NAME_PAUSE_PROP: &str = "pause"; const NAME_PAUSE_PROP: &str = "pause";
const REPL_PAUSE_PROP: u64 = 1; const REPL_PAUSE_PROP: u64 = 1;
pub struct MpvEventHandler { pub struct MpvEventHandler {
mpv: Handle, mpv: Handle,
listener: Box<dyn Listener> listener: Box<dyn Listener>,
logger: Rc<Logger>
} }
impl MpvEventHandler { impl MpvEventHandler {
pub fn new<'a>(mpv: Handle, listener: Box<dyn Listener>) -> Self { pub fn new(mpv: Handle, listener: Box<dyn Listener>, logger: Rc<Logger>) -> Result<Self, String> {
Self { let new_self = Self {
mpv, mpv,
listener listener,
} logger
};
new_self.initialize()?;
Ok(new_self)
} }
pub fn from_ptr<'a>(handle: *mut mpv_handle, listener: Box<dyn Listener>) -> Self { pub fn from_ptr<'a>(handle: *mut mpv_handle, listener: Box<dyn Listener>, logger: Rc<Logger>) -> Result<Self, String> {
MpvEventHandler::new(Handle::from_ptr(handle), listener) 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) 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) { fn handle_event(&self, event: Event) -> Result<(), &'static str>{
println!("[RPC] Property changed: {prop_id}"); logging::info!(self.logger, "Event: {event}");
match prop_id {
REPL_PAUSE_PROP => self.handle_pause_change(prop.data().unwrap()),
_ => ()
}
}
fn handle_event(&self, event: Event) {
println!("[RPC] Event: {event}");
match event { match event {
Event::FileLoaded => self.handle_file_loaded(), Event::FileLoaded => self.handle_file_loaded(),
Event::PlaybackRestart => self.handle_playback_restart(), Event::PlaybackRestart => self.handle_playback_restart(),
_ => () _ => Ok(())
} }
} }
// TODO fn on_property_change(&self, prop_id: u64, prop: Property) -> Result<(), &'static str> {
// Replace unwrap with error handling logging::info!(self.logger, "Property changed: {prop_id}");
fn handle_file_loaded(&self) { match prop_id {
let filename = self.mpv.get_property("filename").unwrap(); 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 artist = self.mpv.get_property("metadata/by-key/artist").ok();
let album = self.mpv.get_property("metadata/by-key/album").ok(); let album = self.mpv.get_property("metadata/by-key/album").ok();
let title = self.mpv.get_property("metadata/by-key/title").ok(); let title = self.mpv.get_property("metadata/by-key/title").ok();
let track = self.mpv.get_property("metadata/by-key/Artist").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 { let metadata = FileMetadata {
artist, artist,
album, album,
@ -74,40 +89,52 @@ impl MpvEventHandler {
}; };
let event = MpvEvent::FileLoaded(file_info); 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(); let res = self.mpv.get_property("playback-time").ok();
match res { match res {
Some(time) => { Some(time) => {
let event = MpvEvent::Seek(time); let event = MpvEvent::Seek(time);
self.listener.handle_event(event); self.listener.handle_event(event)
} }
None => { None => {
println!("[RPC] Failed retrieving playback-time."); logging::warning!(self.logger, "Failed retrieving playback-time.");
println!("[RPC] This usually happens seeking into file end. Possibly mpv bug?"); 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 { let event = match pause {
false => MpvEvent::Play, false => MpvEvent::Play,
true => MpvEvent::Pause true => MpvEvent::Pause
}; };
self.listener.handle_event(event); self.listener.handle_event(event)
} }
// TODO!
// Add logging and error handling, pub fn run(&self) {
// yes unwrap on property changes and events while self.poll_events() {
// Wait for shutdown
}
}
// Refactor to accept warnings as well
pub fn poll_events(&self) -> bool { pub fn poll_events(&self) -> bool {
match self.mpv.wait_event(0.0) { let event = self.mpv.wait_event(0.0);
Event::None => (), let event_name = event.to_string();
let result = match event {
Event::None => Ok(()),
Event::Shutdown => return false, Event::Shutdown => return false,
Event::PropertyChange(prop_id, prop) => self.on_property_change(prop_id, prop), 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 true
} }

View file

@ -18,5 +18,5 @@ pub enum MpvEvent {
} }
pub trait Listener { pub trait Listener {
fn handle_event(&self, event: MpvEvent); fn handle_event(&self, event: MpvEvent) -> Result<(), &'static str>;
} }