From f8fdaf28929266d945da90925f8009789ea43737 Mon Sep 17 00:00:00 2001 From: Savanni D'Gerinel Date: Mon, 26 Aug 2024 11:33:43 -0400 Subject: [PATCH] Build APIs for starting and stoping tracks --- gm-dash/server/src/main.rs | 95 +++++++++++++++++++++---------------- gm-dash/server/src/state.rs | 76 +++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 40 deletions(-) create mode 100644 gm-dash/server/src/state.rs diff --git a/gm-dash/server/src/main.rs b/gm-dash/server/src/main.rs index c80aec8..b52b375 100644 --- a/gm-dash/server/src/main.rs +++ b/gm-dash/server/src/main.rs @@ -1,45 +1,15 @@ use pipewire::{context::Context, main_loop::MainLoop}; -use std::{ - net::{Ipv6Addr, SocketAddrV6}, - sync::{Arc, RwLock}, -}; +use serde::Deserialize; +use std::net::{Ipv6Addr, SocketAddrV6}; use tokio::task::spawn_blocking; use warp::{serve, Filter}; -struct State_ { - device_list: Vec, -} +mod state; +use state::State; -#[derive(Clone)] -struct State { - internal: Arc>, -} - -impl State { - fn new() -> State { - let internal = State_ { - device_list: vec![], - }; - State { - internal: Arc::new(RwLock::new(internal)), - } - } - - fn add_audio(&self, device: String) { - let mut st = self.internal.write().unwrap(); - (*st).device_list.push(device); - } - - fn audio_devices(&self) -> Vec { - let st = self.internal.read().unwrap(); - (*st).device_list.clone() - } -} - -impl Default for State { - fn default() -> State { - State::new() - } +#[derive(Deserialize)] +struct PlayTrackParams { + track_name: String, } async fn server_main(state: State) { @@ -55,13 +25,58 @@ async fn server_main(state: State) { } }); - let routes = root.or(list_output_devices); + let list_tracks = warp::path!("tracks").map({ + let state = state.clone(); + move || serde_json::to_string(&state.tracks()).unwrap() + }); + + let play_track = warp::put() + .and(warp::path!("playing")) + .and(warp::body::json()) + .map({ + let state = state.clone(); + move |params: PlayTrackParams| { + state.play(params.track_name); + "".to_owned() + } + }); + + let stop_track = warp::delete() + .and(warp::path!("playing")) + .and(warp::body::json()) + .map({ + let state = state.clone(); + move |params: PlayTrackParams| { + state.stop(params.track_name); + "".to_owned() + } + }); + + let stop_all_tracks = warp::delete().and(warp::path!("playing")).map({ + let state = state.clone(); + move || { + state.stop_all(); + "".to_owned() + } + }); + + let now_playing = warp::path!("playing").map({ + let state = state.clone(); + move || serde_json::to_string(&state.playing()).unwrap() + }); + + let routes = root + .or(list_output_devices) + .or(list_tracks) + .or(play_track) + .or(stop_track) + .or(stop_all_tracks) + .or(now_playing); serve(routes).run(server_addr).await; } -fn handle_add_audio_device(state: State, props: &pipewire::spa::utils::dict::DictRef) -{ +fn handle_add_audio_device(state: State, props: &pipewire::spa::utils::dict::DictRef) { if props.get("media.class") == Some("Audio/Sink") { if let Some(device_name) = props.get("node.description") { state.add_audio(device_name.to_owned()); diff --git a/gm-dash/server/src/state.rs b/gm-dash/server/src/state.rs new file mode 100644 index 0000000..5a13307 --- /dev/null +++ b/gm-dash/server/src/state.rs @@ -0,0 +1,76 @@ +use std::{collections::HashSet, sync::{Arc, RwLock}}; + +struct State_ { + device_list: Vec, + track_list: Vec, + currently_playing: HashSet, +} + +#[derive(Clone)] +pub struct State { + internal: Arc>, +} + +impl State { + fn new() -> State { + let internal = State_ { + device_list: vec![], + track_list: vec![ + "/home/savanni/Music/Travis Savoie/RPG Toolkit Volume II/01 - A Day to Rebuild.mp3.mp3".to_owned(), + "/home/savanni/Music/Travis Savoie/RPG Toolkit Volume II/05 - Books and Spellcrafting.mp3.mp3".to_owned(), + ], + currently_playing: HashSet::default(), + }; + State { + internal: Arc::new(RwLock::new(internal)), + } + } + + pub fn add_audio(&self, device: String) { + let mut st = self.internal.write().unwrap(); + st.device_list.push(device); + } + + pub fn audio_devices(&self) -> Vec { + let st = self.internal.read().unwrap(); + st.device_list.clone() + } + + pub fn tracks(&self) -> Vec { + let st = self.internal.read().unwrap(); + st.track_list.clone() + } + + pub fn play(&self, track: String) -> Result<(), String> { + let mut st = self.internal.write().unwrap(); + if st.track_list.contains(&track) { + st.currently_playing.insert(track); + } + Ok(()) + } + + pub fn stop(&self, track: String) -> Result<(), String> { + let mut st = self.internal.write().unwrap(); + st.currently_playing.remove(&track); + Ok(()) + } + + pub fn stop_all(&self) -> Result<(), String> { + let mut st = self.internal.write().unwrap(); + st.currently_playing = HashSet::new(); + Ok(()) + } + + pub fn playing(&self) -> Vec { + let st = self.internal.read().unwrap(); + st.currently_playing.iter().cloned().collect() + } +} + +impl Default for State { + fn default() -> State { + State::new() + } +} + +