charcoal_client/actions/
track_manager.rs

1use async_trait::async_trait;
2use hearth_interconnect::messages::Message;
3use hearth_interconnect::worker_communication::{DWCActionType, DirectWorkerCommunication};
4use std::time::Duration;
5use nanoid::nanoid;
6use crate::background::connector::BoilerplateParseIPCError;
7use crate::background::processor::IPCData;
8use crate::PlayerObject;
9use snafu::prelude::*;
10use tokio::sync::broadcast::error::SendError;
11
12#[derive(Debug, Snafu)]
13pub enum TrackActionError {
14    #[snafu(display("Failed to send IPC request to Background thread"))]
15    FailedToSendIPCRequest { source: SendError<IPCData> },
16    #[snafu(display("Did not receive metadata result within timeout time-frame"))]
17    TimedOutWaitingForMetadataResult { source: BoilerplateParseIPCError },
18}
19
20#[async_trait]
21/// Provides functionality that can be used once you start playing a track such as: looping, pausing, and resuming.
22pub trait TrackManager {
23    /// Set playback volume
24    async fn set_playback_volume(&self, playback_volume: f32) -> Result<(), TrackActionError>;
25    /// Stop looping
26    async fn force_stop_loop(&self) -> Result<(), TrackActionError>;
27    /// Loop forever
28    async fn loop_indefinitely(&self) -> Result<(), TrackActionError>;
29    /// Loop X amount of times
30    async fn loop_x_times(&self, times: usize) -> Result<(), TrackActionError>;
31    /// Seek to position on track from start
32    async fn seek_to_position(&self, position: Duration) -> Result<(), TrackActionError>;
33    /// Resume playback
34    async fn resume_playback(&self) -> Result<(), TrackActionError>;
35    /// Pause playback
36    async fn pause_playback(&self) -> Result<(), TrackActionError>;
37    /// Get metadata for track currently being played
38    async fn get_metadata(&mut self) -> Result<(), TrackActionError>;
39}
40#[async_trait]
41impl TrackManager for PlayerObject {
42    async fn set_playback_volume(&self, playback_volume: f32) -> Result<(), TrackActionError> {
43        self.bg_com_tx
44            .send(IPCData::new_from_main(
45                Message::DirectWorkerCommunication(DirectWorkerCommunication {
46                    job_id: self.job_id.read().await.clone().unwrap(),
47                    action_type: DWCActionType::SetPlaybackVolume,
48                    play_audio_url: None,
49                    guild_id: self.guild_id.clone(),
50                    request_id: Some(nanoid!()),
51                    new_volume: Some(playback_volume),
52                    seek_position: None,
53                    loop_times: None,
54                    worker_id: self.worker_id.read().await.clone().unwrap(),
55                    voice_channel_id: None,
56                }),
57                self.tx.clone(),
58                self.guild_id.clone(),
59            ))
60            .context(FailedToSendIPCRequestSnafu)?;
61        Ok(())
62    }
63    async fn force_stop_loop(&self) -> Result<(), TrackActionError> {
64        self.bg_com_tx
65            .send(IPCData::new_from_main(
66                Message::DirectWorkerCommunication(DirectWorkerCommunication {
67                    job_id: self.job_id.read().await.clone().unwrap(),
68                    action_type: DWCActionType::ForceStopLoop,
69                    play_audio_url: None,
70                    guild_id: self.guild_id.clone(),
71                    request_id: Some(nanoid!()),
72                    new_volume: None,
73                    seek_position: None,
74                    loop_times: None,
75                    worker_id: self.worker_id.read().await.clone().unwrap(),
76                    voice_channel_id: None,
77                }),
78                self.tx.clone(),
79                self.guild_id.clone(),
80            ))
81            .context(FailedToSendIPCRequestSnafu)?;
82
83        Ok(())
84    }
85    async fn loop_indefinitely(&self) -> Result<(), TrackActionError> {
86        self.bg_com_tx
87            .send(IPCData::new_from_main(
88                Message::DirectWorkerCommunication(DirectWorkerCommunication {
89                    job_id: self.job_id.read().await.clone().unwrap(),
90                    action_type: DWCActionType::LoopForever,
91                    play_audio_url: None,
92                    guild_id: self.guild_id.clone(),
93                    request_id: Some(nanoid!()),
94                    new_volume: None,
95                    seek_position: None,
96                    loop_times: None,
97                    worker_id: self.worker_id.read().await.clone().unwrap(),
98                    voice_channel_id: None,
99                }),
100                self.tx.clone(),
101                self.guild_id.clone(),
102            ))
103            .context(FailedToSendIPCRequestSnafu)?;
104
105        Ok(())
106    }
107
108    async fn loop_x_times(&self, times: usize) -> Result<(), TrackActionError> {
109        self.bg_com_tx
110            .send(IPCData::new_from_main(
111                Message::DirectWorkerCommunication(DirectWorkerCommunication {
112                    job_id: self.job_id.read().await.clone().unwrap(),
113                    action_type: DWCActionType::LoopXTimes,
114                    play_audio_url: None,
115                    guild_id: self.guild_id.clone(),
116                    request_id: Some(nanoid!()),
117                    new_volume: None,
118                    seek_position: None,
119                    loop_times: Some(times),
120                    worker_id: self.worker_id.read().await.clone().unwrap(),
121                    voice_channel_id: None,
122                }),
123                self.tx.clone(),
124                self.guild_id.clone(),
125            ))
126            .context(FailedToSendIPCRequestSnafu)?;
127
128        Ok(())
129    }
130    async fn seek_to_position(&self, position: Duration) -> Result<(), TrackActionError> {
131        self.bg_com_tx
132            .send(IPCData::new_from_main(
133                Message::DirectWorkerCommunication(DirectWorkerCommunication {
134                    job_id: self.job_id.read().await.clone().unwrap(),
135                    action_type: DWCActionType::SeekToPosition,
136                    play_audio_url: None,
137                    guild_id: self.guild_id.clone(),
138                    request_id: Some(nanoid!()),
139                    new_volume: None,
140                    seek_position: Some(position.as_millis() as u64),
141                    loop_times: None,
142                    worker_id: self.worker_id.read().await.clone().unwrap(),
143                    voice_channel_id: None,
144                }),
145                self.tx.clone(),
146                self.guild_id.clone(),
147            ))
148            .context(FailedToSendIPCRequestSnafu)?;
149
150        Ok(())
151    }
152    async fn resume_playback(&self) -> Result<(), TrackActionError> {
153        self.bg_com_tx
154            .send(IPCData::new_from_main(
155                Message::DirectWorkerCommunication(DirectWorkerCommunication {
156                    job_id: self.job_id.read().await.clone().unwrap(),
157                    action_type: DWCActionType::ResumePlayback,
158                    play_audio_url: None,
159                    guild_id: self.guild_id.clone(),
160                    request_id: Some(nanoid!()),
161                    new_volume: None,
162                    seek_position: None,
163                    loop_times: None,
164                    worker_id: self.worker_id.read().await.clone().unwrap(),
165                    voice_channel_id: None,
166                }),
167                self.tx.clone(),
168                self.guild_id.clone(),
169            ))
170            .context(FailedToSendIPCRequestSnafu)?;
171
172        Ok(())
173    }
174    async fn pause_playback(&self) -> Result<(), TrackActionError> {
175        self.bg_com_tx
176            .send(IPCData::new_from_main(
177                Message::DirectWorkerCommunication(DirectWorkerCommunication {
178                    job_id: self.job_id.read().await.clone().unwrap(),
179                    action_type: DWCActionType::PausePlayback,
180                    play_audio_url: None,
181                    guild_id: self.guild_id.clone(),
182                    request_id: Some(nanoid!()),
183                    new_volume: None,
184                    seek_position: None,
185                    loop_times: None,
186                    worker_id: self.worker_id.read().await.clone().unwrap(),
187                    voice_channel_id: None,
188                }),
189                self.tx.clone(),
190                self.guild_id.clone(),
191            ))
192            .context(FailedToSendIPCRequestSnafu)?;
193
194        Ok(())
195    }
196    async fn get_metadata(&mut self) -> Result<(), TrackActionError> {
197        self.bg_com_tx
198            .send(IPCData::new_from_main(
199                Message::DirectWorkerCommunication(DirectWorkerCommunication {
200                    job_id: self.job_id.read().await.clone().unwrap(),
201                    action_type: DWCActionType::GetMetaData,
202                    play_audio_url: None,
203                    guild_id: self.guild_id.clone(),
204                    request_id: Some(nanoid!()),
205                    new_volume: None,
206                    seek_position: None,
207                    loop_times: None,
208                    worker_id: self.worker_id.read().await.clone().unwrap(),
209                    voice_channel_id: None,
210                }),
211                self.tx.clone(),
212                self.guild_id.clone(),
213            ))
214            .context(FailedToSendIPCRequestSnafu)?;
215
216        Ok(())
217    }
218}