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::logging::{self, Logger};
pub struct MpvListener;
pub struct MpvListener {
logger: Rc<Logger>
}
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;
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),

0
src/discord_client.rs Normal file
View file

View file

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

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 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<dyn Listener>
listener: Box<dyn Listener>,
logger: Rc<Logger>
}
impl MpvEventHandler {
pub fn new<'a>(mpv: Handle, listener: Box<dyn Listener>) -> Self {
Self {
pub fn new(mpv: Handle, listener: Box<dyn Listener>, logger: Rc<Logger>) -> Result<Self, String> {
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<dyn Listener>) -> Self {
MpvEventHandler::new(Handle::from_ptr(handle), listener)
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, 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
}

View file

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