Implemented logging and error_handling
This commit is contained in:
parent
b239baa7ff
commit
6fd1dd7255
7 changed files with 203 additions and 60 deletions
|
@ -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
0
src/discord_client.rs
Normal file
22
src/lib.rs
22
src/lib.rs
|
@ -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
69
src/logging.rs
Normal 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
26
src/logging/macros.rs
Normal 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};
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>;
|
||||||
}
|
}
|
Loading…
Reference in a new issue