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, 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    /// Emits the given signal.
611    #[inline]
612    pub async fn emit(&self, signal: Signal) -> Result<()> {
613        self.inner.emit(signal).await
614    }
615
616    /// Emits the `PropertiesChanged` signal for the given properties.
617    ///
618    /// This categorizes the property in the `changed` or `invalidated`
619    /// properties as defined by the spec.
620    ///
621    /// [`LocalServer::track_list_properties_changed`] or
622    /// [`LocalServer::playlists_properties_changed`] are used
623    /// to emit `PropertiesChanged` for the `TrackList` or `Playlists`
624    /// interfaces respectively.
625    #[inline]
626    pub async fn properties_changed(
627        &self,
628        properties: impl IntoIterator<Item = Property>,
629    ) -> Result<()> {
630        self.inner.properties_changed(properties).await
631    }
632
633    async fn handle_root_action(imp: &T, action: RootAction) {
634        match action {
635            // Methods
636            RootAction::Raise(sender) => {
637                let ret = imp.raise().await;
638                sender.send(ret).unwrap();
639            }
640            RootAction::Quit(sender) => {
641                let ret = imp.quit().await;
642                sender.send(ret).unwrap();
643            }
644            // Properties
645            RootAction::CanQuit(sender) => {
646                let ret = imp.can_quit().await;
647                sender.send(ret).unwrap();
648            }
649            RootAction::Fullscreen(sender) => {
650                let ret = imp.fullscreen().await;
651                sender.send(ret).unwrap();
652            }
653            RootAction::SetFullscreen(fullscreen, sender) => {
654                let ret = imp.set_fullscreen(fullscreen).await;
655                sender.send(ret).unwrap();
656            }
657            RootAction::CanSetFullScreen(sender) => {
658                let ret = imp.can_set_fullscreen().await;
659                sender.send(ret).unwrap();
660            }
661            RootAction::CanRaise(sender) => {
662                let ret = imp.can_raise().await;
663                sender.send(ret).unwrap();
664            }
665            RootAction::HasTrackList(sender) => {
666                let ret = imp.has_track_list().await;
667                sender.send(ret).unwrap();
668            }
669            RootAction::Identity(sender) => {
670                let ret = imp.identity().await;
671                sender.send(ret).unwrap();
672            }
673            RootAction::DesktopEntry(sender) => {
674                let ret = imp.desktop_entry().await;
675                sender.send(ret).unwrap();
676            }
677            RootAction::SupportedUriSchemes(sender) => {
678                let ret = imp.supported_uri_schemes().await;
679                sender.send(ret).unwrap();
680            }
681            RootAction::SupportedMimeTypes(sender) => {
682                let ret = imp.supported_mime_types().await;
683                sender.send(ret).unwrap();
684            }
685        }
686    }
687
688    async fn handle_player_action(imp: &T, action: PlayerAction) {
689        match action {
690            // Methods
691            PlayerAction::Next(sender) => {
692                let ret = imp.next().await;
693                sender.send(ret).unwrap();
694            }
695            PlayerAction::Previous(sender) => {
696                let ret = imp.previous().await;
697                sender.send(ret).unwrap();
698            }
699            PlayerAction::Pause(sender) => {
700                let ret = imp.pause().await;
701                sender.send(ret).unwrap();
702            }
703            PlayerAction::PlayPause(sender) => {
704                let ret = imp.play_pause().await;
705                sender.send(ret).unwrap();
706            }
707            PlayerAction::Stop(sender) => {
708                let ret = imp.stop().await;
709                sender.send(ret).unwrap();
710            }
711            PlayerAction::Play(sender) => {
712                let ret = imp.play().await;
713                sender.send(ret).unwrap();
714            }
715            PlayerAction::Seek(offset, sender) => {
716                let ret = imp.seek(offset).await;
717                sender.send(ret).unwrap();
718            }
719            PlayerAction::SetPosition(track_id, position, sender) => {
720                let ret = imp.set_position(track_id, position).await;
721                sender.send(ret).unwrap();
722            }
723            PlayerAction::OpenUri(uri, sender) => {
724                let ret = imp.open_uri(uri).await;
725                sender.send(ret).unwrap();
726            }
727            // Properties
728            PlayerAction::PlaybackStatus(sender) => {
729                let ret = imp.playback_status().await;
730                sender.send(ret).unwrap();
731            }
732            PlayerAction::LoopStatus(sender) => {
733                let ret = imp.loop_status().await;
734                sender.send(ret).unwrap();
735            }
736            PlayerAction::SetLoopStatus(loop_status, sender) => {
737                let ret = imp.set_loop_status(loop_status).await;
738                sender.send(ret).unwrap();
739            }
740            PlayerAction::Rate(sender) => {
741                let ret = imp.rate().await;
742                sender.send(ret).unwrap();
743            }
744            PlayerAction::SetRate(rate, sender) => {
745                let ret = imp.set_rate(rate).await;
746                sender.send(ret).unwrap();
747            }
748            PlayerAction::Shuffle(sender) => {
749                let ret = imp.shuffle().await;
750                sender.send(ret).unwrap();
751            }
752            PlayerAction::SetShuffle(shuffle, sender) => {
753                let ret = imp.set_shuffle(shuffle).await;
754                sender.send(ret).unwrap();
755            }
756            PlayerAction::Metadata(sender) => {
757                let ret = imp.metadata().await;
758                sender.send(ret).unwrap();
759            }
760            PlayerAction::Volume(sender) => {
761                let ret = imp.volume().await;
762                sender.send(ret).unwrap();
763            }
764            PlayerAction::SetVolume(volume, sender) => {
765                let ret = imp.set_volume(volume).await;
766                sender.send(ret).unwrap();
767            }
768            PlayerAction::Position(sender) => {
769                let ret = imp.position().await;
770                sender.send(ret).unwrap();
771            }
772            PlayerAction::MinimumRate(sender) => {
773                let ret = imp.minimum_rate().await;
774                sender.send(ret).unwrap();
775            }
776            PlayerAction::MaximumRate(sender) => {
777                let ret = imp.maximum_rate().await;
778                sender.send(ret).unwrap();
779            }
780            PlayerAction::CanGoNext(sender) => {
781                let ret = imp.can_go_next().await;
782                sender.send(ret).unwrap();
783            }
784            PlayerAction::CanGoPrevious(sender) => {
785                let ret = imp.can_go_previous().await;
786                sender.send(ret).unwrap();
787            }
788            PlayerAction::CanPlay(sender) => {
789                let ret = imp.can_play().await;
790                sender.send(ret).unwrap();
791            }
792            PlayerAction::CanPause(sender) => {
793                let ret = imp.can_pause().await;
794                sender.send(ret).unwrap();
795            }
796            PlayerAction::CanSeek(sender) => {
797                let ret = imp.can_seek().await;
798                sender.send(ret).unwrap();
799            }
800            PlayerAction::CanControl(sender) => {
801                let ret = imp.can_control().await;
802                sender.send(ret).unwrap();
803            }
804        }
805    }
806
807    async fn new_inner<'a, SR, RR>(
808        bus_name_suffix: &'a str,
809        imp: T,
810        server_func: impl FnOnce(&'a str, InnerImp<T>) -> SR + 'static,
811        runner_func: impl FnOnce(Receiver<Action>, Rc<T>) -> RR + 'static,
812    ) -> Result<Self>
813    where
814        SR: Future<Output = Result<Server<InnerImp<T>>>>,
815        RR: Future<Output = ()> + 'static,
816    {
817        let (tx, rx) = async_channel::bounded(1);
818
819        let inner = server_func(
820            bus_name_suffix,
821            InnerImp {
822                tx,
823                imp_ty: PhantomData,
824            },
825        )
826        .await?;
827
828        let imp = Rc::new(imp);
829        let runner = Box::pin(runner_func(rx, Rc::clone(&imp)));
830
831        Ok(Self {
832            inner,
833            imp,
834            runner: RefCell::new(Some(runner)),
835        })
836    }
837}
838
839impl<T> LocalServer<T>
840where
841    T: LocalTrackListInterface + 'static,
842{
843    /// Creates a new [`LocalServer`] with the given bus name suffix and
844    /// implementation, which must implement [`TrackListInterface`] in addition
845    /// to [`LocalRootInterface`] and [`LocalPlayerInterface`].
846    ///
847    /// See also [`LocalServer::new`].
848    ///
849    /// [`LocalRootInterface`]: crate::LocalRootInterface
850    pub async fn new_with_track_list(bus_name_suffix: &str, imp: T) -> Result<Self> {
851        Self::new_inner(
852            bus_name_suffix,
853            imp,
854            Server::new_with_track_list,
855            |rx, imp| async move {
856                while let Ok(action) = rx.recv().await {
857                    match action {
858                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
859                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
860                        Action::TrackList(action) => {
861                            Self::handle_track_list_action(&imp, action).await
862                        }
863                        Action::Playlists(_) => unreachable!(),
864                    }
865                }
866            },
867        )
868        .await
869    }
870
871    /// Emits the given signal on the `TrackList` interface.
872    #[inline]
873    pub async fn track_list_emit(&self, signal: TrackListSignal) -> Result<()> {
874        self.inner.track_list_emit(signal).await
875    }
876
877    /// Emits the `PropertiesChanged` signal for the given properties.
878    ///
879    /// This categorizes the property in the `changed` or `invalidated`
880    /// properties as defined by the spec.
881    #[inline]
882    pub async fn track_list_properties_changed(
883        &self,
884        properties: impl IntoIterator<Item = TrackListProperty>,
885    ) -> Result<()> {
886        self.inner.track_list_properties_changed(properties).await
887    }
888
889    async fn handle_track_list_action(imp: &T, action: TrackListAction) {
890        match action {
891            // Methods
892            TrackListAction::GetTracksMetadata(track_ids, sender) => {
893                let ret = imp.get_tracks_metadata(track_ids).await;
894                sender.send(ret).unwrap();
895            }
896            TrackListAction::AddTrack(uri, after_track, set_as_current, sender) => {
897                let ret = imp.add_track(uri, after_track, set_as_current).await;
898                sender.send(ret).unwrap();
899            }
900            TrackListAction::RemoveTrack(track_id, sender) => {
901                let ret = imp.remove_track(track_id).await;
902                sender.send(ret).unwrap();
903            }
904            TrackListAction::GoTo(track_id, sender) => {
905                let ret = imp.go_to(track_id).await;
906                sender.send(ret).unwrap();
907            }
908            // Properties
909            TrackListAction::Tracks(sender) => {
910                let ret = imp.tracks().await;
911                sender.send(ret).unwrap();
912            }
913            TrackListAction::CanEditTracks(sender) => {
914                let ret = imp.can_edit_tracks().await;
915                sender.send(ret).unwrap();
916            }
917        }
918    }
919}
920
921impl<T> LocalServer<T>
922where
923    T: LocalPlaylistsInterface + 'static,
924{
925    /// Creates a new [`LocalServer`] with the given bus name suffix and
926    /// implementation, which must implement [`LocalPlaylistsInterface`] in
927    /// addition to [`LocalRootInterface`] and [`LocalPlayerInterface`].
928    ///
929    /// See also [`LocalServer::new`].
930    ///
931    /// [`LocalRootInterface`]: crate::LocalRootInterface
932    pub async fn new_with_playlists(bus_name_suffix: &str, imp: T) -> Result<Self> {
933        Self::new_inner(
934            bus_name_suffix,
935            imp,
936            Server::new_with_playlists,
937            |rx, imp| async move {
938                while let Ok(action) = rx.recv().await {
939                    match action {
940                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
941                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
942                        Action::Playlists(action) => {
943                            Self::handle_playlists_action(&imp, action).await
944                        }
945                        Action::TrackList(_) => unreachable!(),
946                    }
947                }
948            },
949        )
950        .await
951    }
952
953    /// Emits the given signal on the `Playlists` interface.
954    #[inline]
955    pub async fn playlists_emit(&self, signal: PlaylistsSignal) -> Result<()> {
956        self.inner.playlists_emit(signal).await
957    }
958
959    /// Emits the `PropertiesChanged` signal for the given properties.
960    ///
961    /// This categorizes the property in the `changed` or `invalidated`
962    /// properties as defined by the spec.
963    #[inline]
964    pub async fn playlists_properties_changed(
965        &self,
966        properties: impl IntoIterator<Item = PlaylistsProperty>,
967    ) -> Result<()> {
968        self.inner.playlists_properties_changed(properties).await
969    }
970
971    async fn handle_playlists_action(imp: &T, action: PlaylistsAction) {
972        match action {
973            PlaylistsAction::ActivatePlaylist(playlist_id, sender) => {
974                let ret = imp.activate_playlist(playlist_id).await;
975                sender.send(ret).unwrap();
976            }
977            PlaylistsAction::GetPlaylists(index, max_count, order, reverse_order, sender) => {
978                let ret = imp
979                    .get_playlists(index, max_count, order, reverse_order)
980                    .await;
981                sender.send(ret).unwrap();
982            }
983            PlaylistsAction::PlaylistCount(sender) => {
984                let ret = imp.playlist_count().await;
985                sender.send(ret).unwrap();
986            }
987            PlaylistsAction::Orderings(sender) => {
988                let ret = imp.orderings().await;
989                sender.send(ret).unwrap();
990            }
991            PlaylistsAction::ActivePlaylist(sender) => {
992                let ret = imp.active_playlist().await;
993                sender.send(ret).unwrap();
994            }
995        }
996    }
997}
998
999impl<T> LocalServer<T>
1000where
1001    T: LocalTrackListInterface + LocalPlaylistsInterface + 'static,
1002{
1003    /// Creates a new [`LocalServer`] with the given bus name suffix and
1004    /// implementation, which must implement [`LocalTrackListInterface`] and
1005    /// [`LocalPlaylistsInterface`] in addition to [`LocalRootInterface`] and
1006    /// [`LocalPlayerInterface`].
1007    ///
1008    /// See also [`LocalServer::new`].
1009    ///
1010    /// [`LocalRootInterface`]: crate::LocalRootInterface
1011    pub async fn new_with_all(bus_name_suffix: &str, imp: T) -> Result<Self> {
1012        Self::new_inner(
1013            bus_name_suffix,
1014            imp,
1015            Server::new_with_all,
1016            |rx, imp| async move {
1017                while let Ok(action) = rx.recv().await {
1018                    match action {
1019                        Action::Root(action) => Self::handle_root_action(&imp, action).await,
1020                        Action::Player(action) => Self::handle_player_action(&imp, action).await,
1021                        Action::Playlists(action) => {
1022                            Self::handle_playlists_action(&imp, action).await
1023                        }
1024                        Action::TrackList(action) => {
1025                            Self::handle_track_list_action(&imp, action).await
1026                        }
1027                    }
1028                }
1029            },
1030        )
1031        .await
1032    }
1033}
1034
1035#[cfg(test)]
1036mod tests {
1037    use static_assertions::{assert_impl_all, assert_not_impl_any};
1038
1039    use super::LocalServer;
1040
1041    #[allow(dead_code)]
1042    pub struct TestPlayer;
1043
1044    assert_not_impl_any!(LocalServer<TestPlayer>: Send, Sync);
1045    assert_impl_all!(LocalServer<TestPlayer>: Unpin);
1046}