fix(peer): coalesce full UI view publications
Keep one queued and one replaceable pending snapshot for remote-library and Call-to-Play views while preserving lifecycle-event FIFO delivery. Generation barriers and fenced drains prevent stale nonempty views from crossing disable or acknowledgement boundaries. Test Plan: - just test - just clippy - focused burst, lifecycle ordering, fence, repeated-barrier, and stale-view tests - independent ordering review - git diff --check
This commit is contained in:
1 parent
470e119515
commit
37420e26ed
17 files changed
+828
-251
No files matched your search
@@ -14,7 +14,7 @@ use lanspread_db::{
|
||||
db::GameDB,
|
||||
};
|
||||
use lanspread_proto::PeerEndpoint;
|
||||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use crate::PeerEventSender;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -82,7 +82,7 @@ where
|
||||
|
||||
async fn register_download_attempt(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
key: DownloadAttemptKey,
|
||||
cancellation: CancellationToken,
|
||||
) -> DownloadAttemptStatus {
|
||||
@@ -202,7 +202,7 @@ impl fmt::Display for StreamDownloadError {
|
||||
}
|
||||
|
||||
/// Handles the `ListGames` command.
|
||||
pub async fn handle_list_games_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
||||
pub async fn handle_list_games_command(ctx: &Ctx, tx_notify_ui: &PeerEventSender) {
|
||||
log::info!("ListGames command received");
|
||||
events::emit_peer_game_list(&ctx.peer_game_db, tx_notify_ui).await;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ pub async fn handle_list_games_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub async fn handle_download_game_files_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
install_after_download: bool,
|
||||
) {
|
||||
@@ -494,7 +494,7 @@ pub async fn handle_download_game_files_command(
|
||||
|
||||
fn finish_cached_download(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
attempt: &DownloadAttemptKey,
|
||||
install_after_download: bool,
|
||||
target: OperationTarget,
|
||||
@@ -547,7 +547,7 @@ async fn settle_download_completion(
|
||||
/// Handles the `InstallGame` command.
|
||||
pub async fn handle_install_game_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
) {
|
||||
let games_folder = ctx.game_dir.read().await.clone();
|
||||
@@ -575,7 +575,7 @@ async fn stream_install_target_is_ready(ctx: &Ctx, target: &OperationTarget) ->
|
||||
|
||||
async fn begin_stream_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
attempt: &DownloadAttemptKey,
|
||||
) -> bool {
|
||||
@@ -631,7 +631,7 @@ async fn begin_stream_install_operation(
|
||||
|
||||
pub async fn handle_stream_install_game_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
settings: StreamInstallSettings,
|
||||
) {
|
||||
@@ -742,7 +742,7 @@ pub async fn handle_stream_install_game_command(
|
||||
|
||||
struct StreamInstallOperation {
|
||||
ctx: Ctx,
|
||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: PeerEventSender,
|
||||
target: OperationTarget,
|
||||
manifest: Arc<CatalogContentManifest>,
|
||||
settings: StreamInstallSettings,
|
||||
@@ -768,7 +768,7 @@ async fn stream_install_sources(
|
||||
|
||||
async fn select_stream_install_sources_or_finish(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
manifest: &CatalogContentManifest,
|
||||
download_guard: OperationGuard,
|
||||
@@ -798,7 +798,7 @@ async fn select_stream_install_sources_or_finish(
|
||||
/// Handles the `UninstallGame` command.
|
||||
pub async fn handle_uninstall_game_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
) {
|
||||
let games_folder = ctx.game_dir.read().await.clone();
|
||||
@@ -812,7 +812,7 @@ pub async fn handle_uninstall_game_command(
|
||||
|
||||
pub async fn handle_remove_downloaded_game_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
) {
|
||||
let games_folder = ctx.game_dir.read().await.clone();
|
||||
@@ -826,7 +826,7 @@ pub async fn handle_remove_downloaded_game_command(
|
||||
|
||||
pub async fn handle_cancel_download_command(
|
||||
ctx: &Ctx,
|
||||
_tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
_tx_notify_ui: &PeerEventSender,
|
||||
id: String,
|
||||
) {
|
||||
let signal = ctx.active_downloads.read().await.get(&id).cloned();
|
||||
@@ -945,7 +945,7 @@ async fn run_stream_install_operation(operation: StreamInstallOperation) {
|
||||
|
||||
async fn finish_stream_receive_error(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
download_guard: OperationGuard,
|
||||
download_attempt: &DownloadAttemptStatus,
|
||||
@@ -975,7 +975,7 @@ async fn finish_stream_receive_error(
|
||||
|
||||
struct StreamInstallPromotionPreparation<'a> {
|
||||
ctx: &'a Ctx,
|
||||
tx_notify_ui: &'a UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &'a PeerEventSender,
|
||||
target: &'a OperationTarget,
|
||||
transaction: install::StreamedInstallTransaction,
|
||||
settings: &'a StreamInstallSettings,
|
||||
@@ -1055,7 +1055,7 @@ async fn prepare_streamed_install_for_promotion(
|
||||
|
||||
struct StreamInstallReceiveRequest<'a> {
|
||||
ctx: &'a Ctx,
|
||||
tx_notify_ui: &'a UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &'a PeerEventSender,
|
||||
target: &'a OperationTarget,
|
||||
manifest: &'a Arc<CatalogContentManifest>,
|
||||
sources: &'a [PeerEndpoint],
|
||||
@@ -1218,7 +1218,7 @@ async fn receive_streamed_install_from_peers(
|
||||
|
||||
async fn finish_failed_stream_download(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
guard: OperationGuard,
|
||||
status: &DownloadAttemptStatus,
|
||||
@@ -1243,7 +1243,7 @@ async fn finish_failed_stream_download(
|
||||
|
||||
struct StreamInstallCommit {
|
||||
ctx: Ctx,
|
||||
tx_notify_ui: UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: PeerEventSender,
|
||||
target: OperationTarget,
|
||||
transaction: install::StreamedInstallTransaction,
|
||||
manifest: Arc<CatalogContentManifest>,
|
||||
@@ -1346,7 +1346,7 @@ fn promote_streamed_install(
|
||||
|
||||
fn spawn_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: OperationTarget,
|
||||
) {
|
||||
let ctx = ctx.clone();
|
||||
@@ -1358,7 +1358,7 @@ fn spawn_install_operation(
|
||||
|
||||
async fn run_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: OperationTarget,
|
||||
) {
|
||||
let id = target.game_id().to_owned();
|
||||
@@ -1442,7 +1442,7 @@ struct PreparedInstallOperation {
|
||||
|
||||
async fn prepare_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
) -> Option<PreparedInstallOperation> {
|
||||
let id = target.game_id();
|
||||
@@ -1499,7 +1499,7 @@ async fn prepare_install_operation(
|
||||
|
||||
async fn revalidate_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
expected_kind: OperationKind,
|
||||
) -> Option<PreparedInstallOperation> {
|
||||
@@ -1522,7 +1522,7 @@ async fn revalidate_install_operation(
|
||||
|
||||
async fn run_started_install_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: OperationTarget,
|
||||
prepared: PreparedInstallOperation,
|
||||
operation_guard: OperationGuard,
|
||||
@@ -1599,7 +1599,7 @@ async fn run_started_install_operation(
|
||||
|
||||
async fn run_uninstall_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: OperationTarget,
|
||||
) {
|
||||
let id = target.game_id().to_owned();
|
||||
@@ -1696,7 +1696,7 @@ async fn run_uninstall_operation(
|
||||
|
||||
async fn run_remove_downloaded_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: OperationTarget,
|
||||
) {
|
||||
let id = target.game_id().to_owned();
|
||||
@@ -1804,7 +1804,7 @@ enum BeginOperationResult {
|
||||
|
||||
async fn begin_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
operation: OperationKind,
|
||||
) -> BeginOperationResult {
|
||||
@@ -1820,7 +1820,7 @@ async fn begin_operation(
|
||||
|
||||
async fn begin_operation_with_drain_timeout(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
operation: OperationKind,
|
||||
drain_timeout: Duration,
|
||||
@@ -2009,7 +2009,7 @@ async fn cancel_and_wait_for_outbound_transfers(
|
||||
|
||||
async fn transition_download_to_install(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
id: &str,
|
||||
operation: OperationKind,
|
||||
) -> bool {
|
||||
@@ -2042,7 +2042,7 @@ async fn transition_download_to_install(
|
||||
transitioned
|
||||
}
|
||||
|
||||
async fn end_operation(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>, id: &str) {
|
||||
async fn end_operation(ctx: &Ctx, tx_notify_ui: &PeerEventSender, id: &str) {
|
||||
if ctx.active_operations.write().await.remove(id).is_some() {
|
||||
events::emit_active_operations(&ctx.active_operations, tx_notify_ui).await;
|
||||
}
|
||||
@@ -2059,7 +2059,7 @@ async fn clear_active_download(ctx: &Ctx, attempt: &DownloadAttemptKey) {
|
||||
}
|
||||
|
||||
fn send_download_failed(
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
attempt: &DownloadAttemptKey,
|
||||
reason: DownloadFailureReason,
|
||||
) {
|
||||
@@ -2074,7 +2074,7 @@ fn send_download_failed(
|
||||
|
||||
async fn end_download_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
attempt: &DownloadAttemptKey,
|
||||
) {
|
||||
clear_active_download(ctx, attempt).await;
|
||||
@@ -2083,7 +2083,7 @@ async fn end_download_operation(
|
||||
|
||||
async fn settle_target_state(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
) -> eyre::Result<()> {
|
||||
install::recover_game_root(
|
||||
@@ -2097,7 +2097,7 @@ async fn settle_target_state(
|
||||
|
||||
async fn settle_and_end_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
guard: OperationGuard,
|
||||
label: &str,
|
||||
@@ -2121,7 +2121,7 @@ async fn settle_and_end_operation(
|
||||
|
||||
async fn settle_and_end_download(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
guard: OperationGuard,
|
||||
attempt: &DownloadAttemptKey,
|
||||
@@ -2142,7 +2142,7 @@ async fn settle_and_end_download(
|
||||
|
||||
async fn finish_successful_download_after_refresh(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
guard: OperationGuard,
|
||||
status: &DownloadAttemptStatus,
|
||||
@@ -2164,7 +2164,7 @@ async fn finish_successful_download_after_refresh(
|
||||
|
||||
async fn finish_failed_download_after_refresh(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
guard: OperationGuard,
|
||||
status: &DownloadAttemptStatus,
|
||||
@@ -2193,7 +2193,7 @@ fn catalog_contains(ctx: &Ctx, id: &str) -> bool {
|
||||
|
||||
async fn begin_local_recovery(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
game_dir: &Path,
|
||||
force_empty_snapshot: bool,
|
||||
) -> eyre::Result<()> {
|
||||
@@ -2225,7 +2225,7 @@ async fn begin_local_recovery(
|
||||
/// quarantined. `Err` is returned only before changing the configured root.
|
||||
pub async fn handle_set_game_dir_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
game_dir: PathBuf,
|
||||
) -> Result<PathBuf, String> {
|
||||
handle_set_game_dir_command_with_drain_timeout(
|
||||
@@ -2239,7 +2239,7 @@ pub async fn handle_set_game_dir_command(
|
||||
|
||||
async fn handle_set_game_dir_command_with_drain_timeout(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
requested_game_dir: PathBuf,
|
||||
drain_timeout: Duration,
|
||||
) -> Result<PathBuf, String> {
|
||||
@@ -2344,14 +2344,14 @@ async fn handle_set_game_dir_command_with_drain_timeout(
|
||||
/// Loads the configured local library and announces the result.
|
||||
pub async fn load_local_library(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
) -> eyre::Result<()> {
|
||||
load_local_library_with_policy(ctx, tx_notify_ui, LocalLibraryEventPolicy::OnChange).await
|
||||
}
|
||||
|
||||
async fn load_local_library_with_policy(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
event_policy: LocalLibraryEventPolicy,
|
||||
) -> eyre::Result<()> {
|
||||
let game_dir = { ctx.game_dir.read().await.clone() };
|
||||
@@ -2385,7 +2385,7 @@ async fn load_local_library_with_policy(
|
||||
|
||||
async fn scan_and_announce_local_library(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
game_dir: &Path,
|
||||
event_policy: LocalLibraryEventPolicy,
|
||||
recovery_failed_ids: &HashSet<String>,
|
||||
@@ -2410,7 +2410,7 @@ async fn scan_and_announce_local_library(
|
||||
/// active-operation snapshot, while preserving freeze behavior for other games.
|
||||
async fn refresh_local_game_for_ending_operation(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
target: &OperationTarget,
|
||||
) -> eyre::Result<()> {
|
||||
let catalog = ctx.catalog.catalog();
|
||||
@@ -2456,7 +2456,7 @@ async fn active_operation_ids(ctx: &Ctx) -> HashSet<String> {
|
||||
}
|
||||
|
||||
/// Handles the `GetPeerCount` command.
|
||||
pub async fn handle_get_peer_count_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerEvent>) {
|
||||
pub async fn handle_get_peer_count_command(ctx: &Ctx, tx_notify_ui: &PeerEventSender) {
|
||||
log::info!("GetPeerCount command received");
|
||||
events::emit_peer_count(&ctx.peer_game_db, tx_notify_ui).await;
|
||||
}
|
||||
@@ -2464,7 +2464,7 @@ pub async fn handle_get_peer_count_command(ctx: &Ctx, tx_notify_ui: &UnboundedSe
|
||||
/// Connects to a peer directly, bypassing mDNS discovery.
|
||||
pub async fn handle_connect_peer_command(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
endpoint: PeerEndpoint,
|
||||
) {
|
||||
log::info!("Direct connect command received for {}", endpoint.addr);
|
||||
@@ -2509,7 +2509,7 @@ pub async fn handle_connect_peer_command(
|
||||
/// Updates the local game database and announces changes to peers.
|
||||
pub async fn update_and_announce_games(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
scan: LocalLibraryScan,
|
||||
) {
|
||||
let _ = update_and_announce_games_with_policy(
|
||||
@@ -2524,7 +2524,7 @@ pub async fn update_and_announce_games(
|
||||
|
||||
async fn update_and_announce_games_with_policy(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
scan: LocalLibraryScan,
|
||||
event_policy: LocalLibraryEventPolicy,
|
||||
ending_operation_id: Option<&str>,
|
||||
@@ -2659,7 +2659,7 @@ mod tests {
|
||||
PeerId,
|
||||
RuntimeSessionId,
|
||||
};
|
||||
use tokio::sync::{RwLock, mpsc, oneshot};
|
||||
use tokio::sync::{RwLock, oneshot};
|
||||
use tokio_util::{sync::CancellationToken, task::TaskTracker};
|
||||
|
||||
use super::*;
|
||||
@@ -2834,7 +2834,7 @@ mod tests {
|
||||
|
||||
async fn register_test_download(
|
||||
ctx: &Ctx,
|
||||
tx_notify_ui: &UnboundedSender<PeerEvent>,
|
||||
tx_notify_ui: &PeerEventSender,
|
||||
) -> (DownloadAttemptStatus, CancellationToken) {
|
||||
let cancellation = CancellationToken::new();
|
||||
let status = register_download_attempt(
|
||||
@@ -2868,7 +2868,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn cancelled_download_owner_does_not_emit_failed_event() {
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let status = DownloadAttemptStatus::new(
|
||||
DownloadAttemptKey::next("game".to_owned()),
|
||||
CancellationToken::new(),
|
||||
@@ -2885,7 +2885,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn uncancelled_download_error_emits_failed_event() {
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let attempt = DownloadAttemptKey::next("game".to_owned());
|
||||
|
||||
send_download_failed(&tx, &attempt, DownloadFailureReason::OperationFailed);
|
||||
@@ -2959,7 +2959,7 @@ mod tests {
|
||||
);
|
||||
seed_exact_download_ownership(&ctx, games.path(), content_id).await;
|
||||
let peer_db = ctx.peer_game_db.write().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(1),
|
||||
@@ -2993,7 +2993,7 @@ mod tests {
|
||||
NetworkControl::disabled_for_test(),
|
||||
);
|
||||
let peer_db = ctx.peer_game_db.write().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(1),
|
||||
@@ -3033,7 +3033,7 @@ mod tests {
|
||||
NetworkControl::disabled_for_test(),
|
||||
);
|
||||
let peer_db = ctx.peer_game_db.write().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(1),
|
||||
@@ -3070,7 +3070,7 @@ mod tests {
|
||||
NetworkControl::disabled_for_test(),
|
||||
);
|
||||
let peer_db = ctx.peer_game_db.write().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
tokio::time::timeout(
|
||||
Duration::from_secs(1),
|
||||
@@ -3100,7 +3100,7 @@ mod tests {
|
||||
.current_publication()
|
||||
.expect("initial Call-to-Play projection should load")
|
||||
.view;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let (reply_tx, reply_rx) = oneshot::channel();
|
||||
|
||||
tokio::time::timeout(
|
||||
@@ -3136,7 +3136,7 @@ mod tests {
|
||||
let games = TempDir::new("lanspread-handler-enabled-call-to-play");
|
||||
let ctx = test_ctx(games.path().to_path_buf());
|
||||
let store = ctx.call_to_play.write().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let (reply_tx, mut reply_rx) = oneshot::channel();
|
||||
let task = tokio::spawn({
|
||||
let ctx = ctx.clone();
|
||||
@@ -3177,7 +3177,7 @@ mod tests {
|
||||
async fn streamed_install_without_extracted_catalog_manifest_fails_before_admission() {
|
||||
let games = TempDir::new("lanspread-handler-stream-capability");
|
||||
let ctx = test_ctx(games.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
handle_stream_install_game_command(
|
||||
&ctx,
|
||||
@@ -3226,7 +3226,7 @@ mod tests {
|
||||
)
|
||||
.await
|
||||
);
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
handle_download_game_files_command(&ctx, &tx, "game".to_string(), false).await;
|
||||
|
||||
@@ -3264,7 +3264,7 @@ mod tests {
|
||||
.write()
|
||||
.await
|
||||
.insert("game".to_owned(), OperationKind::Downloading);
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
handle_download_game_files_command(&ctx, &tx, "game".to_owned(), false).await;
|
||||
|
||||
@@ -3401,7 +3401,7 @@ mod tests {
|
||||
games.path().to_path_buf(),
|
||||
catalog_bundle([("broken", "20250101"), ("healthy", "20250101")]),
|
||||
);
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let error = load_local_library(&ctx, &tx)
|
||||
.await
|
||||
@@ -3445,7 +3445,7 @@ mod tests {
|
||||
.expect("game-root symlink should be created");
|
||||
|
||||
let ctx = test_ctx(games.path().to_path_buf());
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let error = load_local_library(&ctx, &tx)
|
||||
.await
|
||||
@@ -3470,7 +3470,7 @@ mod tests {
|
||||
async fn operation_admission_rejects_recovering_and_failed_games() {
|
||||
let games = TempDir::new("lanspread-handler-recovery-admission");
|
||||
let ctx = test_ctx(games.path().to_path_buf());
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
ctx.recovery_quarantine.begin(games.path().to_path_buf());
|
||||
let target = operation_target(games.path());
|
||||
@@ -3496,7 +3496,7 @@ mod tests {
|
||||
let games = TempDir::new("lanspread-handler-download-refresh-failure");
|
||||
write_file(&games.game_root(), b"not a directory");
|
||||
let ctx = test_ctx(games.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let (status, cancel) = register_test_download(&ctx, &tx).await;
|
||||
ctx.active_operations
|
||||
.write()
|
||||
@@ -3519,14 +3519,14 @@ mod tests {
|
||||
assert_no_event(&mut rx).await;
|
||||
}
|
||||
|
||||
async fn recv_event(rx: &mut mpsc::UnboundedReceiver<PeerEvent>) -> PeerEvent {
|
||||
async fn recv_event(rx: &mut crate::PeerEventReceiver) -> PeerEvent {
|
||||
tokio::time::timeout(Duration::from_secs(1), rx.recv())
|
||||
.await
|
||||
.expect("event should arrive")
|
||||
.expect("event channel should remain open")
|
||||
}
|
||||
|
||||
async fn assert_no_event(rx: &mut mpsc::UnboundedReceiver<PeerEvent>) {
|
||||
async fn assert_no_event(rx: &mut crate::PeerEventReceiver) {
|
||||
assert!(
|
||||
tokio::time::timeout(Duration::from_millis(50), rx.recv())
|
||||
.await
|
||||
@@ -3535,7 +3535,7 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
fn drain_events(rx: &mut mpsc::UnboundedReceiver<PeerEvent>) -> Vec<PeerEvent> {
|
||||
fn drain_events(rx: &mut crate::PeerEventReceiver) -> Vec<PeerEvent> {
|
||||
let mut events = Vec::new();
|
||||
while let Ok(event) = rx.try_recv() {
|
||||
events.push(event);
|
||||
@@ -3682,7 +3682,7 @@ mod tests {
|
||||
let state = TempDir::new("lanspread-handler-stream-retry-setup-state");
|
||||
std::fs::create_dir_all(games.game_root().join("local"))
|
||||
.expect("installed tree should be created");
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let status = DownloadAttemptStatus::new(
|
||||
DownloadAttemptKey::next("game".to_owned()),
|
||||
CancellationToken::new(),
|
||||
@@ -3719,7 +3719,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
|
||||
// 1. Initial scan: the game is ready and announced
|
||||
@@ -3845,7 +3845,7 @@ mod tests {
|
||||
.expect("catalog construction should defer manifest body parsing"),
|
||||
);
|
||||
let ctx = test_ctx_with_catalog(games.path().to_path_buf(), catalog);
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let scan = scan_local_library(games.path(), ctx.state_dir.as_ref(), ctx.catalog.catalog())
|
||||
.await
|
||||
.expect("ready game should scan before manifest priming");
|
||||
@@ -3884,7 +3884,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
|
||||
let current_scan = scan_local_library(current.path(), ctx.state_dir.as_ref(), catalog)
|
||||
@@ -3921,7 +3921,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
let older_scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), catalog)
|
||||
.await
|
||||
@@ -3973,7 +3973,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let target = operation_target(temp.path());
|
||||
|
||||
assert_eq!(
|
||||
@@ -3997,7 +3997,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), ctx.catalog.catalog())
|
||||
.await
|
||||
.expect("initial scan should succeed");
|
||||
@@ -4057,7 +4057,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let target = operation_target(temp.path());
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), ctx.catalog.catalog())
|
||||
.await
|
||||
@@ -4122,7 +4122,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), ctx.catalog.catalog())
|
||||
.await
|
||||
.expect("initial scan should succeed");
|
||||
@@ -4195,7 +4195,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), catalog)
|
||||
@@ -4221,7 +4221,7 @@ mod tests {
|
||||
write_file(&root.join("local").join("old.txt"), b"old");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), catalog)
|
||||
.await
|
||||
@@ -4256,7 +4256,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
run_install_operation(&ctx, &tx, operation_target(temp.path())).await;
|
||||
|
||||
@@ -4281,7 +4281,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let target = operation_target(temp.path());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
let prepared = prepare_install_operation(&ctx, &tx, &target)
|
||||
.await
|
||||
@@ -4334,7 +4334,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let target = operation_target(temp.path());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
assert!(stream_install_target_is_ready(&ctx, &target).await);
|
||||
assert_eq!(
|
||||
@@ -4383,7 +4383,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (prepare_tx, _prepare_rx) = mpsc::unbounded_channel();
|
||||
let (prepare_tx, _prepare_rx) = crate::peer_event_channel();
|
||||
let (download_status, _download_cancel) = register_test_download(&ctx, &prepare_tx).await;
|
||||
ctx.active_operations
|
||||
.write()
|
||||
@@ -4394,7 +4394,7 @@ mod tests {
|
||||
.await
|
||||
.expect("downloaded game should be installable");
|
||||
let read_guard = ctx.active_operations.read().await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
let install_task = tokio::spawn({
|
||||
let ctx = ctx.clone();
|
||||
@@ -4445,7 +4445,7 @@ mod tests {
|
||||
async fn cancel_download_command_only_cancels_active_token() {
|
||||
let temp = TempDir::new("lanspread-handler-cancel-download");
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let (_status, cancel) = register_test_download(&ctx, &tx).await;
|
||||
ctx.active_operations
|
||||
.write()
|
||||
@@ -4472,7 +4472,7 @@ mod tests {
|
||||
write_file(&root.join("local").join("old.txt"), b"old");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
run_install_operation(&ctx, &tx, operation_target(temp.path())).await;
|
||||
|
||||
@@ -4497,7 +4497,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"old archive");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
run_install_operation(&ctx, &tx, operation_target(temp.path())).await;
|
||||
assert_active_update(
|
||||
@@ -4560,7 +4560,7 @@ mod tests {
|
||||
write_file(&root.join("local").join("old.txt"), b"old");
|
||||
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
run_uninstall_operation(&ctx, &tx, operation_target(temp.path())).await;
|
||||
|
||||
@@ -4592,7 +4592,7 @@ mod tests {
|
||||
&["game.eti"],
|
||||
)
|
||||
.await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
let scan = scan_local_library(temp.path(), ctx.state_dir.as_ref(), catalog)
|
||||
.await
|
||||
@@ -4630,7 +4630,7 @@ mod tests {
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
}
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
// On the current-thread test runtime, this ready lock acquisition does
|
||||
// not yield to the newly spawned command. Move the configured root
|
||||
@@ -4671,7 +4671,7 @@ mod tests {
|
||||
write_file(&root.join("local/payload.txt"), b"installed");
|
||||
}
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
handle_uninstall_game_command(&ctx, &tx, "game".to_string()).await;
|
||||
*ctx.game_dir.write().await = next.path().to_path_buf();
|
||||
@@ -4715,7 +4715,7 @@ mod tests {
|
||||
&["game.eti"],
|
||||
)
|
||||
.await;
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
handle_remove_downloaded_game_command(&ctx, &tx, "game".to_string()).await;
|
||||
*ctx.game_dir.write().await = next.path().to_path_buf();
|
||||
@@ -4757,7 +4757,7 @@ mod tests {
|
||||
.write()
|
||||
.await
|
||||
.insert("game".to_string(), OperationKind::Downloading);
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let error = handle_set_game_dir_command(&ctx, &tx, next.path().to_path_buf())
|
||||
.await
|
||||
@@ -4778,7 +4778,7 @@ mod tests {
|
||||
symlink(current.path(), &alias).expect("same-root alias should be created");
|
||||
let current = std::fs::canonicalize(current.path()).expect("root should canonicalize");
|
||||
let ctx = test_ctx(current.clone());
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let accepted = handle_set_game_dir_command(&ctx, &tx, alias)
|
||||
.await
|
||||
@@ -4801,7 +4801,7 @@ mod tests {
|
||||
let current = std::fs::canonicalize(current.path()).expect("root should canonicalize");
|
||||
let next = std::fs::canonicalize(next.path()).expect("new root should canonicalize");
|
||||
let ctx = test_ctx(current);
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let accepted = handle_set_game_dir_command(&ctx, &tx, alias.clone())
|
||||
.await
|
||||
@@ -4817,7 +4817,7 @@ mod tests {
|
||||
let current = TempDir::new("lanspread-handler-invalid-dir-current");
|
||||
let missing = current.path().join("missing");
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
let error = handle_set_game_dir_command(&ctx, &tx, missing)
|
||||
.await
|
||||
@@ -4837,7 +4837,7 @@ mod tests {
|
||||
let candidate_path =
|
||||
std::fs::canonicalize(candidate.path()).expect("candidate root should canonicalize");
|
||||
let ctx = test_ctx(current_path.clone());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let published = summary("game", "20250101", Availability::Ready);
|
||||
ctx.local_library
|
||||
.write()
|
||||
@@ -4884,7 +4884,7 @@ mod tests {
|
||||
let temp = TempDir::new("lanspread-handler-same-dir");
|
||||
write_file(&temp.game_root().join(".version.ini.tmp"), b"tmp");
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
let first = CancellationToken::new();
|
||||
let second = CancellationToken::new();
|
||||
*ctx.active_outbound_transfers.write().await = HashMap::from([
|
||||
@@ -4936,7 +4936,7 @@ mod tests {
|
||||
let temp = TempDir::new("lanspread-handler-same-dir-timeout");
|
||||
write_file(&temp.game_root().join(".version.ini.tmp"), b"tmp");
|
||||
let ctx = test_ctx(temp.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let token = CancellationToken::new();
|
||||
ctx.active_outbound_transfers
|
||||
.write()
|
||||
@@ -4969,7 +4969,7 @@ mod tests {
|
||||
.write()
|
||||
.await
|
||||
.insert("game".to_string(), OperationKind::Downloading);
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
|
||||
let error = handle_set_game_dir_command(&ctx, &tx, temp.path().to_path_buf())
|
||||
.await
|
||||
@@ -4985,7 +4985,7 @@ mod tests {
|
||||
let next = TempDir::new("lanspread-handler-new-dir");
|
||||
write_file(&next.game_root().join(".version.ini.tmp"), b"tmp");
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, _rx) = mpsc::unbounded_channel();
|
||||
let (tx, _rx) = crate::peer_event_channel();
|
||||
let first = CancellationToken::new();
|
||||
let second = CancellationToken::new();
|
||||
*ctx.active_outbound_transfers.write().await = HashMap::from([
|
||||
@@ -5041,7 +5041,7 @@ mod tests {
|
||||
write_file(&root.join("version.ini"), b"20250101");
|
||||
write_file(&root.join("game.eti"), b"archive");
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
let catalog = ctx.catalog.catalog();
|
||||
let scan = scan_local_library(current.path(), ctx.state_dir.as_ref(), catalog)
|
||||
@@ -5095,7 +5095,7 @@ mod tests {
|
||||
let current = TempDir::new("lanspread-handler-revision-exhausted-current");
|
||||
let next = TempDir::new("lanspread-handler-revision-exhausted-next");
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let published = summary("game", "20250101", Availability::Ready);
|
||||
ctx.local_library
|
||||
.write()
|
||||
@@ -5138,7 +5138,7 @@ mod tests {
|
||||
std::fs::create_dir_all(next_root.join(".version.ini.tmp"))
|
||||
.expect("invalid recovery scratch directory should be created");
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
|
||||
assert_eq!(
|
||||
handle_set_game_dir_command_with_drain_timeout(
|
||||
@@ -5198,7 +5198,7 @@ mod tests {
|
||||
}
|
||||
|
||||
let ctx = test_ctx(current.path().to_path_buf());
|
||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||
let (tx, mut rx) = crate::peer_event_channel();
|
||||
let catalog = ctx.catalog.catalog();
|
||||
let scan = scan_local_library(current.path(), ctx.state_dir.as_ref(), catalog)
|
||||
.await
|
||||
|
||||
Reference in new issue
Block a user