Skip to content

Commit

Permalink
Merge branch 'refactor-time-to-pause-backend'
Browse files Browse the repository at this point in the history
  • Loading branch information
hpp2334 committed Nov 25, 2024
2 parents 0be6eb2 + b9a1e9b commit c0e623d
Show file tree
Hide file tree
Showing 28 changed files with 344 additions and 266 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.kutedev.easemusicplayer.utils.nextTickOnMain
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import uniffi.ease_client.MainAction
import uniffi.ease_client_android.IPermissionServiceForeign
import uniffi.ease_client_android.IRouterServiceForeign
import uniffi.ease_client_android.IToastServiceForeign
Expand Down Expand Up @@ -240,9 +241,11 @@ class UIBridge {
}

fun onActivityStart() {
dispatchAction(ViewAction.Main(MainAction.ON_MAIN_WIN_SHOWN))
}

fun onActivityStop() {
dispatchAction(ViewAction.Main(MainAction.ON_MAIN_WIN_HIDDEN))
}

fun onActivityDestroy() {
Expand Down
4 changes: 2 additions & 2 deletions misty-vm/misty-async/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ enum LocalTask {
pub trait IAsyncRuntimeAdapter: Send + Sync + 'static {
fn is_main_thread(&self) -> bool;
fn on_spawn_locals(&self);
fn sleep(&self, duration: Duration) -> LocalBoxFuture<()>;
fn sleep(&self, duration: Duration) -> BoxFuture<()>;
fn get_time(&self) -> Duration;
}

Expand Down Expand Up @@ -125,7 +125,7 @@ impl AsyncRuntime {
task
}

pub fn sleep(self: &Arc<Self>, duration: Duration) -> LocalBoxFuture<()> {
pub fn sleep(self: &Arc<Self>, duration: Duration) -> BoxFuture<()> {
self.adapter.sleep(duration)
}

Expand Down
4 changes: 2 additions & 2 deletions misty-vm/misty-vm-test/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::{
time::Duration,
};

use misty_vm::{App, AppPod, IAsyncRuntimeAdapter, IOnAsyncRuntime, LocalBoxFuture};
use misty_vm::{App, AppPod, BoxFuture, IAsyncRuntimeAdapter, IOnAsyncRuntime, LocalBoxFuture};

use crate::timer::FakeTimers;

Expand Down Expand Up @@ -111,7 +111,7 @@ impl IAsyncRuntimeAdapter for TestAsyncRuntimeAdapter {
self.is_same_thread()
}

fn sleep(&self, duration: Duration) -> LocalBoxFuture<()> {
fn sleep(&self, duration: Duration) -> BoxFuture<()> {
self.check_same_thread();
let timer = self.store.timers.sleep(duration);
Box::pin(timer)
Expand Down
28 changes: 17 additions & 11 deletions misty-vm/misty-vm-test/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,32 @@ use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicU64;
use std::sync::{Arc, RwLock};
use std::task::{Context, Poll, Waker};
use std::time::Duration;

#[derive(Clone)]
pub struct FakeTimers {
current: Rc<RefCell<u64>>,
timers: Rc<RefCell<Vec<(u64, Waker)>>>,
current: Arc<AtomicU64>,
timers: Arc<RwLock<Vec<(u64, Waker)>>>,
}

impl FakeTimers {
pub fn new() -> Self {
FakeTimers {
current: Rc::new(RefCell::new(0)),
timers: Rc::new(RefCell::new(Vec::new())),
current: Default::default(),
timers: Default::default(),
}
}

pub fn advance(&self, duration: Duration) {
let new_time = *self.current.borrow() + duration.as_millis() as u64;
*self.current.borrow_mut() = new_time;
let new_time =
self.current.load(std::sync::atomic::Ordering::Relaxed) + duration.as_millis() as u64;
self.current
.store(new_time, std::sync::atomic::Ordering::Relaxed);

let mut timers = self.timers.borrow_mut();
let mut timers = self.timers.write().unwrap();
let (to_wake, to_keep): (Vec<_>, Vec<_>) =
timers.drain(..).partition(|&(t, _)| t <= new_time);

Expand All @@ -35,15 +39,16 @@ impl FakeTimers {
}

pub fn sleep(&self, duration: Duration) -> FakeTimer {
let wake_time = *self.current.borrow() + duration.as_millis() as u64;
let wake_time =
self.current.load(std::sync::atomic::Ordering::Relaxed) + duration.as_millis() as u64;
FakeTimer {
wake_time,
time: self.clone(),
}
}

pub fn get_current_time(&self) -> Duration {
Duration::from_millis(*self.current.borrow())
Duration::from_millis(self.current.load(std::sync::atomic::Ordering::Relaxed))
}
}

Expand All @@ -56,12 +61,13 @@ impl Future for FakeTimer {
type Output = ();

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if *self.time.current.borrow() >= self.wake_time {
if self.time.current.load(std::sync::atomic::Ordering::Relaxed) >= self.wake_time {
Poll::Ready(())
} else {
self.time
.timers
.borrow_mut()
.write()
.unwrap()
.push((self.wake_time, cx.waker().clone()));
Poll::Pending
}
Expand Down
4 changes: 2 additions & 2 deletions misty-vm/misty-vm/src/async_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{

use async_task::{Runnable, Task};
use futures::future::LocalBoxFuture;
use misty_async::{AsyncRuntime, IAsyncRuntimeAdapter};
use misty_async::{AsyncRuntime, BoxFuture, IAsyncRuntimeAdapter};

use crate::internal::{AppInternal, WeakAppInternal};

Expand Down Expand Up @@ -84,7 +84,7 @@ impl IAsyncRuntimeAdapter for DefaultAsyncRuntimeAdapter {
todo!()
}

fn sleep(&self, duration: Duration) -> LocalBoxFuture<()> {
fn sleep(&self, duration: Duration) -> BoxFuture<()> {
todo!()
}

Expand Down
4 changes: 2 additions & 2 deletions rust-libs/ease-client-android/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ease_client_shared::backends::{
app::ArgInitializeApp, encode_message_payload, generated::Code, player::PlayerDelegateEvent,
storage::DataSourceKey, MessagePayload,
};
use misty_vm::{AppPods, AsyncRuntime, IAsyncRuntimeAdapter, LocalBoxFuture};
use misty_vm::{AppPods, AsyncRuntime, BoxFuture, IAsyncRuntimeAdapter, LocalBoxFuture};
use once_cell::sync::Lazy;

use tokio::runtime::Runtime;
Expand Down Expand Up @@ -60,7 +60,7 @@ impl IAsyncRuntimeAdapter for AsyncAdapterDelegate {
.unwrap()
}

fn sleep(&self, duration: Duration) -> LocalBoxFuture<()> {
fn sleep(&self, duration: Duration) -> BoxFuture<()> {
Box::pin(tokio::time::sleep(duration))
}
}
Expand Down
2 changes: 1 addition & 1 deletion rust-libs/ease-client-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ num-derive = "0.2"
bytes = "1.5.0"
thiserror = "1.0.57"
urlencoding = "2.1.3"
getset = "0.1.2"
getset = "0.1.3"
serde_json = "1.0"
serde_bytes = "0.11.14"
futures = "0.3.30"
Expand Down
3 changes: 2 additions & 1 deletion rust-libs/ease-client-backend/src/controllers/connector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
ctx::BackendContext,
error::BResult,
services::{
app::load_preference_data, player::on_connect_for_player,
app::load_preference_data, music::notify_time_to_pause, player::on_connect_for_player,
playlist::notify_all_playlist_abstracts, storage::notify_storages,
},
};
Expand All @@ -18,6 +18,7 @@ pub(crate) async fn ci_on_connect(cx: &Arc<BackendContext>, _arg: ()) -> BResult
on_connect_for_player(cx, data.playmode),
notify_all_playlist_abstracts(cx),
notify_storages(cx),
notify_time_to_pause(cx),
}?;
Ok(())
}
17 changes: 15 additions & 2 deletions rust-libs/ease-client-backend/src/controllers/music.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::sync::Arc;
use std::{sync::Arc, time::Duration};

use ease_client_shared::backends::music::{ArgUpdateMusicLyric, Music, MusicId};
use futures::try_join;
Expand All @@ -8,7 +8,7 @@ use crate::{
error::BResult,
repositories::{core::get_conn, music::db_update_music_lyric},
services::{
music::{get_music, notify_music},
music::{disable_time_to_pause, enable_time_to_pause, get_music, notify_music},
storage::from_opt_storage_entry,
},
};
Expand All @@ -31,3 +31,16 @@ pub(crate) async fn cu_update_music_lyric(

Ok(())
}

pub(crate) async fn cu_enable_time_to_pause(
cx: &Arc<BackendContext>,
arg: std::time::Duration,
) -> BResult<()> {
enable_time_to_pause(cx, arg);
Ok(())
}

pub(crate) async fn cu_disable_time_to_pause(cx: &Arc<BackendContext>, _arg: ()) -> BResult<()> {
disable_time_to_pause(cx);
Ok(())
}
23 changes: 11 additions & 12 deletions rust-libs/ease-client-backend/src/ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,30 @@ use std::{
};

use ease_client_shared::backends::connector::{ConnectorAction, IConnectorNotifier};
use getset::Getters;
use misty_async::AsyncRuntime;

use crate::services::{
music::TimeToPauseState,
player::{IPlayerDelegate, PlayerState},
server::AssetServer,
storage::StorageState,
};

#[derive(Getters)]
pub struct BackendContext {
storage_path: RwLock<String>,
app_document_dir: RwLock<String>,
schema_version: AtomicU32,
rt: Arc<AsyncRuntime>,
player: Arc<dyn IPlayerDelegate>,
#[getset(get = "pub(crate)")]
player_delegate: Arc<dyn IPlayerDelegate>,
#[getset(get = "pub(crate)")]
player_state: Arc<PlayerState>,
#[getset(get = "pub(crate)")]
storage_state: Arc<StorageState>,
#[getset(get = "pub(crate)")]
time_to_pause_state: Arc<TimeToPauseState>,
connectors: (
RwLock<HashMap<usize, Arc<dyn IConnectorNotifier>>>,
AtomicUsize,
Expand All @@ -48,8 +56,9 @@ impl BackendContext {
schema_version: AtomicU32::new(0),
rt,
player_state: Default::default(),
player,
player_delegate: player,
storage_state: Default::default(),
time_to_pause_state: Default::default(),
connectors: Default::default(),
}
}
Expand All @@ -71,16 +80,6 @@ impl BackendContext {
&self.rt
}

pub fn player_state(&self) -> &Arc<PlayerState> {
&self.player_state
}
pub fn player_delegate(&self) -> &Arc<dyn IPlayerDelegate> {
&self.player
}
pub fn storage_state(&self) -> &Arc<StorageState> {
&self.storage_state
}

pub fn current_time(&self) -> Duration {
std::time::UNIX_EPOCH.elapsed().unwrap()
}
Expand Down
81 changes: 79 additions & 2 deletions rust-libs/ease-client-backend/src/services/music/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use std::sync::Arc;
use std::{
sync::{atomic::AtomicBool, Arc, RwLock},
time::Duration,
};

use ease_client_shared::backends::{
connector::ConnectorAction,
music::{LyricLoadState, Music, MusicAbstract, MusicId, MusicLyric, MusicMeta},
music::{
LyricLoadState, Music, MusicAbstract, MusicId, MusicLyric, MusicMeta, TimeToPauseInfo,
},
music_duration::MusicDuration,
storage::{DataSourceKey, StorageEntryLoc},
};
use misty_async::Task;

use crate::{
ctx::BackendContext,
Expand All @@ -24,6 +30,13 @@ use super::{
storage::{load_storage_entry_data, to_opt_storage_entry},
};

#[derive(Debug, Default)]
pub struct TimeToPauseState {
enabled: AtomicBool,
expired: RwLock<Duration>,
task: RwLock<Option<Task<()>>>,
}

async fn load_lyric(
cx: &Arc<BackendContext>,
loc: Option<StorageEntryLoc>,
Expand Down Expand Up @@ -220,3 +233,67 @@ pub(crate) async fn notify_music(cx: &Arc<BackendContext>, id: MusicId) -> BResu
}
Ok(())
}

pub(crate) fn enable_time_to_pause(cx: &Arc<BackendContext>, delay: Duration) {
let state = cx.time_to_pause_state().clone();
state.task.write().unwrap().take();
state
.enabled
.store(true, std::sync::atomic::Ordering::Relaxed);
*state.expired.write().unwrap() = cx.async_runtime().get_time() + delay;
let task = {
let cx = cx.clone();
cx.async_runtime().clone().spawn(async move {
cx.async_runtime().sleep(delay).await;
state
.enabled
.store(false, std::sync::atomic::Ordering::Relaxed);
sync_notify_time_to_pause(&cx);
{
let cx = cx.clone();
cx.async_runtime()
.clone()
.spawn_on_main(async move {
cx.player_delegate().pause();
})
.await
}
})
};
{
let mut w = cx.time_to_pause_state().task.write().unwrap();
*w = Some(task);
}
sync_notify_time_to_pause(cx);
}

pub(crate) fn disable_time_to_pause(cx: &Arc<BackendContext>) {
cx.time_to_pause_state().task.write().unwrap().take();
cx.time_to_pause_state()
.enabled
.store(false, std::sync::atomic::Ordering::Relaxed);
sync_notify_time_to_pause(cx);
}

pub(crate) fn sync_notify_time_to_pause(cx: &Arc<BackendContext>) {
let state = cx.time_to_pause_state().clone();
let enabled = state.enabled.load(std::sync::atomic::Ordering::Relaxed);
let expired = state.expired.read().unwrap().clone();
let current_time = cx.async_runtime().get_time();
let left = if current_time < expired {
expired - current_time
} else {
Duration::ZERO
};

cx.notify(ConnectorAction::TimeToPause(TimeToPauseInfo {
enabled,
expired,
left,
}));
}

pub(crate) async fn notify_time_to_pause(cx: &Arc<BackendContext>) -> BResult<()> {
sync_notify_time_to_pause(cx);
Ok(())
}
Loading

0 comments on commit c0e623d

Please sign in to comment.