diff --git a/src/rust/amadeus-next/Cargo.toml b/src/rust/amadeus-next/Cargo.toml index d7be59e79b50a4e63369fd2623137536b44926b1..2ed2f9d8f687633cbb3ef11ab11be1d1beeec568 100644 --- a/src/rust/amadeus-next/Cargo.toml +++ b/src/rust/amadeus-next/Cargo.toml @@ -15,7 +15,6 @@ version = "0.1.0" license = "MIT" [workspace.dependencies] -log = "0.4" lazy_static = "1" toml = { version = "^0.5", features = ["preserve_order"] } serde = { version = "^1", default-features = false, features = [ diff --git a/src/rust/amadeus-next/amalib/src/query.rs b/src/rust/amadeus-next/amalib/src/query.rs index 4aeab97c3bbcd5b4ba0956b831f5adb1964cbc17..37029d1bdbe7009571bce0847e90d077c0a30f69 100644 --- a/src/rust/amadeus-next/amalib/src/query.rs +++ b/src/rust/amadeus-next/amalib/src/query.rs @@ -27,17 +27,23 @@ pub enum LektorQuery { CurrentKara, PlaybackStatus, + Play(usize), + Pause, + UnPause, + Stop, PlayNext, PlayPrevious, - ShuffleQueue, + CropQueue, + ShuffleQueue(LektorPriorityLevel), + ClearQueue(LektorPriorityLevel), + SwapInQueue(usize, usize), + SeekIdInQueue(usize), ListAllPlaylists, ListPlaylist(String), - SearchKara(LektorUri), - FindAddKara(LektorUri), - InsertKara(LektorUri), - AddKara(LektorUri), + SearchKara(LektorUri), + AddKara(LektorPriorityLevel, LektorUri), CreatePlaylist(String), DestroyPlaylist(String), @@ -99,9 +105,26 @@ impl LektorQuery { pub(crate) fn get_response_type(&self) -> QueryToTypeResponseBuilder { use LektorQuery::*; match self { - Populate | DryPopulate | Update | DryUpdate | Ping | Close | KillServer - | RestartServer | PlayNext | PlayPrevious | ShuffleQueue | InsertKara(_) - | AddKara(_) => LektorEmptyResponse::from_formated, + Populate + | DryPopulate + | Update + | DryUpdate + | Ping + | Close + | KillServer + | Play(_) + | Pause + | Stop + | UnPause + | RestartServer + | PlayNext + | PlayPrevious + | ShuffleQueue(_) + | SwapInQueue(_, _) + | SeekIdInQueue(_) + | ClearQueue(_) + | CropQueue + | AddKara(_, _) => LektorEmptyResponse::from_formated, CreatePlaylist(_) | DestroyPlaylist(_) @@ -114,9 +137,7 @@ impl LektorQuery { ConnectAsUser(_, cmd) | Continuation(_, cmd) => cmd.get_response_type(), - ListPlaylist(_) | SearchKara(_) | FindAddKara(_) => { - LektorKaraSetResponse::from_formated - } + ListPlaylist(_) | SearchKara(_) => LektorKaraSetResponse::from_formated, } } @@ -139,9 +160,24 @@ impl LektorQuery { } match self { // User commands - SearchKara(_) | FindAddKara(_) | InsertKara(_) | AddKara(_) | PlaybackStatus - | PlayNext | PlayPrevious | ShuffleQueue | ListAllPlaylists | ListPlaylist(_) - | CurrentKara | Ping => Ok(()), + SearchKara(_) + | AddKara(_, _) + | PlaybackStatus + | PlayNext + | PlayPrevious + | ShuffleQueue(_) + | ListAllPlaylists + | ListPlaylist(_) + | SwapInQueue(_, _) + | SeekIdInQueue(_) + | ClearQueue(_) + | CropQueue + | Play(_) + | Stop + | Pause + | UnPause + | CurrentKara + | Ping => Ok(()), CreatePlaylist(str) | DestroyPlaylist(str) @@ -161,7 +197,7 @@ impl LektorQuery { // Continuation commands Continuation(_, cmd) => match cmd.as_ref() { - ListAllPlaylists | FindAddKara(_) | SearchKara(_) | ListPlaylist(_) => Ok(()), + ListAllPlaylists | SearchKara(_) | ListPlaylist(_) => Ok(()), _ => Err(format!("not a continuable command: {cmd:?}")), }, } @@ -169,8 +205,13 @@ impl LektorQuery { /// Format the query to send it to the lektor server. pub(crate) fn format_query(&self) -> String { - #[rustfmt::skip] - macro_rules! lkt_str { ($lit:literal) => { (concat!($lit, '\n')).to_string() }; } + macro_rules! lkt_str { + ($($arg:tt)*) => {{ + let mut str = std::fmt::format(format_args!($($arg)*)); + str.push('\n'); + str + }}; + } use LektorQuery::*; match self { Populate => lkt_str!("rescan"), @@ -195,24 +236,35 @@ impl LektorQuery { CurrentKara => lkt_str!("currentsong"), PlaybackStatus => lkt_str!("status"), + ClearQueue(lvl) => lkt_str!("clear {lvl}"), + CropQueue => lkt_str!("crop"), + Play(pos) => lkt_str!("play {pos}"), + Stop => lkt_str!("stop"), + Pause => lkt_str!("pause 1"), + UnPause => lkt_str!("pause 0"), PlayNext => lkt_str!("next"), PlayPrevious => lkt_str!("previous"), - ShuffleQueue => lkt_str!("shuffle"), + ShuffleQueue(lvl) => lkt_str!("shuffle {lvl}"), + SwapInQueue(p1, p2) => lkt_str!("swap {p1} {p2}"), + SeekIdInQueue(id) => lkt_str!("seek {id}"), ListAllPlaylists => lkt_str!("listplaylists"), - ListPlaylist(plt_name) => format!("listplaylist {plt_name}\n"), - SearchKara(uri) => format!("find {uri}\n"), + ListPlaylist(plt_name) => lkt_str!("listplaylist {plt_name}"), + SearchKara(uri) => lkt_str!("find {uri}"), - FindAddKara(uri) => format!("findadd {uri}\n"), - InsertKara(uri) => format!("__insert {uri}\n"), - AddKara(uri) => format!("add {uri}\n"), + AddKara(LektorPriorityLevel::Add, uri) => lkt_str!("add {uri}"), + AddKara(LektorPriorityLevel::Insert, uri) => lkt_str!("__insert {uri}"), + AddKara(lvl, uri) => unimplemented!("add {lvl} {uri}"), - CreatePlaylist(name) => format!("playlistadd {name}\n"), - DestroyPlaylist(name) => format!("playlistdelete {name}\n"), - AddToPlaylist(name, uri) => format!("playlistadd {name} {uri}\n"), - RemoveFromPlaylist(name, uri) => format!("playlistdelete {name} {uri}\n"), + CreatePlaylist(name) => lkt_str!("playlistadd {name}"), + DestroyPlaylist(name) => lkt_str!("playlistdelete {name}"), + AddToPlaylist(name, uri) => lkt_str!("playlistadd {name} {uri}"), + RemoveFromPlaylist(name, uri) => lkt_str!("playlistdelete {name} {uri}"), - Continuation(cont, query) => format!("{cont} {}\n", query.format_query()), + Continuation(cont, query) => { + let query = query.format_query(); + lkt_str!("{cont} {query}") + } } } } diff --git a/src/rust/amadeus-next/commons/Cargo.toml b/src/rust/amadeus-next/commons/Cargo.toml index 1e71a6fe965f8ee9dc614bb9c1acaf1ec3c335d8..f66252d165c27b06a867c1ffcc5329086f45ad26 100644 --- a/src/rust/amadeus-next/commons/Cargo.toml +++ b/src/rust/amadeus-next/commons/Cargo.toml @@ -6,8 +6,8 @@ authors.workspace = true license.workspace = true [dependencies] -log.workspace = true lazy_static.workspace = true +log = "0.4" thiserror = { version = "^1", default-features = false } error-stack = { version = "^0.2", default-features = false, features = ["std"] } diff --git a/src/rust/amadeus-next/lkt-rs/src/args.rs b/src/rust/amadeus-next/lkt-rs/src/args.rs index e4fbe10d6d630ba465cfb6db1920c0be9deb2a77..079c3403db6dc9ddd2499c19dda12a02ae61f858 100644 --- a/src/rust/amadeus-next/lkt-rs/src/args.rs +++ b/src/rust/amadeus-next/lkt-rs/src/args.rs @@ -1,5 +1,5 @@ use crate::config::LktConfig; -use amalib::LektorPriorityLevel; +use amalib::{LektorPriorityLevel, LektorUri, LektorUriBuilder}; use clap::{Parser, Subcommand}; use std::ops::Range; @@ -69,7 +69,7 @@ enum SubCommand { , exclusive = true , short = 'r' , long = "play" - , help = "Toggle play/pause state. If the playback is stopped, start at a possibly specified index." + , help = "If the playback is stopped, start at a possibly specified index. If the lektor is playing do nothing." , id = "QUEUE_INDEX" )] play: Option<Option<usize>>, @@ -316,7 +316,7 @@ enum SubCommand { /// The lkt command enum. The main should only handle that enum to decide what /// to do based on user input. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum LktCommand { +pub(crate) enum LktCommand { Queue(LktQueueCommand), Search(LktSearchCommand), Playlist(LktPlaylistCommand), @@ -324,7 +324,7 @@ pub enum LktCommand { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum LktQueueCommand { +pub(crate) enum LktQueueCommand { ShowCurrent, ShowStatus, @@ -340,12 +340,12 @@ pub enum LktQueueCommand { TogglePause, Stop, Play { - index: usize, + index: Option<usize>, }, Add { priority: LektorPriorityLevel, - query: amalib::LektorUri, + query: LektorUri, }, Crop, @@ -368,58 +368,35 @@ pub enum LktQueueCommand { } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum LktSearchCommand { - Database { - query: amalib::LektorUri, - }, +pub(crate) enum LktSearchCommand { + Database { query: LektorUri }, - DatabaseCount { - query: amalib::LektorUri, - }, + DatabaseCount { query: LektorUri }, - Get { - id: usize, - }, + Get { id: usize }, - Playlist { - name: String, - query: amalib::LektorUri, - }, + Playlist { name: String, query: LektorUri }, - Queue { - query: amalib::LektorUri, - }, + Queue { query: LektorUri }, } #[derive(Debug, Clone, PartialEq, Eq)] -pub enum LktPlaylistCommand { - Create { - name: String, - }, +pub(crate) enum LktPlaylistCommand { + Create { name: String }, - Destroy { - name: String, - }, + Destroy { name: String }, - Add { - name: String, - query: amalib::LektorUri, - }, + Add { name: String, query: LektorUri }, - Remove { - name: String, - query: amalib::LektorUri, - }, + Remove { name: String, query: LektorUri }, List, - ListContent { - name: String, - }, + ListContent { name: String }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum LktAdminCommand { +pub(crate) enum LktAdminCommand { Ping, Kill, Restart, @@ -428,7 +405,7 @@ pub enum LktAdminCommand { } impl LktCommand { - pub fn parse(config: &LktConfig) -> Result<Self, String> { + pub(crate) fn parse(config: &LktConfig) -> Result<Self, String> { let Args { action, verbose } = <Args as Parser>::parse(); commons::logger::level(verbose); @@ -458,7 +435,7 @@ impl LktCommand { SubCommand::Queue { seek: Some(id), .. } => { Queue(LktQueueCommand::SeekIdInQueue { id }) } SubCommand::Queue { pos: Some(None), .. } => Queue(LktQueueCommand::List { range: 0..config.search.default_queue_count }), SubCommand::Queue { pos: Some(Some(range)), .. } => Queue(LktQueueCommand::List { range }), - SubCommand::Queue { play: Some(index), .. } => Queue(LktQueueCommand::Play { index: index.unwrap_or_default() }), + SubCommand::Queue { play: Some(index), .. } => Queue(LktQueueCommand::Play { index }), SubCommand::Queue { swap: Some(args), .. } => match &args[..] { [p1, p2] => Queue(LktQueueCommand::SwapPositions { p1: p1.parse::<usize>().map_err(|e| format!("invalid swap command, {p1} is not an integer: {e}"))?, @@ -470,12 +447,12 @@ impl LktCommand { [] => sterr!("invalid queue add command, expected `priority query...` or `query...`, got nothing"), [priority, query @ .. ] if !query.is_empty() && priority.parse::<LektorPriorityLevel>().is_ok() => Queue(LktQueueCommand::Add { priority: priority.parse().expect("something went wrong"), - query: amalib::LektorUriBuilder::default() + query: LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.iter().cloned()).try_build() .map_err(|e| format!("invalid query in queue add command: {e}"))? }), query => Queue(LktQueueCommand::Add { priority: LektorPriorityLevel::Add, - query: amalib::LektorUriBuilder::default() + query: LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.iter().cloned()).try_build() .map_err(|e| format!("invalid query in queue add command: {e}"))? }), @@ -484,24 +461,24 @@ impl LktCommand { // SEARCH COMMANDS // SubCommand::Search { database: Some(query), .. } => Search(LktSearchCommand::Database { - query: amalib::LektorUriBuilder::default() + query: LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.into_iter()).try_build() .map_err(|e| format!("invalid query in search database command: {e}"))? }), SubCommand::Search { count: Some(query), .. } => Search(LktSearchCommand::DatabaseCount { query: - amalib::LektorUriBuilder::default() + LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.into_iter()).try_build() .map_err(|e| format!("invalid query in search count command: {e}"))? }), SubCommand::Search { queue: Some(query), .. } => Search(LktSearchCommand::Queue { query: - amalib::LektorUriBuilder::default() + LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.into_iter()).try_build() .map_err(|e| format!("invalid query in search queue command: {e}"))? }), SubCommand::Search { get: Some(id), .. } => Search(LktSearchCommand::Get { id }), SubCommand::Search { plt: Some(args), .. } => match &args[..] { [name, query @ ..] if !query.is_empty() => Search(LktSearchCommand::Playlist { name: name.clone(), query: - amalib::LektorUriBuilder::default() + LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.iter().cloned()).try_build() .map_err(|e| format!("invalid query in search playlist command: {e}"))? }), @@ -517,7 +494,7 @@ impl LktCommand { SubCommand::Playlist { destroy: Some(name), .. } => Playlist(LktPlaylistCommand::Destroy { name }), SubCommand::Playlist { add: Some(args), .. } => match &args[..] { [name, query @ ..] if !query.is_empty() => Playlist(LktPlaylistCommand::Add { name: name.clone(), query: - amalib::LektorUriBuilder::default() + LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.iter().cloned()).try_build() .map_err(|e| format!("invalid query in playlist add command: {e}"))? }), @@ -526,7 +503,7 @@ impl LktCommand { } SubCommand::Playlist { remove: Some(args), .. } => match &args[..] { [name, query @ ..] if !query.is_empty() => Playlist(LktPlaylistCommand::Remove { name: name.clone(), query: - amalib::LektorUriBuilder::default() + LektorUriBuilder::default() .query_type(config.search.query_type).strings(query.iter().cloned()).try_build() .map_err(|e| format!("invalid query in playlist add command: {e}"))? }), diff --git a/src/rust/amadeus-next/lkt-rs/src/main.rs b/src/rust/amadeus-next/lkt-rs/src/main.rs index 5ec2a228455e21780e9793f933433d580cce58d6..bc2ad06bc48fa34b8cc9b70bb7d0d765f5c561da 100644 --- a/src/rust/amadeus-next/lkt-rs/src/main.rs +++ b/src/rust/amadeus-next/lkt-rs/src/main.rs @@ -4,13 +4,17 @@ mod args; mod config; mod parsers; -use crate::{args::*, config::LktConfig}; -use amalib::{LektorQuery, LektorResponse}; +use crate::{ + args::*, + config::{LktConfig, LktHostPort}, +}; +use amalib::{LektorConnexion, LektorQuery, LektorResponse, LektorState}; +use commons::log; #[tokio::main(worker_threads = 2)] async fn main() { commons::Report::install_debug_hook::<std::backtrace::Backtrace>(|_, _| {}); - commons::logger::init(Some(commons::log::Level::Trace)) + commons::logger::init(Some(log::Level::Trace)) .unwrap_or_else(|e| panic!("failed to install logger: {e}")); let config = LktConfig::get_or_write_default().expect("failed to get or write default config"); let cmd = LktCommand::parse(&config).expect("oupsy"); @@ -18,10 +22,10 @@ async fn main() { } async fn handle_cmd(config: LktConfig, cmd: LktCommand) { - commons::log::debug!("{config:#?}\ncmd = {cmd:#?}"); + log::debug!("{config:#?}\ncmd = {cmd:#?}"); let conn = match config.host.socket { - config::LktHostPort::UNIX => unimplemented!("connexion to unix socket is not implemented"), - config::LktHostPort::TCP(port) => amalib::LektorConnexion::new(&config.host.address, port) + LktHostPort::UNIX => unimplemented!("connexion to unix socket is not implemented"), + LktHostPort::TCP(port) => LektorConnexion::new(&config.host.address, port) .await .expect("failed to connect to the lektord server"), }; @@ -46,11 +50,11 @@ macro_rules! send { }}; } -async fn handle_cmd_queue(_: LktConfig, mut conn: amalib::LektorConnexion, cmd: LktQueueCommand) { +async fn handle_cmd_queue(_: LktConfig, mut conn: LektorConnexion, cmd: LktQueueCommand) { match cmd { LktQueueCommand::ShowCurrent => { send!(conn => LektorQuery::CurrentKara; LektorResponse::CurrentKara(kara) => { - kara.maybe_into_inner().map(|kara| println!("{kara:#?}")); + if let Some(kara) = kara.maybe_into_inner() { println!("{kara:#?}") } }) } LktQueueCommand::ShowStatus => { @@ -59,31 +63,86 @@ async fn handle_cmd_queue(_: LktConfig, mut conn: amalib::LektorConnexion, cmd: }) } LktQueueCommand::List { range } => todo!(), - LktQueueCommand::Next => todo!(), - LktQueueCommand::Previous => todo!(), - LktQueueCommand::Pause => todo!(), - LktQueueCommand::UnPause => todo!(), - LktQueueCommand::TogglePause => todo!(), - LktQueueCommand::Stop => todo!(), - LktQueueCommand::Play { index } => todo!(), - LktQueueCommand::Add { priority, query } => todo!(), - LktQueueCommand::Crop => todo!(), - LktQueueCommand::Clear { up_to_lvl } => todo!(), - LktQueueCommand::SwapPositions { p1, p2 } => todo!(), - LktQueueCommand::SeekIdInQueue { id } => todo!(), - LktQueueCommand::Shuffle { up_to_lvl } => todo!(), + LktQueueCommand::Next => send!(conn => LektorQuery::PlayNext; ok), + LktQueueCommand::Previous => send!(conn => LektorQuery::PlayPrevious; ok), + LktQueueCommand::Pause => { + if let LektorState::Play(_) = send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + send!(conn => LektorQuery::Pause; ok) + } + } + LktQueueCommand::UnPause => { + if let LektorState::Pause(_) = send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + send!(conn => LektorQuery::UnPause; ok) + } + } + LktQueueCommand::TogglePause => { + match send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + LektorState::Play(_) => send!(conn => LektorQuery::Pause; ok), + LektorState::Pause(_) => send!(conn => LektorQuery::UnPause; ok), + _ => {} + } + } + LktQueueCommand::Stop => { + match send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + LektorState::Play(_) | LektorState::Pause(_) => { + send!(conn => LektorQuery::Stop; ok) + } + _ => {} + } + } + LktQueueCommand::Play { index: None } => { + match send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + LektorState::Stopped => send!(conn => LektorQuery::Play(0); ok), + LektorState::Pause(_) => send!(conn => LektorQuery::UnPause; ok), + _ => {} + } + } + LktQueueCommand::Play { index: Some(index) } => { + match send!(conn => LektorQuery::PlaybackStatus; + LektorResponse::PlaybackStatus(status) => { status.state() } + ) { + LektorState::Stopped => send!(conn => LektorQuery::Play(index); ok), + LektorState::Play(pos) if pos == index => {} + LektorState::Pause(pos) if pos == index => { + send!(conn => LektorQuery::UnPause; ok) + } + LektorState::Play(_) | LektorState::Pause(_) => { + send!(conn => LektorQuery::Play(index); ok) + } + } + } + LktQueueCommand::Add { priority, query } => { + send!(conn => LektorQuery::AddKara(priority, query); ok) + } + LktQueueCommand::Crop => send!(conn => LektorQuery::CropQueue; ok), + LktQueueCommand::Clear { up_to_lvl } => { + send!(conn => LektorQuery::ClearQueue(up_to_lvl); ok) + } + LktQueueCommand::Shuffle { up_to_lvl } => { + send!(conn => LektorQuery::ShuffleQueue(up_to_lvl); ok) + } + LktQueueCommand::SwapPositions { p1, p2 } => { + send!(conn => LektorQuery::SwapInQueue(p1, p2); ok) + } + LktQueueCommand::SeekIdInQueue { id } => send!(conn => LektorQuery::SeekIdInQueue(id); ok), } } -async fn handle_cmd_search(_: LktConfig, _: amalib::LektorConnexion, _: LktSearchCommand) { +async fn handle_cmd_search(_: LktConfig, _: LektorConnexion, _: LktSearchCommand) { unimplemented!() } -async fn handle_cmd_playlist( - _: LktConfig, - mut conn: amalib::LektorConnexion, - cmd: LktPlaylistCommand, -) { +async fn handle_cmd_playlist(_: LktConfig, mut conn: LektorConnexion, cmd: LktPlaylistCommand) { match cmd { LktPlaylistCommand::Create { name } => { send!(conn => LektorQuery::CreatePlaylist(name); ok) @@ -110,11 +169,7 @@ async fn handle_cmd_playlist( } } -async fn handle_cmd_admin( - config: LktConfig, - mut conn: amalib::LektorConnexion, - cmd: LktAdminCommand, -) { +async fn handle_cmd_admin(config: LktConfig, mut conn: LektorConnexion, cmd: LktAdminCommand) { match config.password { Some(password) => { let cmd = Box::new(match cmd {