use std::{
cell::RefCell,
fmt,
future::Future,
marker::PhantomData,
pin::Pin,
rc::Rc,
task::{Context, Poll},
};
use async_channel::{Receiver, Sender};
use futures_channel::oneshot;
use zbus::{fdo, Connection, Result};
use crate::{
LocalPlayerInterface, LocalPlaylistsInterface, LocalTrackListInterface, LoopStatus, Metadata,
PlaybackRate, PlaybackStatus, PlayerInterface, Playlist, PlaylistId, PlaylistOrdering,
PlaylistsInterface, PlaylistsProperty, PlaylistsSignal, Property, RootInterface, Server,
Signal, Time, TrackId, TrackListInterface, TrackListProperty, TrackListSignal, Uri, Volume,
};
enum RootAction {
Raise(oneshot::Sender<fdo::Result<()>>),
Quit(oneshot::Sender<fdo::Result<()>>),
CanQuit(oneshot::Sender<fdo::Result<bool>>),
Fullscreen(oneshot::Sender<fdo::Result<bool>>),
SetFullscreen(bool, oneshot::Sender<Result<()>>),
CanSetFullScreen(oneshot::Sender<fdo::Result<bool>>),
CanRaise(oneshot::Sender<fdo::Result<bool>>),
HasTrackList(oneshot::Sender<fdo::Result<bool>>),
Identity(oneshot::Sender<fdo::Result<String>>),
DesktopEntry(oneshot::Sender<fdo::Result<String>>),
SupportedUriSchemes(oneshot::Sender<fdo::Result<Vec<String>>>),
SupportedMimeTypes(oneshot::Sender<fdo::Result<Vec<String>>>),
}
enum PlayerAction {
Next(oneshot::Sender<fdo::Result<()>>),
Previous(oneshot::Sender<fdo::Result<()>>),
Pause(oneshot::Sender<fdo::Result<()>>),
PlayPause(oneshot::Sender<fdo::Result<()>>),
Stop(oneshot::Sender<fdo::Result<()>>),
Play(oneshot::Sender<fdo::Result<()>>),
Seek(Time, oneshot::Sender<fdo::Result<()>>),
SetPosition(TrackId, Time, oneshot::Sender<fdo::Result<()>>),
OpenUri(String, oneshot::Sender<fdo::Result<()>>),
PlaybackStatus(oneshot::Sender<fdo::Result<PlaybackStatus>>),
LoopStatus(oneshot::Sender<fdo::Result<LoopStatus>>),
SetLoopStatus(LoopStatus, oneshot::Sender<Result<()>>),
Rate(oneshot::Sender<fdo::Result<PlaybackRate>>),
SetRate(PlaybackRate, oneshot::Sender<Result<()>>),
Shuffle(oneshot::Sender<fdo::Result<bool>>),
SetShuffle(bool, oneshot::Sender<Result<()>>),
Metadata(oneshot::Sender<fdo::Result<Metadata>>),
Volume(oneshot::Sender<fdo::Result<Volume>>),
SetVolume(Volume, oneshot::Sender<Result<()>>),
Position(oneshot::Sender<fdo::Result<Time>>),
MinimumRate(oneshot::Sender<fdo::Result<PlaybackRate>>),
MaximumRate(oneshot::Sender<fdo::Result<PlaybackRate>>),
CanGoNext(oneshot::Sender<fdo::Result<bool>>),
CanGoPrevious(oneshot::Sender<fdo::Result<bool>>),
CanPlay(oneshot::Sender<fdo::Result<bool>>),
CanPause(oneshot::Sender<fdo::Result<bool>>),
CanSeek(oneshot::Sender<fdo::Result<bool>>),
CanControl(oneshot::Sender<fdo::Result<bool>>),
}
enum TrackListAction {
GetTracksMetadata(Vec<TrackId>, oneshot::Sender<fdo::Result<Vec<Metadata>>>),
AddTrack(Uri, TrackId, bool, oneshot::Sender<fdo::Result<()>>),
RemoveTrack(TrackId, oneshot::Sender<fdo::Result<()>>),
GoTo(TrackId, oneshot::Sender<fdo::Result<()>>),
Tracks(oneshot::Sender<fdo::Result<Vec<TrackId>>>),
CanEditTracks(oneshot::Sender<fdo::Result<bool>>),
}
enum PlaylistsAction {
ActivatePlaylist(PlaylistId, oneshot::Sender<fdo::Result<()>>),
GetPlaylists(
u32,
u32,
PlaylistOrdering,
bool,
oneshot::Sender<fdo::Result<Vec<Playlist>>>,
),
PlaylistCount(oneshot::Sender<fdo::Result<u32>>),
Orderings(oneshot::Sender<fdo::Result<Vec<PlaylistOrdering>>>),
ActivePlaylist(oneshot::Sender<fdo::Result<Option<Playlist>>>),
}
enum Action {
Root(RootAction),
Player(PlayerAction),
TrackList(TrackListAction),
Playlists(PlaylistsAction),
}
struct InnerImp<T> {
tx: Sender<Action>,
imp_ty: PhantomData<fn() -> T>,
}
impl<T> InnerImp<T> {
async fn send_root(&self, action: RootAction) {
self.tx.send(Action::Root(action)).await.unwrap();
}
async fn send_player(&self, action: PlayerAction) {
self.tx.send(Action::Player(action)).await.unwrap();
}
async fn send_track_list(&self, action: TrackListAction) {
self.tx.send(Action::TrackList(action)).await.unwrap();
}
async fn send_playlists(&self, action: PlaylistsAction) {
self.tx.send(Action::Playlists(action)).await.unwrap();
}
}
impl<T> RootInterface for InnerImp<T> {
async fn raise(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::Raise(tx)).await;
rx.await.unwrap()
}
async fn quit(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::Quit(tx)).await;
rx.await.unwrap()
}
async fn can_quit(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::CanQuit(tx)).await;
rx.await.unwrap()
}
async fn fullscreen(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::Fullscreen(tx)).await;
rx.await.unwrap()
}
async fn set_fullscreen(&self, fullscreen: bool) -> Result<()> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::SetFullscreen(fullscreen, tx))
.await;
rx.await.unwrap()
}
async fn can_set_fullscreen(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::CanSetFullScreen(tx)).await;
rx.await.unwrap()
}
async fn can_raise(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::CanRaise(tx)).await;
rx.await.unwrap()
}
async fn has_track_list(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::HasTrackList(tx)).await;
rx.await.unwrap()
}
async fn identity(&self) -> fdo::Result<String> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::Identity(tx)).await;
rx.await.unwrap()
}
async fn desktop_entry(&self) -> fdo::Result<String> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::DesktopEntry(tx)).await;
rx.await.unwrap()
}
async fn supported_uri_schemes(&self) -> fdo::Result<Vec<String>> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::SupportedUriSchemes(tx)).await;
rx.await.unwrap()
}
async fn supported_mime_types(&self) -> fdo::Result<Vec<String>> {
let (tx, rx) = oneshot::channel();
self.send_root(RootAction::SupportedMimeTypes(tx)).await;
rx.await.unwrap()
}
}
impl<T> PlayerInterface for InnerImp<T> {
async fn next(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Next(tx)).await;
rx.await.unwrap()
}
async fn previous(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Previous(tx)).await;
rx.await.unwrap()
}
async fn pause(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Pause(tx)).await;
rx.await.unwrap()
}
async fn play_pause(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::PlayPause(tx)).await;
rx.await.unwrap()
}
async fn stop(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Stop(tx)).await;
rx.await.unwrap()
}
async fn play(&self) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Play(tx)).await;
rx.await.unwrap()
}
async fn seek(&self, offset: Time) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Seek(offset, tx)).await;
rx.await.unwrap()
}
async fn set_position(&self, track_id: TrackId, position: Time) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::SetPosition(track_id, position, tx))
.await;
rx.await.unwrap()
}
async fn open_uri(&self, uri: String) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::OpenUri(uri, tx)).await;
rx.await.unwrap()
}
async fn playback_status(&self) -> fdo::Result<PlaybackStatus> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::PlaybackStatus(tx)).await;
rx.await.unwrap()
}
async fn loop_status(&self) -> fdo::Result<LoopStatus> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::LoopStatus(tx)).await;
rx.await.unwrap()
}
async fn set_loop_status(&self, loop_status: LoopStatus) -> Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::SetLoopStatus(loop_status, tx))
.await;
rx.await.unwrap()
}
async fn rate(&self) -> fdo::Result<PlaybackRate> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Rate(tx)).await;
rx.await.unwrap()
}
async fn set_rate(&self, rate: PlaybackRate) -> Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::SetRate(rate, tx)).await;
rx.await.unwrap()
}
async fn shuffle(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Shuffle(tx)).await;
rx.await.unwrap()
}
async fn set_shuffle(&self, shuffle: bool) -> Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::SetShuffle(shuffle, tx))
.await;
rx.await.unwrap()
}
async fn metadata(&self) -> fdo::Result<Metadata> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Metadata(tx)).await;
rx.await.unwrap()
}
async fn volume(&self) -> fdo::Result<Volume> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Volume(tx)).await;
rx.await.unwrap()
}
async fn set_volume(&self, volume: Volume) -> Result<()> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::SetVolume(volume, tx)).await;
rx.await.unwrap()
}
async fn position(&self) -> fdo::Result<Time> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::Position(tx)).await;
rx.await.unwrap()
}
async fn minimum_rate(&self) -> fdo::Result<PlaybackRate> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::MinimumRate(tx)).await;
rx.await.unwrap()
}
async fn maximum_rate(&self) -> fdo::Result<PlaybackRate> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::MaximumRate(tx)).await;
rx.await.unwrap()
}
async fn can_go_next(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanGoNext(tx)).await;
rx.await.unwrap()
}
async fn can_go_previous(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanGoPrevious(tx)).await;
rx.await.unwrap()
}
async fn can_play(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanPlay(tx)).await;
rx.await.unwrap()
}
async fn can_pause(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanPause(tx)).await;
rx.await.unwrap()
}
async fn can_seek(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanSeek(tx)).await;
rx.await.unwrap()
}
async fn can_control(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_player(PlayerAction::CanControl(tx)).await;
rx.await.unwrap()
}
}
impl<T> TrackListInterface for InnerImp<T>
where
T: LocalTrackListInterface,
{
async fn get_tracks_metadata(&self, track_ids: Vec<TrackId>) -> fdo::Result<Vec<Metadata>> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::GetTracksMetadata(track_ids, tx))
.await;
rx.await.unwrap()
}
async fn add_track(
&self,
uri: Uri,
after_track: TrackId,
set_as_current: bool,
) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::AddTrack(
uri,
after_track,
set_as_current,
tx,
))
.await;
rx.await.unwrap()
}
async fn remove_track(&self, track_id: TrackId) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::RemoveTrack(track_id, tx))
.await;
rx.await.unwrap()
}
async fn go_to(&self, track_id: TrackId) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::GoTo(track_id, tx))
.await;
rx.await.unwrap()
}
async fn tracks(&self) -> fdo::Result<Vec<TrackId>> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::Tracks(tx)).await;
rx.await.unwrap()
}
async fn can_edit_tracks(&self) -> fdo::Result<bool> {
let (tx, rx) = oneshot::channel();
self.send_track_list(TrackListAction::CanEditTracks(tx))
.await;
rx.await.unwrap()
}
}
impl<T> PlaylistsInterface for InnerImp<T>
where
T: LocalPlaylistsInterface,
{
async fn activate_playlist(&self, playlist_id: PlaylistId) -> fdo::Result<()> {
let (tx, rx) = oneshot::channel();
self.send_playlists(PlaylistsAction::ActivatePlaylist(playlist_id, tx))
.await;
rx.await.unwrap()
}
async fn get_playlists(
&self,
index: u32,
max_count: u32,
order: PlaylistOrdering,
reverse_order: bool,
) -> fdo::Result<Vec<Playlist>> {
let (tx, rx) = oneshot::channel();
self.send_playlists(PlaylistsAction::GetPlaylists(
index,
max_count,
order,
reverse_order,
tx,
))
.await;
rx.await.unwrap()
}
async fn playlist_count(&self) -> fdo::Result<u32> {
let (tx, rx) = oneshot::channel();
self.send_playlists(PlaylistsAction::PlaylistCount(tx))
.await;
rx.await.unwrap()
}
async fn orderings(&self) -> fdo::Result<Vec<PlaylistOrdering>> {
let (tx, rx) = oneshot::channel();
self.send_playlists(PlaylistsAction::Orderings(tx)).await;
rx.await.unwrap()
}
async fn active_playlist(&self) -> fdo::Result<Option<Playlist>> {
let (tx, rx) = oneshot::channel();
self.send_playlists(PlaylistsAction::ActivePlaylist(tx))
.await;
rx.await.unwrap()
}
}
type TaskInner = Pin<Box<dyn Future<Output = ()>>>;
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct LocalServerRunTask {
inner: Option<TaskInner>,
}
impl fmt::Debug for LocalServerRunTask {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LocalServerRunTask")
.field("has_inner", &self.inner.is_some())
.finish()
}
}
impl Future for LocalServerRunTask {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.inner.as_mut() {
Some(inner) => Pin::new(inner).poll(cx),
None => Poll::Ready(()),
}
}
}
pub struct LocalServer<T> {
inner: Server<InnerImp<T>>,
imp: Rc<T>,
runner: RefCell<Option<TaskInner>>,
}
impl<T> fmt::Debug for LocalServer<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LocalServer").finish()
}
}
impl<T> LocalServer<T>
where
T: LocalPlayerInterface + 'static,
{
pub async fn new(bus_name_suffix: &str, imp: T) -> Result<Self> {
Self::new_inner(bus_name_suffix, imp, Server::new, |rx, imp| async move {
while let Ok(action) = rx.recv().await {
match action {
Action::Root(action) => Self::handle_root_action(&imp, action).await,
Action::Player(action) => Self::handle_player_action(&imp, action).await,
Action::TrackList(_) | Action::Playlists(_) => unreachable!(),
}
}
})
.await
}
pub fn run(&self) -> LocalServerRunTask {
LocalServerRunTask {
inner: self.runner.take(),
}
}
#[inline]
pub fn imp(&self) -> &T {
&self.imp
}
#[cfg(feature = "unstable")]
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
#[inline]
pub fn connection(&self) -> &Connection {
self.inner.connection()
}
#[inline]
pub async fn emit(&self, signal: Signal) -> Result<()> {
self.inner.emit(signal).await
}
#[inline]
pub async fn properties_changed(
&self,
properties: impl IntoIterator<Item = Property>,
) -> Result<()> {
self.inner.properties_changed(properties).await
}
async fn handle_root_action(imp: &T, action: RootAction) {
match action {
RootAction::Raise(sender) => {
let ret = imp.raise().await;
sender.send(ret).unwrap();
}
RootAction::Quit(sender) => {
let ret = imp.quit().await;
sender.send(ret).unwrap();
}
RootAction::CanQuit(sender) => {
let ret = imp.can_quit().await;
sender.send(ret).unwrap();
}
RootAction::Fullscreen(sender) => {
let ret = imp.fullscreen().await;
sender.send(ret).unwrap();
}
RootAction::SetFullscreen(fullscreen, sender) => {
let ret = imp.set_fullscreen(fullscreen).await;
sender.send(ret).unwrap();
}
RootAction::CanSetFullScreen(sender) => {
let ret = imp.can_set_fullscreen().await;
sender.send(ret).unwrap();
}
RootAction::CanRaise(sender) => {
let ret = imp.can_raise().await;
sender.send(ret).unwrap();
}
RootAction::HasTrackList(sender) => {
let ret = imp.has_track_list().await;
sender.send(ret).unwrap();
}
RootAction::Identity(sender) => {
let ret = imp.identity().await;
sender.send(ret).unwrap();
}
RootAction::DesktopEntry(sender) => {
let ret = imp.desktop_entry().await;
sender.send(ret).unwrap();
}
RootAction::SupportedUriSchemes(sender) => {
let ret = imp.supported_uri_schemes().await;
sender.send(ret).unwrap();
}
RootAction::SupportedMimeTypes(sender) => {
let ret = imp.supported_mime_types().await;
sender.send(ret).unwrap();
}
}
}
async fn handle_player_action(imp: &T, action: PlayerAction) {
match action {
PlayerAction::Next(sender) => {
let ret = imp.next().await;
sender.send(ret).unwrap();
}
PlayerAction::Previous(sender) => {
let ret = imp.previous().await;
sender.send(ret).unwrap();
}
PlayerAction::Pause(sender) => {
let ret = imp.pause().await;
sender.send(ret).unwrap();
}
PlayerAction::PlayPause(sender) => {
let ret = imp.play_pause().await;
sender.send(ret).unwrap();
}
PlayerAction::Stop(sender) => {
let ret = imp.stop().await;
sender.send(ret).unwrap();
}
PlayerAction::Play(sender) => {
let ret = imp.play().await;
sender.send(ret).unwrap();
}
PlayerAction::Seek(offset, sender) => {
let ret = imp.seek(offset).await;
sender.send(ret).unwrap();
}
PlayerAction::SetPosition(track_id, position, sender) => {
let ret = imp.set_position(track_id, position).await;
sender.send(ret).unwrap();
}
PlayerAction::OpenUri(uri, sender) => {
let ret = imp.open_uri(uri).await;
sender.send(ret).unwrap();
}
PlayerAction::PlaybackStatus(sender) => {
let ret = imp.playback_status().await;
sender.send(ret).unwrap();
}
PlayerAction::LoopStatus(sender) => {
let ret = imp.loop_status().await;
sender.send(ret).unwrap();
}
PlayerAction::SetLoopStatus(loop_status, sender) => {
let ret = imp.set_loop_status(loop_status).await;
sender.send(ret).unwrap();
}
PlayerAction::Rate(sender) => {
let ret = imp.rate().await;
sender.send(ret).unwrap();
}
PlayerAction::SetRate(rate, sender) => {
let ret = imp.set_rate(rate).await;
sender.send(ret).unwrap();
}
PlayerAction::Shuffle(sender) => {
let ret = imp.shuffle().await;
sender.send(ret).unwrap();
}
PlayerAction::SetShuffle(shuffle, sender) => {
let ret = imp.set_shuffle(shuffle).await;
sender.send(ret).unwrap();
}
PlayerAction::Metadata(sender) => {
let ret = imp.metadata().await;
sender.send(ret).unwrap();
}
PlayerAction::Volume(sender) => {
let ret = imp.volume().await;
sender.send(ret).unwrap();
}
PlayerAction::SetVolume(volume, sender) => {
let ret = imp.set_volume(volume).await;
sender.send(ret).unwrap();
}
PlayerAction::Position(sender) => {
let ret = imp.position().await;
sender.send(ret).unwrap();
}
PlayerAction::MinimumRate(sender) => {
let ret = imp.minimum_rate().await;
sender.send(ret).unwrap();
}
PlayerAction::MaximumRate(sender) => {
let ret = imp.maximum_rate().await;
sender.send(ret).unwrap();
}
PlayerAction::CanGoNext(sender) => {
let ret = imp.can_go_next().await;
sender.send(ret).unwrap();
}
PlayerAction::CanGoPrevious(sender) => {
let ret = imp.can_go_previous().await;
sender.send(ret).unwrap();
}
PlayerAction::CanPlay(sender) => {
let ret = imp.can_play().await;
sender.send(ret).unwrap();
}
PlayerAction::CanPause(sender) => {
let ret = imp.can_pause().await;
sender.send(ret).unwrap();
}
PlayerAction::CanSeek(sender) => {
let ret = imp.can_seek().await;
sender.send(ret).unwrap();
}
PlayerAction::CanControl(sender) => {
let ret = imp.can_control().await;
sender.send(ret).unwrap();
}
}
}
async fn new_inner<'a, SR, RR>(
bus_name_suffix: &'a str,
imp: T,
server_func: impl FnOnce(&'a str, InnerImp<T>) -> SR + 'static,
runner_func: impl FnOnce(Receiver<Action>, Rc<T>) -> RR + 'static,
) -> Result<Self>
where
SR: Future<Output = Result<Server<InnerImp<T>>>>,
RR: Future<Output = ()> + 'static,
{
let (tx, rx) = async_channel::bounded(1);
let inner = server_func(
bus_name_suffix,
InnerImp {
tx,
imp_ty: PhantomData,
},
)
.await?;
let imp = Rc::new(imp);
let runner = Box::pin(runner_func(rx, Rc::clone(&imp)));
Ok(Self {
inner,
imp,
runner: RefCell::new(Some(runner)),
})
}
}
impl<T> LocalServer<T>
where
T: LocalTrackListInterface + 'static,
{
pub async fn new_with_track_list(bus_name_suffix: &str, imp: T) -> Result<Self> {
Self::new_inner(
bus_name_suffix,
imp,
Server::new_with_track_list,
|rx, imp| async move {
while let Ok(action) = rx.recv().await {
match action {
Action::Root(action) => Self::handle_root_action(&imp, action).await,
Action::Player(action) => Self::handle_player_action(&imp, action).await,
Action::TrackList(action) => {
Self::handle_track_list_action(&imp, action).await
}
Action::Playlists(_) => unreachable!(),
}
}
},
)
.await
}
#[inline]
pub async fn track_list_emit(&self, signal: TrackListSignal) -> Result<()> {
self.inner.track_list_emit(signal).await
}
#[inline]
pub async fn track_list_properties_changed(
&self,
properties: impl IntoIterator<Item = TrackListProperty>,
) -> Result<()> {
self.inner.track_list_properties_changed(properties).await
}
async fn handle_track_list_action(imp: &T, action: TrackListAction) {
match action {
TrackListAction::GetTracksMetadata(track_ids, sender) => {
let ret = imp.get_tracks_metadata(track_ids).await;
sender.send(ret).unwrap();
}
TrackListAction::AddTrack(uri, after_track, set_as_current, sender) => {
let ret = imp.add_track(uri, after_track, set_as_current).await;
sender.send(ret).unwrap();
}
TrackListAction::RemoveTrack(track_id, sender) => {
let ret = imp.remove_track(track_id).await;
sender.send(ret).unwrap();
}
TrackListAction::GoTo(track_id, sender) => {
let ret = imp.go_to(track_id).await;
sender.send(ret).unwrap();
}
TrackListAction::Tracks(sender) => {
let ret = imp.tracks().await;
sender.send(ret).unwrap();
}
TrackListAction::CanEditTracks(sender) => {
let ret = imp.can_edit_tracks().await;
sender.send(ret).unwrap();
}
}
}
}
impl<T> LocalServer<T>
where
T: LocalPlaylistsInterface + 'static,
{
pub async fn new_with_playlists(bus_name_suffix: &str, imp: T) -> Result<Self> {
Self::new_inner(
bus_name_suffix,
imp,
Server::new_with_playlists,
|rx, imp| async move {
while let Ok(action) = rx.recv().await {
match action {
Action::Root(action) => Self::handle_root_action(&imp, action).await,
Action::Player(action) => Self::handle_player_action(&imp, action).await,
Action::Playlists(action) => {
Self::handle_playlists_action(&imp, action).await
}
Action::TrackList(_) => unreachable!(),
}
}
},
)
.await
}
#[inline]
pub async fn playlists_emit(&self, signal: PlaylistsSignal) -> Result<()> {
self.inner.playlists_emit(signal).await
}
#[inline]
pub async fn playlists_properties_changed(
&self,
properties: impl IntoIterator<Item = PlaylistsProperty>,
) -> Result<()> {
self.inner.playlists_properties_changed(properties).await
}
async fn handle_playlists_action(imp: &T, action: PlaylistsAction) {
match action {
PlaylistsAction::ActivatePlaylist(playlist_id, sender) => {
let ret = imp.activate_playlist(playlist_id).await;
sender.send(ret).unwrap();
}
PlaylistsAction::GetPlaylists(index, max_count, order, reverse_order, sender) => {
let ret = imp
.get_playlists(index, max_count, order, reverse_order)
.await;
sender.send(ret).unwrap();
}
PlaylistsAction::PlaylistCount(sender) => {
let ret = imp.playlist_count().await;
sender.send(ret).unwrap();
}
PlaylistsAction::Orderings(sender) => {
let ret = imp.orderings().await;
sender.send(ret).unwrap();
}
PlaylistsAction::ActivePlaylist(sender) => {
let ret = imp.active_playlist().await;
sender.send(ret).unwrap();
}
}
}
}
impl<T> LocalServer<T>
where
T: LocalTrackListInterface + LocalPlaylistsInterface + 'static,
{
pub async fn new_with_all(bus_name_suffix: &str, imp: T) -> Result<Self> {
Self::new_inner(
bus_name_suffix,
imp,
Server::new_with_all,
|rx, imp| async move {
while let Ok(action) = rx.recv().await {
match action {
Action::Root(action) => Self::handle_root_action(&imp, action).await,
Action::Player(action) => Self::handle_player_action(&imp, action).await,
Action::Playlists(action) => {
Self::handle_playlists_action(&imp, action).await
}
Action::TrackList(action) => {
Self::handle_track_list_action(&imp, action).await
}
}
}
},
)
.await
}
}
#[cfg(test)]
mod tests {
use static_assertions::{assert_impl_all, assert_not_impl_any};
use super::LocalServer;
#[allow(dead_code)]
pub struct TestPlayer;
assert_not_impl_any!(LocalServer<TestPlayer>: Send, Sync);
assert_impl_all!(LocalServer<TestPlayer>: Unpin);
}