mpris_server/
local_server.rs

1use std::{
2    cell::RefCell,
3    fmt,
4    future::Future,
5    marker::PhantomData,
6    pin::Pin,
7    rc::Rc,
8    task::{Context, Poll},
9};
10
11use async_channel::{Receiver, Sender};
12use futures_channel::oneshot;
13use zbus::{fdo, names::WellKnownName, Result};
14
15use crate::{
16    LocalPlayerInterface, LocalPlaylistsInterface, LocalTrackListInterface, LoopStatus, Metadata,
17    PlaybackRate, PlaybackStatus, PlayerInterface, Playlist, PlaylistId, PlaylistOrdering,
18    PlaylistsInterface, PlaylistsProperty, PlaylistsSignal, Property, RootInterface, Server,
19    Signal, Time, TrackId, TrackListInterface, TrackListProperty, TrackListSignal, Uri, Volume,
20};
21
22enum RootAction {
23    //  Methods
24    Raise(oneshot::Sender<fdo::Result<()>>),
25    Quit(oneshot::Sender<fdo::Result<()>>),
26
27    // `org.mpris.MediaPlayer2` Properties
28    CanQuit(oneshot::Sender<fdo::Result<bool>>),
29    Fullscreen(oneshot::Sender<fdo::Result<bool>>),
30    SetFullscreen(bool, oneshot::Sender<Result<()>>),
31    CanSetFullScreen(oneshot::Sender<fdo::Result<bool>>),
32    CanRaise(oneshot::Sender<fdo::Result<bool>>),
33    HasTrackList(oneshot::Sender<fdo::Result<bool>>),
34    Identity(oneshot::Sender<fdo::Result<String>>),
35    DesktopEntry(oneshot::Sender<fdo::Result<String>>),
36    SupportedUriSchemes(oneshot::Sender<fdo::Result<Vec<String>>>),
37    SupportedMimeTypes(oneshot::Sender<fdo::Result<Vec<String>>>),
38}
39
40enum PlayerAction {
41    // Methods
42    Next(oneshot::Sender<fdo::Result<()>>),
43    Previous(oneshot::Sender<fdo::Result<()>>),
44    Pause(oneshot::Sender<fdo::Result<()>>),
45    PlayPause(oneshot::Sender<fdo::Result<()>>),
46    Stop(oneshot::Sender<fdo::Result<()>>),
47    Play(oneshot::Sender<fdo::Result<()>>),
48    Seek(Time, oneshot::Sender<fdo::Result<()>>),
49    SetPosition(TrackId, Time, oneshot::Sender<fdo::Result<()>>),
50    OpenUri(String, oneshot::Sender<fdo::Result<()>>),
51
52    // Properties
53    PlaybackStatus(oneshot::Sender<fdo::Result<PlaybackStatus>>),
54    LoopStatus(oneshot::Sender<fdo::Result<LoopStatus>>),
55    SetLoopStatus(LoopStatus, oneshot::Sender<Result<()>>),
56    Rate(oneshot::Sender<fdo::Result<PlaybackRate>>),
57    SetRate(PlaybackRate, oneshot::Sender<Result<()>>),
58    Shuffle(oneshot::Sender<fdo::Result<bool>>),
59    SetShuffle(bool, oneshot::Sender<Result<()>>),
60    Metadata(oneshot::Sender<fdo::Result<Metadata>>),
61    Volume(oneshot::Sender<fdo::Result<Volume>>),
62    SetVolume(Volume, oneshot::Sender<Result<()>>),
63    Position(oneshot::Sender<fdo::Result<Time>>),
64    MinimumRate(oneshot::Sender<fdo::Result<PlaybackRate>>),
65    MaximumRate(oneshot::Sender<fdo::Result<PlaybackRate>>),
66    CanGoNext(oneshot::Sender<fdo::Result<bool>>),
67    CanGoPrevious(oneshot::Sender<fdo::Result<bool>>),
68    CanPlay(oneshot::Sender<fdo::Result<bool>>),
69    CanPause(oneshot::Sender<fdo::Result<bool>>),
70    CanSeek(oneshot::Sender<fdo::Result<bool>>),
71    CanControl(oneshot::Sender<fdo::Result<bool>>),
72}
73
74enum TrackListAction {
75    // Methods
76    GetTracksMetadata(Vec<TrackId>, oneshot::Sender<fdo::Result<Vec<Metadata>>>),
77    AddTrack(Uri, TrackId, bool, oneshot::Sender<fdo::Result<()>>),
78    RemoveTrack(TrackId, oneshot::Sender<fdo::Result<()>>),
79    GoTo(TrackId, oneshot::Sender<fdo::Result<()>>),
80
81    // Properties
82    Tracks(oneshot::Sender<fdo::Result<Vec<TrackId>>>),
83    CanEditTracks(oneshot::Sender<fdo::Result<bool>>),
84}
85
86enum PlaylistsAction {
87    // Methods
88    ActivatePlaylist(PlaylistId, oneshot::Sender<fdo::Result<()>>),
89    GetPlaylists(
90        u32,
91        u32,
92        PlaylistOrdering,
93        bool,
94        oneshot::Sender<fdo::Result<Vec<Playlist>>>,
95    ),
96
97    // Properties
98    PlaylistCount(oneshot::Sender<fdo::Result<u32>>),
99    Orderings(oneshot::Sender<fdo::Result<Vec<PlaylistOrdering>>>),
100    ActivePlaylist(oneshot::Sender<fdo::Result<Option<Playlist>>>),
101}
102
103enum Action {
104    Root(RootAction),
105    Player(PlayerAction),
106    TrackList(TrackListAction),
107    Playlists(PlaylistsAction),
108}
109
110struct InnerImp<T> {
111    tx: Sender<Action>,
112
113    // If we use `PhantomData<T>` and `T` is not `Send` and `Sync`, we get a compile error
114    // when using `InnerImp` in the inner non-local `Server` as it requires `T` to be `Send`
115    // and `Sync`, which defeats the purpose of `LocalServer`. So, we need to use `fn() -> T`
116    // in `PhantomData` to preserve the type information without requiring `T` to be `Send`
117    // and `Sync` for `InnerImp` to be `Send` and `Sync`.
118    imp_ty: PhantomData<fn() -> T>,
119}
120
121impl<T> InnerImp<T> {
122    async fn send_root(&self, action: RootAction) {
123        self.tx.send(Action::Root(action)).await.unwrap();
124    }
125
126    async fn send_player(&self, action: PlayerAction) {
127        self.tx.send(Action::Player(action)).await.unwrap();
128    }
129
130    async fn send_track_list(&self, action: TrackListAction) {
131        self.tx.send(Action::TrackList(action)).await.unwrap();
132    }
133
134    async fn send_playlists(&self, action: PlaylistsAction) {
135        self.tx.send(Action::Playlists(action)).await.unwrap();
136    }
137}
138
139impl<T> RootInterface for InnerImp<T> {
140    async fn raise(&self) -> fdo::Result<()> {
141        let (tx, rx) = oneshot::channel();
142        self.send_root(RootAction::Raise(tx)).await;
143        rx.await.unwrap()
144    }
145
146    async fn quit(&self) -> fdo::Result<()> {
147        let (tx, rx) = oneshot::channel();
148        self.send_root(RootAction::Quit(tx)).await;
149        rx.await.unwrap()
150    }
151
152    async fn can_quit(&self) -> fdo::Result<bool> {
153        let (tx, rx) = oneshot::channel();
154        self.send_root(RootAction::CanQuit(tx)).await;
155        rx.await.unwrap()
156    }
157
158    async fn fullscreen(&self) -> fdo::Result<bool> {
159        let (tx, rx) = oneshot::channel();
160        self.send_root(RootAction::Fullscreen(tx)).await;
161        rx.await.unwrap()
162    }
163
164    async fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
165        let (tx, rx) = oneshot::channel();
166        self.send_root(RootAction::SetFullscreen(fullscreen, tx))
167            .await;
168        rx.await.unwrap()
169    }
170
171    async fn can_set_fullscreen(&self) -> fdo::Result<bool> {
172        let (tx, rx) = oneshot::channel();
173        self.send_root(RootAction::CanSetFullScreen(tx)).await;
174        rx.await.unwrap()
175    }
176
177    async fn can_raise(&self) -> fdo::Result<bool> {
178        let (tx, rx) = oneshot::channel();
179        self.send_root(RootAction::CanRaise(tx)).await;
180        rx.await.unwrap()
181    }
182
183    async fn has_track_list(&self) -> fdo::Result<bool> {
184        let (tx, rx) = oneshot::channel();
185        self.send_root(RootAction::HasTrackList(tx)).await;
186        rx.await.unwrap()
187    }
188
189    async fn identity(&self) -> fdo::Result<String> {
190        let (tx, rx) = oneshot::channel();
191        self.send_root(RootAction::Identity(tx)).await;
192        rx.await.unwrap()
193    }
194
195    async fn desktop_entry(&self) -> fdo::Result<String> {
196        let (tx, rx) = oneshot::channel();
197        self.send_root(RootAction::DesktopEntry(tx)).await;
198        rx.await.unwrap()
199    }
200
201    async fn supported_uri_schemes(&self) -> fdo::Result<Vec<String>> {
202        let (tx, rx) = oneshot::channel();
203        self.send_root(RootAction::SupportedUriSchemes(tx)).await;
204        rx.await.unwrap()
205    }
206
207    async fn supported_mime_types(&self) -> fdo::Result<Vec<String>> {
208        let (tx, rx) = oneshot::channel();
209        self.send_root(RootAction::SupportedMimeTypes(tx)).await;
210        rx.await.unwrap()
211    }
212}
213
214impl<T> PlayerInterface for InnerImp<T> {
215    async fn next(&self) -> fdo::Result<()> {
216        let (tx, rx) = oneshot::channel();
217        self.send_player(PlayerAction::Next(tx)).await;
218        rx.await.unwrap()
219    }
220
221    async fn previous(&self) -> fdo::Result<()> {
222        let (tx, rx) = oneshot::channel();
223        self.send_player(PlayerAction::Previous(tx)).await;
224        rx.await.unwrap()
225    }
226
227    async fn pause(&self) -> fdo::Result<()> {
228        let (tx, rx) = oneshot::channel();
229        self.send_player(PlayerAction::Pause(tx)).await;
230        rx.await.unwrap()
231    }
232
233    async fn play_pause(&self) -> fdo::Result<()> {
234        let (tx, rx) = oneshot::channel();
235        self.send_player(PlayerAction::PlayPause(tx)).await;
236        rx.await.unwrap()
237    }
238
239    async fn stop(&self) -> fdo::Result<()> {
240        let (tx, rx) = oneshot::channel();
241        self.send_player(PlayerAction::Stop(tx)).await;
242        rx.await.unwrap()
243    }
244
245    async fn play(&self) -> fdo::Result<()> {
246        let (tx, rx) = oneshot::channel();
247        self.send_player(PlayerAction::Play(tx)).await;
248        rx.await.unwrap()
249    }
250
251    async fn seek(&self, offset: Time) -> fdo::Result<()> {
252        let (tx, rx) = oneshot::channel();
253        self.send_player(PlayerAction::Seek(offset, tx)).await;
254        rx.await.unwrap()
255    }
256
257    async fn set_position(&self, track_id: TrackId, position: Time) -> fdo::Result<()> {
258        let (tx, rx) = oneshot::channel();
259        self.send_player(PlayerAction::SetPosition(track_id, position, tx))
260            .await;
261        rx.await.unwrap()
262    }
263
264    async fn open_uri(&self, uri: String) -> fdo::Result<()> {
265        let (tx, rx) = oneshot::channel();
266        self.send_player(PlayerAction::OpenUri(uri, tx)).await;
267        rx.await.unwrap()
268    }
269
270    async fn playback_status(&self) -> fdo::Result<PlaybackStatus> {
271        let (tx, rx) = oneshot::channel();
272        self.send_player(PlayerAction::PlaybackStatus(tx)).await;
273        rx.await.unwrap()
274    }
275
276    async fn loop_status(&self) -> fdo::Result<LoopStatus> {
277        let (tx, rx) = oneshot::channel();
278        self.send_player(PlayerAction::LoopStatus(tx)).await;
279        rx.await.unwrap()
280    }
281
282    async fn set_loop_status(&self, loop_status: LoopStatus) -> Result<()> {
283        let (tx, rx) = oneshot::channel();
284        self.send_player(PlayerAction::SetLoopStatus(loop_status, tx))
285            .await;
286        rx.await.unwrap()
287    }
288
289    async fn rate(&self) -> fdo::Result<PlaybackRate> {
290        let (tx, rx) = oneshot::channel();
291        self.send_player(PlayerAction::Rate(tx)).await;
292        rx.await.unwrap()
293    }
294
295    async fn set_rate(&self, rate: PlaybackRate) -> Result<()> {
296        let (tx, rx) = oneshot::channel();
297        self.send_player(PlayerAction::SetRate(rate, tx)).await;
298        rx.await.unwrap()
299    }
300
301    async fn shuffle(&self) -> fdo::Result<bool> {
302        let (tx, rx) = oneshot::channel();
303        self.send_player(PlayerAction::Shuffle(tx)).await;
304        rx.await.unwrap()
305    }
306
307    async fn set_shuffle(&self, shuffle: bool) -> Result<()> {
308        let (tx, rx) = oneshot::channel();
309        self.send_player(PlayerAction::SetShuffle(shuffle, tx))
310            .await;
311        rx.await.unwrap()
312    }
313
314    async fn metadata(&self) -> fdo::Result<Metadata> {
315        let (tx, rx) = oneshot::channel();
316        self.send_player(PlayerAction::Metadata(tx)).await;
317        rx.await.unwrap()
318    }
319
320    async fn volume(&self) -> fdo::Result<Volume> {
321        let (tx, rx) = oneshot::channel();
322        self.send_player(PlayerAction::Volume(tx)).await;
323        rx.await.unwrap()
324    }
325
326    async fn set_volume(&self, volume: Volume) -> Result<()> {
327        let (tx, rx) = oneshot::channel();
328        self.send_player(PlayerAction::SetVolume(volume, tx)).await;
329        rx.await.unwrap()
330    }
331
332    async fn position(&self) -> fdo::Result<Time> {
333        let (tx, rx) = oneshot::channel();
334        self.send_player(PlayerAction::Position(tx)).await;
335        rx.await.unwrap()
336    }
337
338    async fn minimum_rate(&self) -> fdo::Result<PlaybackRate> {
339        let (tx, rx) = oneshot::channel();
340        self.send_player(PlayerAction::MinimumRate(tx)).await;
341        rx.await.unwrap()
342    }
343
344    async fn maximum_rate(&self) -> fdo::Result<PlaybackRate> {
345        let (tx, rx) = oneshot::channel();
346        self.send_player(PlayerAction::MaximumRate(tx)).await;
347        rx.await.unwrap()
348    }
349
350    async fn can_go_next(&self) -> fdo::Result<bool> {
351        let (tx, rx) = oneshot::channel();
352        self.send_player(PlayerAction::CanGoNext(tx)).await;
353        rx.await.unwrap()
354    }
355
356    async fn can_go_previous(&self) -> fdo::Result<bool> {
357        let (tx, rx) = oneshot::channel();
358        self.send_player(PlayerAction::CanGoPrevious(tx)).await;
359        rx.await.unwrap()
360    }
361
362    async fn can_play(&self) -> fdo::Result<bool> {
363        let (tx, rx) = oneshot::channel();
364        self.send_player(PlayerAction::CanPlay(tx)).await;
365        rx.await.unwrap()
366    }
367
368    async fn can_pause(&self) -> fdo::Result<bool> {
369        let (tx, rx) = oneshot::channel();
370        self.send_player(PlayerAction::CanPause(tx)).await;
371        rx.await.unwrap()
372    }
373
374    async fn can_seek(&self) -> fdo::Result<bool> {
375        let (tx, rx) = oneshot::channel();
376        self.send_player(PlayerAction::CanSeek(tx)).await;
377        rx.await.unwrap()
378    }
379
380    async fn can_control(&self) -> fdo::Result<bool> {
381        let (tx, rx) = oneshot::channel();
382        self.send_player(PlayerAction::CanControl(tx)).await;
383        rx.await.unwrap()
384    }
385}
386
387impl<T> TrackListInterface for InnerImp<T>
388where
389    T: LocalTrackListInterface,
390{
391    async fn get_tracks_metadata(&self, track_ids: Vec<TrackId>) -> fdo::Result<Vec<Metadata>> {
392        let (tx, rx) = oneshot::channel();
393        self.send_track_list(TrackListAction::GetTracksMetadata(track_ids, tx))
394            .await;
395        rx.await.unwrap()
396    }
397
398    async fn add_track(
399        &self,
400        uri: Uri,
401        after_track: TrackId,
402        set_as_current: bool,
403    ) -> fdo::Result<()> {
404        let (tx, rx) = oneshot::channel();
405        self.send_track_list(TrackListAction::AddTrack(
406            uri,
407            after_track,
408            set_as_current,
409            tx,
410        ))
411        .await;
412        rx.await.unwrap()
413    }
414
415    async fn remove_track(&self, track_id: TrackId) -> fdo::Result<()> {
416        let (tx, rx) = oneshot::channel();
417        self.send_track_list(TrackListAction::RemoveTrack(track_id, tx))
418            .await;
419        rx.await.unwrap()
420    }
421
422    async fn go_to(&self, track_id: TrackId) -> fdo::Result<()> {
423        let (tx, rx) = oneshot::channel();
424        self.send_track_list(TrackListAction::GoTo(track_id, tx))
425            .await;
426        rx.await.unwrap()
427    }
428
429    async fn tracks(&self) -> fdo::Result<Vec<TrackId>> {
430        let (tx, rx) = oneshot::channel();
431        self.send_track_list(TrackListAction::Tracks(tx)).await;
432        rx.await.unwrap()
433    }
434
435    async fn can_edit_tracks(&self) -> fdo::Result<bool> {
436        let (tx, rx) = oneshot::channel();
437        self.send_track_list(TrackListAction::CanEditTracks(tx))
438            .await;
439        rx.await.unwrap()
440    }
441}
442
443impl<T> PlaylistsInterface for InnerImp<T>
444where
445    T: LocalPlaylistsInterface,
446{
447    async fn activate_playlist(&self, playlist_id: PlaylistId) -> fdo::Result<()> {
448        let (tx, rx) = oneshot::channel();
449        self.send_playlists(PlaylistsAction::ActivatePlaylist(playlist_id, tx))
450            .await;
451        rx.await.unwrap()
452    }
453
454    async fn get_playlists(
455        &self,
456        index: u32,
457        max_count: u32,
458        order: PlaylistOrdering,
459        reverse_order: bool,
460    ) -> fdo::Result<Vec<Playlist>> {
461        let (tx, rx) = oneshot::channel();
462        self.send_playlists(PlaylistsAction::GetPlaylists(
463            index,
464            max_count,
465            order,
466            reverse_order,
467            tx,
468        ))
469        .await;
470        rx.await.unwrap()
471    }
472
473    async fn playlist_count(&self) -> fdo::Result<u32> {
474        let (tx, rx) = oneshot::channel();
475        self.send_playlists(PlaylistsAction::PlaylistCount(tx))
476            .await;
477        rx.await.unwrap()
478    }
479
480    async fn orderings(&self) -> fdo::Result<Vec<PlaylistOrdering>> {
481        let (tx, rx) = oneshot::channel();
482        self.send_playlists(PlaylistsAction::Orderings(tx)).await;
483        rx.await.unwrap()
484    }
485
486    async fn active_playlist(&self) -> fdo::Result<Option<Playlist>> {
487        let (tx, rx) = oneshot::channel();
488        self.send_playlists(PlaylistsAction::ActivePlaylist(tx))
489            .await;
490        rx.await.unwrap()
491    }
492}
493
494type TaskInner = Pin<Box<dyn Future<Output = ()>>>;
495
496/// A task that runs [`LocalServer`]'s event handler until the server
497/// and this task is dropped.
498///
499/// This must be awaited as soon as possible after creating the server.
500///
501/// See [`LocalServer::run`] for more information.
502#[must_use = "futures do nothing unless you `.await` or poll them"]
503pub struct LocalServerRunTask {
504    inner: Option<TaskInner>,
505}
506
507impl fmt::Debug for LocalServerRunTask {
508    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509        f.debug_struct("LocalServerRunTask")
510            .field("has_inner", &self.inner.is_some())
511            .finish()
512    }
513}
514
515impl Future for LocalServerRunTask {
516    type Output = ();
517
518    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
519        match self.inner.as_mut() {
520            Some(inner) => Pin::new(inner).poll(cx),
521            None => Poll::Ready(()),
522        }
523    }
524}
525
526/// Local version of [`Server`] that doesn't require `T` to be `Send` and
527/// `Sync`.
528///
529/// If your type is already `Send` and `Sync`, consider using [`Server`] instead
530/// because [`LocalServer`] has an overhead of sending messages across threads.
531///
532/// For more information, see [`Server`] documentations.
533pub struct LocalServer<T> {
534    inner: Server<InnerImp<T>>,
535    imp: Rc<T>,
536    runner: RefCell<Option<TaskInner>>,
537}
538
539impl<T> fmt::Debug for LocalServer<T> {
540    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541        f.debug_struct("LocalServer").finish()
542    }
543}
544
545impl<T> LocalServer<T>
546where
547    T: LocalPlayerInterface + 'static,
548{
549    /// Creates a new [`LocalServer`] with the given bus name suffix and
550    /// implementation, `imp`, which must implement [`LocalRootInterface`] and
551    /// [`LocalPlayerInterface`].
552    ///
553    /// To start handling events, [`LocalServer::run`] must be called as soon
554    /// as possible.
555    ///
556    /// The resulting bus name will be
557    /// `org.mpris.MediaPlayer2.<bus_name_suffix>`, where
558    /// `<bus_name_suffix>`must be a unique identifier, such as one based on a
559    /// UNIX process id. For example, this could be:
560    ///
561    /// * `org.mpris.MediaPlayer2.vlc.instance7389`
562    ///
563    /// **Note:** According to the [D-Bus specification], the unique
564    /// identifier "must only contain  the ASCII characters
565    /// `[A-Z][a-z][0-9]_-`" and "must not begin with a digit".
566    ///
567    /// [`LocalRootInterface`]: crate::LocalRootInterface
568    /// [D-Bus specification]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus
569    pub async fn new(bus_name_suffix: &str, imp: T) -> Result<Self> {
570        Self::new_inner(bus_name_suffix, imp, Server::new, |rx, imp| async move {
571            while let Ok(action) = rx.recv().await {
572                match action {
573                    Action::Root(action) => Self::handle_root_action(&imp, action).await,
574                    Action::Player(action) => Self::handle_player_action(&imp, action).await,
575                    Action::TrackList(_) | Action::Playlists(_) => unreachable!(),
576                }
577            }
578        })
579        .await
580    }
581
582    /// Returns a task that run the server until the server and the task is
583    /// dropped.
584    ///
585    /// The task must be awaited as soon as possible after creating the server.
586    ///
587    /// The returned task is no-op if the server has been ran before.
588    pub fn run(&self) -> LocalServerRunTask {
589        LocalServerRunTask {
590            inner: self.runner.take(),
591        }
592    }
593
594    /// Returns a reference to the underlying implementation.
595    #[inline]
596    pub fn imp(&self) -> &T {
597        &self.imp
598    }
599
600    /// Returns a reference to the inner [`zbus::Connection`].
601    ///
602    /// If you needed to call this, consider filing an issue.
603    #[cfg(feature = "unstable")]
604    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
605    #[inline]
606    pub fn connection(&self) -> &zbus::Connection {
607        self.inner.connection()
608    }
609
610    /// Returns the bus name of the server.
611    #[inline]
612    pub fn bus_name(&self) -> &WellKnownName<'_> {
613        self.inner.bus_name()
614    }
615
616    /// Releases the bus name of the server.
617    ///
618    /// The bus name is automatically released when the server is dropped. But
619    /// if you want to release it manually, you can call this method.
620    ///
621    /// Unless an error is encountered, returns `Ok(true)` if name was
622    /// previously registered with the bus and it has now been successfully
623    /// deregistered, `Ok(false)` if name was not previously registered or
624    /// already deregistered.
625    #[inline]
626    pub async fn release_bus_name(&self) -> Result<bool> {
627        self.inner.release_bus_name().await
628    }
629
630    /// Emits the given signal.
631    #[inline]
632    pub async fn emit(&self, signal: Signal) -> Result<()> {
633        self.inner.emit(signal).await
634    }
635
636    /// Emits the `PropertiesChanged` signal for the given properties.
637    ///
638    /// This categorizes the property in the `changed` or `invalidated`
639    /// properties as defined by the spec.
640    ///
641    /// [`LocalServer::track_list_properties_changed`] or
642    /// [`LocalServer::playlists_properties_changed`] are used
643    /// to emit `PropertiesChanged` for the `TrackList` or `Playlists`
644    /// interfaces respectively.
645    #[inline]
646    pub async fn properties_changed(
647        &self,
648        properties: impl IntoIterator<Item = Property>,
649    ) -> Result<()> {
650        self.inner.properties_changed(properties).await
651    }
652
653    async fn handle_root_action(imp: &T, action: RootAction) {
654        match action {
655            // Methods
656            RootAction::Raise(sender) => {
657                let ret = imp.raise().await;
658                sender.send(ret).unwrap();
659            }
660            RootAction::Quit(sender) => {
661                let ret = imp.quit().await;
662                sender.send(ret).unwrap();
663            }
664            // Properties
665            RootAction::CanQuit(sender) => {
666                let ret = imp.can_quit().await;
667                sender.send(ret).unwrap();
668            }
669            RootAction::Fullscreen(sender) => {
670                let ret = imp.fullscreen().await;
671                sender.send(ret).unwrap();
672            }
673            RootAction::SetFullscreen(fullscreen, sender) => {
674                let ret = imp.set_fullscreen(fullscreen).await;
675                sender.send(ret).unwrap();
676            }
677            RootAction::CanSetFullScreen(sender) => {
678                let ret = imp.can_set_fullscreen().await;
679                sender.send(ret).unwrap();
680            }
681            RootAction::CanRaise(sender) => {
682                let ret = imp.can_raise().await;
683                sender.send(ret).unwrap();
684            }
685            RootAction::HasTrackList(sender) => {
686                let ret = imp.has_track_list().await;
687                sender.send(ret).unwrap();
688            }
689            RootAction::Identity(sender) => {
690                let ret = imp.identity().await;
691                sender.send(ret).unwrap();
692            }
693            RootAction::DesktopEntry(sender) => {
694                let ret = imp.desktop_entry().await;
695                sender.send(ret).unwrap();
696            }
697            RootAction::SupportedUriSchemes(sender) => {
698                let ret = imp.supported_uri_schemes().await;
699                sender.send(ret).unwrap();
700            }
701            RootAction::SupportedMimeTypes(sender) => {
702                let ret = imp.supported_mime_types().await;
703                sender.send(ret).unwrap();
704            }
705        }
706    }
707
708    async fn handle_player_action(imp: &T, action: PlayerAction) {
709        match action {
710            // Methods
711            PlayerAction::Next(sender) => {
712                let ret = imp.next().await;
713                sender.send(ret).unwrap();
714            }
715            PlayerAction::Previous(sender) => {
716                let ret = imp.previous().await;
717                sender.send(ret).unwrap();
718            }
719            PlayerAction::Pause(sender) => {
720                let ret = imp.pause().await;
721                sender.send(ret).unwrap();
722            }
723            PlayerAction::PlayPause(sender) => {
724                let ret = imp.play_pause().await;
725                sender.send(ret).unwrap();
726            }
727            PlayerAction::Stop(sender) => {
728                let ret = imp.stop().await;
729                sender.send(ret).unwrap();
730            }
731            PlayerAction::Play(sender) => {
732                let ret = imp.play().await;
733                sender.send(ret).unwrap();
734            }
735            PlayerAction::Seek(offset, sender) => {
736                let ret = imp.seek(offset).await;
737                sender.send(ret).unwrap();
738            }
739            PlayerAction::SetPosition(track_id, position, sender) => {
740                let ret = imp.set_position(track_id, position).await;
741                sender.send(ret).unwrap();
742            }
743            PlayerAction::OpenUri(uri, sender) => {
744                let ret = imp.open_uri(uri).await;
745                sender.send(ret).unwrap();
746            }
747            // Properties
748            PlayerAction::PlaybackStatus(sender) => {
749                let ret = imp.playback_status().await;
750                sender.send(ret).unwrap();
751            }
752            PlayerAction::LoopStatus(sender) => {
753                let ret = imp.loop_status().await;
754                sender.send(ret).unwrap();
755            }
756            PlayerAction::SetLoopStatus(loop_status, sender) => {
757                let ret = imp.set_loop_status(loop_status).await;
758                sender.send(ret).unwrap();
759            }
760            PlayerAction::Rate(sender) => {
761                let ret = imp.rate().await;
762                sender.send(ret).unwrap();
763            }
764            PlayerAction::SetRate(rate, sender) => {
765                let ret = imp.set_rate(rate).await;
766                sender.send(ret).unwrap();
767            }
768            PlayerAction::Shuffle(sender) => {
769                let ret = imp.shuffle().await;
770                sender.send(ret).unwrap();
771            }
772            PlayerAction::SetShuffle(shuffle, sender) => {
773                let ret = imp.set_shuffle(shuffle).await;
774                sender.send(ret).unwrap();
775            }
776            PlayerAction::Metadata(sender) => {
777                let ret = imp.metadata().await;
778                sender.send(ret).unwrap();
779            }
780            PlayerAction::Volume(sender) => {
781                let ret = imp.volume().await;
782                sender.send(ret).unwrap();
783            }
784            PlayerAction::SetVolume(volume, sender) => {
785                let ret = imp.set_volume(volume).await;
786                sender.send(ret).unwrap();
787            }
788            PlayerAction::Position(sender) => {
789                let ret = imp.position().await;
790                sender.send(ret).unwrap();
791            }
792            PlayerAction::MinimumRate(sender) => {
793                let ret = imp.minimum_rate().await;
794                sender.send(ret).unwrap();
795            }
796            PlayerAction::MaximumRate(sender) => {
797                let ret = imp.maximum_rate().await;
798                sender.send(ret).unwrap();
799            }
800            PlayerAction::CanGoNext(sender) => {
801                let ret = imp.can_go_next().await;
802                sender.send(ret).unwrap();
803            }
804            PlayerAction::CanGoPrevious(sender) => {
805                let ret = imp.can_go_previous().await;
806                sender.send(ret).unwrap();
807            }
808            PlayerAction::CanPlay(sender) => {
809                let ret = imp.can_play().await;
810                sender.send(ret).unwrap();
811            }
812            PlayerAction::CanPause(sender) => {
813                let ret = imp.can_pause().await;
814                sender.send(ret).unwrap();
815            }
816            PlayerAction::CanSeek(sender) => {
817                let ret = imp.can_seek().await;
818                sender.send(ret).unwrap();
819            }
820            PlayerAction::CanControl(sender) => {
821                let ret = imp.can_control().await;
822                sender.send(ret).unwrap();
823            }
824        }
825    }
826
827    async fn new_inner<'a, SR, RR>(
828        bus_name_suffix: &'a str,
829        imp: T,
830        server_func: impl FnOnce(&'a str, InnerImp<T>) -> SR + 'static,
831        runner_func: impl FnOnce(Receiver<Action>, Rc<T>) -> RR + 'static,
832    ) -> Result<Self>
833    where
834        SR: Future<Output = Result<Server<InnerImp<T>>>>,
835        RR: Future<Output = ()> + 'static,
836    {
837        let (tx, rx) = async_channel::bounded(1);
838
839        let inner = server_func(
840            bus_name_suffix,
841            InnerImp {
842                tx,
843                imp_ty: PhantomData,
844            },
845        )
846        .await?;
847
848        let imp = Rc::new(imp);
849        let runner = Box::pin(runner_func(rx, Rc::clone(&imp)));
850
851        Ok(Self {
852            inner,
853            imp,
854            runner: RefCell::new(Some(runner)),
855        })
856    }
857}
858
859impl<T> LocalServer<T>
860where
861    T: LocalTrackListInterface + 'static,
862{
863    /// Creates a new [`LocalServer`] with the given bus name suffix and
864    /// implementation, which must implement [`TrackListInterface`] in addition
865    /// to [`LocalRootInterface`] and [`LocalPlayerInterface`].
866    ///
867    /// See also [`LocalServer::new`].
868    ///
869    /// [`LocalRootInterface`]: crate::LocalRootInterface
870    pub async fn new_with_track_list(bus_name_suffix: &str, imp: T) -> Result<Self> {
871        Self::new_inner(
872            bus_name_suffix,
873            imp,
874            Server::new_with_track_list,
875            |rx, imp| async move {
876                while let Ok(action) = rx.recv().await {
877                    match action {
878                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
879                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
880                        Action::TrackList(action) => {
881                            Self::handle_track_list_action(&imp, action).await
882                        }
883                        Action::Playlists(_) => unreachable!(),
884                    }
885                }
886            },
887        )
888        .await
889    }
890
891    /// Emits the given signal on the `TrackList` interface.
892    #[inline]
893    pub async fn track_list_emit(&self, signal: TrackListSignal) -> Result<()> {
894        self.inner.track_list_emit(signal).await
895    }
896
897    /// Emits the `PropertiesChanged` signal for the given properties.
898    ///
899    /// This categorizes the property in the `changed` or `invalidated`
900    /// properties as defined by the spec.
901    #[inline]
902    pub async fn track_list_properties_changed(
903        &self,
904        properties: impl IntoIterator<Item = TrackListProperty>,
905    ) -> Result<()> {
906        self.inner.track_list_properties_changed(properties).await
907    }
908
909    async fn handle_track_list_action(imp: &T, action: TrackListAction) {
910        match action {
911            // Methods
912            TrackListAction::GetTracksMetadata(track_ids, sender) => {
913                let ret = imp.get_tracks_metadata(track_ids).await;
914                sender.send(ret).unwrap();
915            }
916            TrackListAction::AddTrack(uri, after_track, set_as_current, sender) => {
917                let ret = imp.add_track(uri, after_track, set_as_current).await;
918                sender.send(ret).unwrap();
919            }
920            TrackListAction::RemoveTrack(track_id, sender) => {
921                let ret = imp.remove_track(track_id).await;
922                sender.send(ret).unwrap();
923            }
924            TrackListAction::GoTo(track_id, sender) => {
925                let ret = imp.go_to(track_id).await;
926                sender.send(ret).unwrap();
927            }
928            // Properties
929            TrackListAction::Tracks(sender) => {
930                let ret = imp.tracks().await;
931                sender.send(ret).unwrap();
932            }
933            TrackListAction::CanEditTracks(sender) => {
934                let ret = imp.can_edit_tracks().await;
935                sender.send(ret).unwrap();
936            }
937        }
938    }
939}
940
941impl<T> LocalServer<T>
942where
943    T: LocalPlaylistsInterface + 'static,
944{
945    /// Creates a new [`LocalServer`] with the given bus name suffix and
946    /// implementation, which must implement [`LocalPlaylistsInterface`] in
947    /// addition to [`LocalRootInterface`] and [`LocalPlayerInterface`].
948    ///
949    /// See also [`LocalServer::new`].
950    ///
951    /// [`LocalRootInterface`]: crate::LocalRootInterface
952    pub async fn new_with_playlists(bus_name_suffix: &str, imp: T) -> Result<Self> {
953        Self::new_inner(
954            bus_name_suffix,
955            imp,
956            Server::new_with_playlists,
957            |rx, imp| async move {
958                while let Ok(action) = rx.recv().await {
959                    match action {
960                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
961                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
962                        Action::Playlists(action) => {
963                            Self::handle_playlists_action(&imp, action).await
964                        }
965                        Action::TrackList(_) => unreachable!(),
966                    }
967                }
968            },
969        )
970        .await
971    }
972
973    /// Emits the given signal on the `Playlists` interface.
974    #[inline]
975    pub async fn playlists_emit(&self, signal: PlaylistsSignal) -> Result<()> {
976        self.inner.playlists_emit(signal).await
977    }
978
979    /// Emits the `PropertiesChanged` signal for the given properties.
980    ///
981    /// This categorizes the property in the `changed` or `invalidated`
982    /// properties as defined by the spec.
983    #[inline]
984    pub async fn playlists_properties_changed(
985        &self,
986        properties: impl IntoIterator<Item = PlaylistsProperty>,
987    ) -> Result<()> {
988        self.inner.playlists_properties_changed(properties).await
989    }
990
991    async fn handle_playlists_action(imp: &T, action: PlaylistsAction) {
992        match action {
993            PlaylistsAction::ActivatePlaylist(playlist_id, sender) => {
994                let ret = imp.activate_playlist(playlist_id).await;
995                sender.send(ret).unwrap();
996            }
997            PlaylistsAction::GetPlaylists(index, max_count, order, reverse_order, sender) => {
998                let ret = imp
999                    .get_playlists(index, max_count, order, reverse_order)
1000                    .await;
1001                sender.send(ret).unwrap();
1002            }
1003            PlaylistsAction::PlaylistCount(sender) => {
1004                let ret = imp.playlist_count().await;
1005                sender.send(ret).unwrap();
1006            }
1007            PlaylistsAction::Orderings(sender) => {
1008                let ret = imp.orderings().await;
1009                sender.send(ret).unwrap();
1010            }
1011            PlaylistsAction::ActivePlaylist(sender) => {
1012                let ret = imp.active_playlist().await;
1013                sender.send(ret).unwrap();
1014            }
1015        }
1016    }
1017}
1018
1019impl<T> LocalServer<T>
1020where
1021    T: LocalTrackListInterface + LocalPlaylistsInterface + 'static,
1022{
1023    /// Creates a new [`LocalServer`] with the given bus name suffix and
1024    /// implementation, which must implement [`LocalTrackListInterface`] and
1025    /// [`LocalPlaylistsInterface`] in addition to [`LocalRootInterface`] and
1026    /// [`LocalPlayerInterface`].
1027    ///
1028    /// See also [`LocalServer::new`].
1029    ///
1030    /// [`LocalRootInterface`]: crate::LocalRootInterface
1031    pub async fn new_with_all(bus_name_suffix: &str, imp: T) -> Result<Self> {
1032        Self::new_inner(
1033            bus_name_suffix,
1034            imp,
1035            Server::new_with_all,
1036            |rx, imp| async move {
1037                while let Ok(action) = rx.recv().await {
1038                    match action {
1039                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
1040                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
1041                        Action::Playlists(action) => {
1042                            Self::handle_playlists_action(&imp, action).await
1043                        }
1044                        Action::TrackList(action) => {
1045                            Self::handle_track_list_action(&imp, action).await
1046                        }
1047                    }
1048                }
1049            },
1050        )
1051        .await
1052    }
1053}
1054
1055#[cfg(test)]
1056mod tests {
1057    use static_assertions::{assert_impl_all, assert_not_impl_any};
1058
1059    use super::LocalServer;
1060
1061    #[allow(dead_code)]
1062    pub struct TestPlayer;
1063
1064    assert_not_impl_any!(LocalServer<TestPlayer>: Send, Sync);
1065    assert_impl_all!(LocalServer<TestPlayer>: Unpin);
1066}