From e12f15dc0d10a71f54a4c758d13549183dec8963 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Tue, 10 Jan 2023 17:11:22 +0100 Subject: [PATCH] RUST: Continue development of amalib and lkt-rs Fixed bugged communications of amalib. Results where not correctly parsed with the new async way of doing things. --- src/rust/amadeus-next/amalib/src/connexion.rs | 120 +++++++----------- src/rust/amadeus-next/amalib/src/query.rs | 77 ++++++----- src/rust/amadeus-next/amalib/src/response.rs | 2 +- src/rust/amadeus-next/lkt-rs/src/args.rs | 16 +-- src/rust/amadeus-next/lkt-rs/src/config.rs | 68 ++++------ src/rust/amadeus-next/lkt-rs/src/main.rs | 113 +++++++++++------ 6 files changed, 195 insertions(+), 201 deletions(-) diff --git a/src/rust/amadeus-next/amalib/src/connexion.rs b/src/rust/amadeus-next/amalib/src/connexion.rs index 29de6762..1e2f9bdc 100644 --- a/src/rust/amadeus-next/amalib/src/connexion.rs +++ b/src/rust/amadeus-next/amalib/src/connexion.rs @@ -28,6 +28,7 @@ async fn write_string( err_report!(err BufferDontEndWithLF) } else { loop { + trace!("try to write {} bytes...", buffer.len()); stream.writable().await.map_err(Io)?; match stream.try_write(buffer.as_bytes()) { Ok(n) if n != size => break err_report!(err IncorrectWriteSize(size, n)), @@ -39,79 +40,46 @@ async fn write_string( } } -/// Read replies from the lektord server. +/// Read replies from the lektord server. If the `exit_on_would_block` is set, +/// and if nothing is available returns nothing! async fn read_replies( stream: &mut TcpStream, + exit_on_would_block: bool, ) -> StackedResult<(Vec<String>, Option<usize>), LektorCommError> { let (mut ret, mut continuation) = (Vec::new(), None); + let peer_addr = stream.peer_addr().expect("failed to get peer address"); loop { - stream - .readable().await - .map_err(|e| err_report!(LektorCommError::Io(e) => [ format!("failed to get MPD version from {:?}", stream.peer_addr()) ]))?; + trace!("try to read from remote..."); + stream.readable().await.map_err(|e| { + err_report!(LektorCommError::Io(e) => [ + format!("failed to read from {peer_addr}") ]) + })?; let mut line = [0; constants::LKT_MESSAGE_MAX]; match stream.try_read(&mut line) { - Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => continue, - Err(e) => return err_report!(err LektorCommError::Io(e)), - Ok(0) => { - return err_report!(err LektorCommError::Io(std::io::Error::new(std::io::ErrorKind::Other, "recieved empty line"))) - } - Ok(size) => { - let msg = std::str::from_utf8(&line[..size]) - .map_err(|e| err_report!(LektorCommError::Utf8(e) => [ format!("the lektord server at {:?} returned an invalid utf8 string", stream.peer_addr()) ]))? - .trim(); - match LektorQueryLineType::from_str(msg) { - Ok(LektorQueryLineType::Ok) => return Ok((ret, continuation)), - Ok(LektorQueryLineType::Ack) => { - return err_report!(err LektorCommError::Io(std::io::Error::from( - std::io::ErrorKind::Other - ))) - } - Ok(LektorQueryLineType::Data) => ret.push(msg.to_string()), - Ok(LektorQueryLineType::ListOk) => continue, - Ok(LektorQueryLineType::Continuation(cont)) => continuation = Some(cont), - Err(()) => { - return err_report!(err LektorCommError::QueryError => [ "unknown query line type" ]) - } - } + Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => { + either!(exit_on_would_block => return Ok((vec![], None)); continue) } - } - } -} - -/// Read replies from the lektord server. If nothing is available returns -/// nothing! This function do the same thing as [read_replies] but breaks on -/// [std::io::ErrorKind::WouldBlock]. -async fn read_maybe_replies( - stream: &mut TcpStream, -) -> StackedResult<Option<(Vec<String>, Option<usize>)>, LektorCommError> { - let (mut ret, mut continuation) = (Vec::new(), None); - loop { - stream - .readable().await - .map_err(|e| err_report!(LektorCommError::Io(e) => [ format!("failed to get MPD version from {:?}", stream.peer_addr()) ]))?; - let mut line = [0; constants::LKT_MESSAGE_MAX]; - match stream.try_read(&mut line) { - Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => return Ok(None), Err(e) => return err_report!(err LektorCommError::Io(e)), - Ok(0) => { - return err_report!(err LektorCommError::Io(std::io::Error::new(std::io::ErrorKind::Other, "recieved empty line"))) - } + Ok(0) => return Ok((ret, continuation)), Ok(size) => { - let msg = std::str::from_utf8(&line[..size]) - .map_err(|e| err_report!(LektorCommError::Utf8(e) => [ format!("the lektord server at {:?} returned an invalid utf8 string", stream.peer_addr()) ]))? - .trim(); - match LektorQueryLineType::from_str(msg) { - Ok(LektorQueryLineType::Ok) => return Ok(Some((ret, continuation))), - Ok(LektorQueryLineType::Ack) => { - return err_report!(err LektorCommError::Io(std::io::Error::from( - std::io::ErrorKind::Other - ))) - } - Ok(LektorQueryLineType::Data) => ret.push(msg.to_string()), - Ok(LektorQueryLineType::ListOk) => continue, - Ok(LektorQueryLineType::Continuation(cont)) => continuation = Some(cont), - Err(()) => { - return err_report!(err LektorCommError::QueryError => [ "unknown query line type" ]) + let lines = std::str::from_utf8(&line[..size]).map_err(|e| + err_report!(LektorCommError::Utf8(e) => [ + format!("the lektord server at {peer_addr} returned an invalid utf8 string") + ]) + )?.trim().lines().map(|line| line.trim()); + for msg in lines { + trace!("got line: {msg}"); + match LektorQueryLineType::from_str(msg) { + Ok(LektorQueryLineType::Ok) => return Ok((ret, continuation)), + Ok(LektorQueryLineType::Ack(msg)) => { + return err_report!(err LektorCommError::MpdAck => [ msg ]) + } + Ok(LektorQueryLineType::Data) => ret.push(msg.to_string()), + Ok(LektorQueryLineType::ListOk) => continue, + Ok(LektorQueryLineType::Continuation(cont)) => continuation = Some(cont), + Err(()) => { + return err_report!(err LektorCommError::QueryError => [ "unknown query line type" ]) + } } } } @@ -195,6 +163,12 @@ impl LektorConnexion { &mut self, query: LektorQuery, ) -> StackedResult<LektorResponse, LektorCommError> { + debug!( + "send query to server {}: {query:?}", + self.stream + .peer_addr() + .expect("failed to get remote address") + ); let mut res: Vec<String> = Vec::new(); query .verify() @@ -213,22 +187,21 @@ impl LektorConnexion { query: LektorQuery, previous_ret: &mut Vec<String>, ) -> StackedResult<(), LektorCommError> { - write_string(&mut self.stream, query.to_string()).await?; + write_string(&mut self.stream, query.format_query()).await?; loop { - match read_replies(&mut self.stream).await { + match read_replies(&mut self.stream, false).await { Err(e) => return Err(e), Ok((res, _)) if res.is_empty() => return Ok(()), Ok((res, None)) => { + trace!("got no continuation and return: {res:?}"); previous_ret.extend(res); return Ok(()); } Ok((res, Some(cont))) => { + trace!("got continuation {cont} and return: {res:?}"); previous_ret.extend(res); - write_string( - &mut self.stream, - LektorQuery::create_continuation(query.clone(), cont).to_string(), - ) - .await?; + let query = LektorQuery::create_continuation(query.clone(), cont); + write_string(&mut self.stream, query.format_query()).await?; } } } @@ -252,7 +225,7 @@ impl LektorIdleConnexion { write_string(&mut stream, idle_list_buffer).await?; - let (mut reply, _) = read_replies(&mut stream).await?; + let (mut reply, _) = read_replies(&mut stream, false).await?; either!(reply.is_empty() => Ok(Self { version, stream, idle_list }) ; { @@ -264,9 +237,8 @@ impl LektorIdleConnexion { } pub async fn get_notifications(&mut self) -> Vec<LektorIdleNotification> { - match read_maybe_replies(&mut self.stream).await { - Ok(None) => vec![], - Ok(Some((notifications, _))) => notifications + match read_replies(&mut self.stream, true).await { + Ok((notifications, _)) => notifications .iter() .filter_map(|msg| msg.strip_prefix("changed: ")) .flat_map(|notifications| notifications.split(&[',', ' '][..])) diff --git a/src/rust/amadeus-next/amalib/src/query.rs b/src/rust/amadeus-next/amalib/src/query.rs index fda3e8d1..4aeab97c 100644 --- a/src/rust/amadeus-next/amalib/src/query.rs +++ b/src/rust/amadeus-next/amalib/src/query.rs @@ -3,10 +3,11 @@ use crate::*; use std::string::ToString; +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) enum LektorQueryLineType { Ok, ListOk, - Ack, + Ack(String), Continuation(usize), Data, } @@ -16,6 +17,11 @@ pub enum LektorQuery { Ping, Close, KillServer, + RestartServer, + Update, + DryUpdate, + Populate, + DryPopulate, ConnectAsUser(String, Box<LektorQuery>), CurrentKara, @@ -48,7 +54,7 @@ impl std::str::FromStr for LektorQueryLineType { if Self::is_line_ok(line) { Ok(Self::Ok) } else if Self::is_line_ack(line) { - Ok(Self::Ack) + Ok(Self::Ack(line.to_string())) } else if Self::is_line_list_ok(line) { Ok(Self::ListOk) } else if let Some(cont) = Self::is_line_continuation(line) { @@ -79,7 +85,7 @@ impl LektorQueryLineType { } fn is_line_ack(line: &str) -> bool { - line.starts_with("ACK: ") + line.starts_with("ACK [") } } @@ -90,10 +96,11 @@ type QueryToTypeResponseBuilder = fn(LektorFormatedResponse) -> Result<LektorRes impl LektorQuery { /// Get the function to use to produce the typed response from the formated /// response, to automatically create the correct thing. - pub fn get_response_type(&self) -> QueryToTypeResponseBuilder { + pub(crate) fn get_response_type(&self) -> QueryToTypeResponseBuilder { use LektorQuery::*; match self { - Ping | Close | KillServer | PlayNext | PlayPrevious | ShuffleQueue | InsertKara(_) + Populate | DryPopulate | Update | DryUpdate | Ping | Close | KillServer + | RestartServer | PlayNext | PlayPrevious | ShuffleQueue | InsertKara(_) | AddKara(_) => LektorEmptyResponse::from_formated, CreatePlaylist(_) @@ -115,7 +122,7 @@ impl LektorQuery { /// Create a continued query out of another one. If the query is already a /// continuation query then the underlying query is reused. - pub fn create_continuation(query: Self, cont: usize) -> Self { + pub(crate) fn create_continuation(query: Self, cont: usize) -> Self { match query { Self::Continuation(_, query) => Self::Continuation(cont, query), _ => Self::Continuation(cont, Box::new(query)), @@ -123,8 +130,13 @@ impl LektorQuery { } /// Verify that a query is Ok. - pub fn verify(&self) -> Result<(), String> { + pub(crate) fn verify(&self) -> Result<(), String> { use LektorQuery::*; + macro_rules! admin_commands { + () => { + Populate | DryPopulate | DryUpdate | Update | KillServer | RestartServer | Close + }; + } match self { // User commands SearchKara(_) | FindAddKara(_) | InsertKara(_) | AddKara(_) | PlaybackStatus @@ -139,12 +151,11 @@ impl LektorQuery { } // Should be admin commands - Close => Err("close is an admin command".to_string()), - KillServer => Err("kill server is an admin command".to_string()), + admin_commands!() => Err("admin command".to_string()), // Admin commands ConnectAsUser(_, cmd) => match cmd.as_ref() { - Close | KillServer => Ok(()), + admin_commands!() => Ok(()), _ => Err(format!("not an admin command: {cmd:?}")), }, @@ -155,30 +166,30 @@ impl LektorQuery { }, } } -} - -impl std::fmt::Display for LektorQuery { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - macro_rules! lkt_str { - ($lit:literal) => { - f.write_str(concat!($lit, '\n')) - }; - } + /// 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() }; } use LektorQuery::*; match self { + Populate => lkt_str!("rescan"), + DryPopulate => lkt_str!("__dry_rescan"), + Update => lkt_str!("update"), + DryUpdate => lkt_str!("__dry_update"), Ping => lkt_str!("ping"), Close => lkt_str!("close"), KillServer => lkt_str!("kill"), - ConnectAsUser(password, cmd) => write!( - f, + RestartServer => lkt_str!("__restart"), + ConnectAsUser(password, cmd) => format!( concat!( "command_list_ok_begin\n", "password {}\n", - "{}\n", + "{}", "command_list_end\n", ), - password, cmd + password, + cmd.format_query() ), CurrentKara => lkt_str!("currentsong"), @@ -189,19 +200,19 @@ impl std::fmt::Display for LektorQuery { ShuffleQueue => lkt_str!("shuffle"), ListAllPlaylists => lkt_str!("listplaylists"), - ListPlaylist(plt_name) => writeln!(f, "listplaylist {plt_name}"), - SearchKara(uri) => writeln!(f, "find {uri}"), + ListPlaylist(plt_name) => format!("listplaylist {plt_name}\n"), + SearchKara(uri) => format!("find {uri}\n"), - FindAddKara(uri) => writeln!(f, "findadd {uri}"), - InsertKara(uri) => writeln!(f, "__insert {uri}"), - AddKara(uri) => writeln!(f, "add {uri}"), + FindAddKara(uri) => format!("findadd {uri}\n"), + InsertKara(uri) => format!("__insert {uri}\n"), + AddKara(uri) => format!("add {uri}\n"), - CreatePlaylist(name) => todo!("create playlist {name}"), - DestroyPlaylist(name) => todo!("destroy playlist {name}"), - AddToPlaylist(name, uri) => todo!("add to playlist {name} {uri}"), - RemoveFromPlaylist(name, uri) => todo!("remove from playlist {name} {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"), - Continuation(cont, query) => write!(f, "{cont} {query}"), + Continuation(cont, query) => format!("{cont} {}\n", query.format_query()), } } } diff --git a/src/rust/amadeus-next/amalib/src/response.rs b/src/rust/amadeus-next/amalib/src/response.rs index 75e53f74..626eea26 100644 --- a/src/rust/amadeus-next/amalib/src/response.rs +++ b/src/rust/amadeus-next/amalib/src/response.rs @@ -172,7 +172,7 @@ impl LektorCurrentKaraResponse { } pub fn into_inner(self) -> LektorCurrentKaraInnerResponse { - self.content.unwrap() + self.content.expect("no current kara playing") } } diff --git a/src/rust/amadeus-next/lkt-rs/src/args.rs b/src/rust/amadeus-next/lkt-rs/src/args.rs index 85518495..c9325d1c 100644 --- a/src/rust/amadeus-next/lkt-rs/src/args.rs +++ b/src/rust/amadeus-next/lkt-rs/src/args.rs @@ -327,7 +327,6 @@ pub enum LktCommand { #[derive(Debug, Clone, PartialEq, Eq)] pub enum LktQueueCommand { ShowCurrent, - ShowStatus, List { @@ -335,20 +334,15 @@ pub enum LktQueueCommand { }, Next, - Previous, - Play { - index: usize, - }, - Pause, - UnPause, - TogglePause, - Stop, + Play { + index: usize, + }, Add { priority: PriorityLevel, @@ -356,7 +350,6 @@ pub enum LktQueueCommand { }, Crop, - Clear { up_to_lvl: PriorityLevel, }, @@ -464,7 +457,8 @@ impl LktCommand { SubCommand::Queue { shuffle: Some(lvl), .. } => Queue(LktQueueCommand::Shuffle { up_to_lvl: lvl.unwrap_or(PriorityLevel::Enforce) }), SubCommand::Queue { clear: Some(lvl), .. } => Queue(LktQueueCommand::Clear { up_to_lvl: lvl.unwrap_or(PriorityLevel::Enforce) }), SubCommand::Queue { seek: Some(id), .. } => { Queue(LktQueueCommand::SeekIdInQueue { id }) } - SubCommand::Queue { pos: Some(range), .. } => Queue(LktQueueCommand::List { range: range.unwrap_or_else(|| 0..usize::MAX) }), + 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 { swap: Some(args), .. } => match &args[..] { [p1, p2] => Queue(LktQueueCommand::SwapPositions { diff --git a/src/rust/amadeus-next/lkt-rs/src/config.rs b/src/rust/amadeus-next/lkt-rs/src/config.rs index d0ea7f9c..67115c07 100644 --- a/src/rust/amadeus-next/lkt-rs/src/config.rs +++ b/src/rust/amadeus-next/lkt-rs/src/config.rs @@ -9,14 +9,9 @@ pub enum LktHostPort { } #[derive(Debug, serde::Deserialize, serde::Serialize)] -pub struct LktAdminConfig { - pub user: Option<String>, - pub password: Option<String>, -} - -#[derive(Debug, serde::Deserialize, serde::Serialize, Default)] pub struct LktSearchConfig { pub query_type: LektorQueryType, + pub default_queue_count: usize, } #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -28,16 +23,25 @@ pub struct LktHostConfig { #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct LktConfig { pub host: LktHostConfig, - pub admin: Option<LktAdminConfig>, + pub password: Option<String>, pub search: LktSearchConfig, } +impl Default for LktSearchConfig { + fn default() -> Self { + Self { + query_type: Default::default(), + default_queue_count: 15, + } + } +} + impl Default for LktConfig { fn default() -> Self { Self { host: Default::default(), - admin: Some(Default::default()), search: Default::default(), + password: Some("hashire".to_string()), } } } @@ -48,15 +52,6 @@ impl Default for LktHostPort { } } -impl Default for LktAdminConfig { - fn default() -> Self { - Self { - user: Some("sakura".to_string()), - password: Some("sakura".to_string()), - } - } -} - impl Default for LktHostConfig { fn default() -> Self { Self { @@ -67,30 +62,23 @@ impl Default for LktHostConfig { } impl LktConfig { - pub fn has_valid_admin_config(&self) -> bool { - matches!(&self.admin, Some(LktAdminConfig { - user: Some(user), - password: Some(password), - }) if !user.trim().is_empty() && !password.trim().is_empty()) - } -} - -pub fn get_or_write_default() -> Result<LktConfig, String> { - let path = commons::user_config_directory("amadeus").join("lkt.toml"); - match std::fs::read_to_string(&path) { - Ok(config) => toml::from_str(&config).map_err(|err| { - let path = path.to_string_lossy(); - format!("invalid config file `{path}`: {err}") - }), - Err(_) => { - let default_config = LktConfig::default(); - let pretty_config = toml::to_string_pretty(&default_config) - .expect("failed to prettify the default config..."); - std::fs::write(&path, pretty_config).map_err(|err| { + pub fn get_or_write_default() -> Result<LktConfig, String> { + let path = commons::user_config_directory("amadeus").join("lkt.toml"); + match std::fs::read_to_string(&path) { + Ok(config) => toml::from_str(&config).map_err(|err| { let path = path.to_string_lossy(); - format!("failed to write default config to file `{path}`: {err}") - })?; - Ok(default_config) + format!("invalid config file `{path}`: {err}") + }), + Err(_) => { + let default_config = LktConfig::default(); + let pretty_config = toml::to_string_pretty(&default_config) + .expect("failed to prettify the default config..."); + std::fs::write(&path, pretty_config).map_err(|err| { + let path = path.to_string_lossy(); + format!("failed to write default config to file `{path}`: {err}") + })?; + Ok(default_config) + } } } } diff --git a/src/rust/amadeus-next/lkt-rs/src/main.rs b/src/rust/amadeus-next/lkt-rs/src/main.rs index 38230133..9bfb3a7c 100644 --- a/src/rust/amadeus-next/lkt-rs/src/main.rs +++ b/src/rust/amadeus-next/lkt-rs/src/main.rs @@ -3,18 +3,20 @@ mod config; mod parsers; mod types; +use crate::{args::*, config::LktConfig}; +use amalib::{LektorQuery, LektorResponse}; + #[tokio::main(worker_threads = 2)] async fn main() { commons::Report::install_debug_hook::<std::backtrace::Backtrace>(|_, _| {}); commons::logger::init(Some(commons::log::Level::Trace)) .unwrap_or_else(|e| panic!("failed to install logger: {e}")); - let config = config::get_or_write_default().expect("failed to get or write default config"); - - let cmd = args::LktCommand::parse(&config).expect("oupsy"); + let config = LktConfig::get_or_write_default().expect("failed to get or write default config"); + let cmd = LktCommand::parse(&config).expect("oupsy"); handle_cmd(config, cmd).await } -async fn handle_cmd(config: config::LktConfig, cmd: args::LktCommand) { +async fn handle_cmd(config: LktConfig, cmd: LktCommand) { commons::log::debug!("{config:#?}\ncmd = {cmd:#?}"); let conn = match config.host.socket { config::LktHostPort::UNIX => unimplemented!("connexion to unix socket is not implemented"), @@ -23,10 +25,10 @@ async fn handle_cmd(config: config::LktConfig, cmd: args::LktCommand) { .expect("failed to connect to the lektord server"), }; match cmd { - args::LktCommand::Queue(cmd) => handle_cmd_queue(config, conn, cmd).await, - args::LktCommand::Search(cmd) => handle_cmd_search(config, conn, cmd).await, - args::LktCommand::Playlist(cmd) => handle_cmd_playlist(config, conn, cmd).await, - args::LktCommand::Admin(cmd) => handle_cmd_admin(config, conn, cmd).await, + LktCommand::Queue(cmd) => handle_cmd_queue(config, conn, cmd).await, + LktCommand::Search(cmd) => handle_cmd_search(config, conn, cmd).await, + LktCommand::Playlist(cmd) => handle_cmd_playlist(config, conn, cmd).await, + LktCommand::Admin(cmd) => handle_cmd_admin(config, conn, cmd).await, } } @@ -43,49 +45,66 @@ macro_rules! send { }}; } -async fn handle_cmd_queue( - _: config::LktConfig, - _: amalib::LektorConnexion, - _: args::LktQueueCommand, -) { - unimplemented!() +async fn handle_cmd_queue(_: LktConfig, mut conn: amalib::LektorConnexion, cmd: LktQueueCommand) { + match cmd { + LktQueueCommand::ShowCurrent => { + send!(conn => LektorQuery::CurrentKara; LektorResponse::CurrentKara(kara) => { + kara.maybe_into_inner().map(|kara| println!("{kara:#?}")); + }) + } + LktQueueCommand::ShowStatus => { + send!(conn => LektorQuery::PlaybackStatus; LektorResponse::PlaybackStatus(status) => { + println!("{status:#?}"); + }) + } + 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!(), + } } -async fn handle_cmd_search( - _: config::LktConfig, - _: amalib::LektorConnexion, - _: args::LktSearchCommand, -) { +async fn handle_cmd_search(_: LktConfig, _: amalib::LektorConnexion, _: LktSearchCommand) { unimplemented!() } async fn handle_cmd_playlist( - _: config::LktConfig, + _: LktConfig, mut conn: amalib::LektorConnexion, - cmd: args::LktPlaylistCommand, + cmd: LktPlaylistCommand, ) { match cmd { - args::LktPlaylistCommand::Create { name } => { - send!(conn => amalib::LektorQuery::CreatePlaylist(name); ok) + LktPlaylistCommand::Create { name } => { + send!(conn => LektorQuery::CreatePlaylist(name); ok) } - args::LktPlaylistCommand::Destroy { name } => { - send!(conn => amalib::LektorQuery::DestroyPlaylist(name); ok) + LktPlaylistCommand::Destroy { name } => { + send!(conn => LektorQuery::DestroyPlaylist(name); ok) } - args::LktPlaylistCommand::Add { name, query } => { - send!(conn => amalib::LektorQuery::AddToPlaylist(name, query); ok) + LktPlaylistCommand::Add { name, query } => { + send!(conn => LektorQuery::AddToPlaylist(name, query); ok) } - args::LktPlaylistCommand::Remove { name, query } => { - send!(conn => amalib::LektorQuery::RemoveFromPlaylist(name, query); ok) + LktPlaylistCommand::Remove { name, query } => { + send!(conn => LektorQuery::RemoveFromPlaylist(name, query); ok) } - args::LktPlaylistCommand::List => { - send!(conn => amalib::LektorQuery::ListAllPlaylists - ; amalib::LektorResponse::PlaylistSet(playlists) => { + LktPlaylistCommand::List => { + send!(conn => LektorQuery::ListAllPlaylists + ; LektorResponse::PlaylistSet(playlists) => { playlists.into_iter().for_each(|plt| println!("{plt}")) }) } - args::LktPlaylistCommand::ListContent { name } => { - send!(conn => amalib::LektorQuery::ListPlaylist(name) - ; amalib::LektorResponse::KaraSet(karas) => { + LktPlaylistCommand::ListContent { name } => { + send!(conn => LektorQuery::ListPlaylist(name) + ; LektorResponse::KaraSet(karas) => { karas.into_iter().for_each(|kara| println!("{kara}")) }) } @@ -93,13 +112,23 @@ async fn handle_cmd_playlist( } async fn handle_cmd_admin( - config: config::LktConfig, - _: amalib::LektorConnexion, - cmd: args::LktAdminCommand, + config: LktConfig, + mut conn: amalib::LektorConnexion, + cmd: LktAdminCommand, ) { - if config.has_valid_admin_config() { - unimplemented!("handle admin command: {cmd:#?}") - } else { - panic!("no admin config block in config file") + match config.password { + Some(password) => { + let cmd = Box::new(match cmd { + LktAdminCommand::Ping => LektorQuery::Ping, + LktAdminCommand::Kill => LektorQuery::KillServer, + LktAdminCommand::Restart => LektorQuery::RestartServer, + LktAdminCommand::Update { dry: true } => LektorQuery::Update, + LktAdminCommand::Update { dry: false } => LektorQuery::DryUpdate, + LktAdminCommand::Populate { dry: false } => LektorQuery::Populate, + LktAdminCommand::Populate { dry: true } => LektorQuery::DryPopulate, + }); + send!(conn => LektorQuery::ConnectAsUser(password, cmd); ok); + } + None => panic!("no admin config block in config file"), } } -- GitLab