Skip to content

Commit 8684a71

Browse files
committed
Synchronized now playing state on outside promise
- Avoid timing out test to gather additional data
1 parent 1bca0bf commit 8684a71

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/playback/engine/PlaybackEngine.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ import com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.ManageN
2222
import com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.NowPlaying
2323
import com.lasthopesoftware.bluewater.client.playback.playlist.ManagePlaylistPlayback
2424
import com.lasthopesoftware.bluewater.shared.lazyLogger
25-
import com.lasthopesoftware.policies.ratelimiting.PromisingRateLimiter
2625
import com.lasthopesoftware.promises.ContinuingResult
2726
import com.lasthopesoftware.promises.extensions.ProgressingPromise
2827
import com.lasthopesoftware.promises.extensions.keepPromise
2928
import com.lasthopesoftware.promises.extensions.onEachEventually
29+
import com.lasthopesoftware.promises.extensions.regardless
3030
import com.lasthopesoftware.promises.extensions.toPromise
3131
import com.lasthopesoftware.promises.extensions.unitResponse
3232
import com.namehillsoftware.handoff.errors.RejectionDropper
@@ -69,7 +69,10 @@ class PlaybackEngine(
6969

7070
private val activeLibraryId = AtomicReference(markerLibraryId)
7171

72-
private val nowPlayingStateSync = PromisingRateLimiter<NowPlaying?>(1)
72+
private val promisedNowPlayingStateSync = Any()
73+
74+
@Volatile
75+
private var promisedNowPlayingState = Promise.empty<NowPlaying?>()
7376

7477
private val promisedPlayback = AtomicReference<ProgressingPromise<PositionedPlayingFile, Unit>?>(null)
7578

@@ -480,13 +483,9 @@ class PlaybackEngine(
480483
return playlistPlayback.resume()
481484
}
482485

483-
private fun serializedPlayerUpdate() = nowPlayingStateSync.limit {
484-
playbackBootstrapper.updateFromState(activeLibraryId.get())
485-
}
486+
private fun serializedPlayerUpdate() = updateStateSynchronously { playbackBootstrapper.updateFromState(activeLibraryId.get()) }
486487

487-
private fun promiseActiveNowPlaying() = nowPlayingStateSync.limit {
488-
nowPlayingRepository.promiseNowPlaying(activeLibraryId.get())
489-
}
488+
private fun promiseActiveNowPlaying() = updateStateSynchronously { nowPlayingRepository.promiseNowPlaying(activeLibraryId.get()) }
490489

491490
private fun saveState(
492491
libraryId: LibraryId,
@@ -508,7 +507,7 @@ class PlaybackEngine(
508507
private inline fun saveState(
509508
libraryId: LibraryId,
510509
crossinline updateFunc: NowPlaying.() -> NowPlaying
511-
): Promise<NowPlaying?> = nowPlayingStateSync.limit {
510+
): Promise<NowPlaying?> = updateStateSynchronously {
512511
nowPlayingRepository.promiseNowPlaying(libraryId).eventually {
513512
it?.let { np ->
514513
val updatedNowPlaying = updateFunc(np)
@@ -519,7 +518,25 @@ class PlaybackEngine(
519518
}
520519

521520
@Suppress("UNCHECKED_CAST")
522-
private fun saveState(nowPlaying: NowPlaying): Promise<NowPlaying?> = nowPlayingStateSync.limit {
521+
private fun saveState(nowPlaying: NowPlaying): Promise<NowPlaying?> = updateStateSynchronously {
523522
nowPlayingRepository.updateNowPlaying(nowPlaying) as Promise<NowPlaying?>
524523
}
524+
525+
/**
526+
* Updates the `promisedNowPlayingState` with the result of the provided `updateFunc`.
527+
*
528+
* This function ensures that the `promisedNowPlayingState` is updated synchronously.
529+
* Each new update is chained to the previous promise, guaranteeing that state
530+
* updates are applied in the order they are initiated.
531+
*
532+
* @param updateFunc A function that returns a [Promise] for a nullable [NowPlaying] state.
533+
* This function is responsible for fetching or modifying the state.
534+
* @return A [Promise] that resolves with the current [NowPlaying] state after the update
535+
* function has been scheduled. To wait for the update to complete, chain to the returned promise.
536+
*/
537+
private inline fun updateStateSynchronously(crossinline updateFunc: () -> Promise<NowPlaying?>): Promise<NowPlaying?> = synchronized(promisedNowPlayingStateSync) {
538+
promisedNowPlayingState
539+
.regardless { updateFunc() }
540+
.also { promisedNowPlayingState = it }
541+
}
525542
}

projectBlueWater/src/test/java/com/lasthopesoftware/bluewater/client/playback/engine/GivenAPlayingPlaybackEngine/When changing tracks many times.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ import com.lasthopesoftware.bluewater.client.playback.volume.PlaylistVolumeManag
1919
import com.lasthopesoftware.bluewater.shared.promises.extensions.DeferredPromise
2020
import com.lasthopesoftware.bluewater.shared.promises.extensions.toExpiringFuture
2121
import com.lasthopesoftware.promises.ForwardedResponse.Companion.thenForward
22+
import com.lasthopesoftware.promises.PromiseDelay
2223
import com.lasthopesoftware.promises.extensions.keepPromise
24+
import com.lasthopesoftware.promises.toFuture
2325
import com.namehillsoftware.handoff.promises.Promise
2426
import io.mockk.every
2527
import io.mockk.mockk
@@ -107,7 +109,7 @@ class `When changing tracks many times` {
107109
1
108110
)
109111

110-
val (playingPlaybackHandler, resolvablePlaybackHandler) = preparedFiles.getValue(ServiceFile("2"))
112+
val (playingPlaybackHandler, resolvablePlaybackHandler) = preparedFiles.getValue(playlist[1])
111113
resolvablePlaybackHandler.resolve()
112114
promisedStart.toExpiringFuture().get()
113115

@@ -125,12 +127,15 @@ class `When changing tracks many times` {
125127

126128
nextSwitchedFile = promisedChanges.toExpiringFuture().get()?.lastOrNull()?.second
127129

128-
// Resolve the first skipped tracks afterward to ensure a cancellation is tested.
130+
// Resolve the first skipped track afterward to ensure a cancellation is tested.
129131
preparedFiles[playlist[0]]?.second?.resolve()
130132

131133
playingPlaybackHandler.resolve()
132134

133-
latestFile = promisedFinalFile.toExpiringFuture().get()
135+
latestFile = Promise.whenAny(
136+
promisedFinalFile,
137+
PromiseDelay.delay(Duration.standardSeconds(10))
138+
).toFuture().get()
134139
}
135140

136141
@Test

0 commit comments

Comments
 (0)