refactor(peer): centralize game root path policy
Game scanning, manifest validation, install recovery, migration, and download cleanup each carried their own spellings and case rules for reserved entries. Those copies had already diverged, which made it possible for one subsystem to accept or expose a path that another treated as application-owned state. Introduce one game_paths module for the canonical names and conservative portable comparison policy. Keep context-specific predicates for manifest and scanner protection versus cancellation preservation: cancellation still sweeps its own version transaction scratch files, while install and migration state survive. Reuse the constants for all production path construction sites. Test Plan: - `just test` -- passed (175 lanspread-peer tests and full workspace) - `just clippy` -- passed - `just fmt` -- Rust, TOML, and Prettier completed; the recipe remains blocked by 39 pre-existing rumdl issues in five unrelated Markdown files - `git diff --cached --check` -- passed
This commit is contained in:
13 files changed
+198
-129
No files matched your search
@@ -14,13 +14,9 @@ use crate::{
|
||||
PeerEvent,
|
||||
config::LOCAL_GAME_FALLBACK_SCAN_SECS,
|
||||
context::Ctx,
|
||||
game_paths::{is_download_protected_root_name, is_ignored_games_root_name},
|
||||
handlers::update_and_announce_games,
|
||||
local_games::{
|
||||
is_ignored_game_root_name,
|
||||
is_local_dir_name,
|
||||
rescan_local_game,
|
||||
scan_local_library,
|
||||
},
|
||||
local_games::{rescan_local_game, scan_local_library},
|
||||
};
|
||||
|
||||
struct WatchState {
|
||||
@@ -197,7 +193,7 @@ async fn list_game_roots(game_dir: &Path) -> eyre::Result<Vec<PathBuf>> {
|
||||
let Some(name) = entry.file_name().to_str().map(ToOwned::to_owned) else {
|
||||
continue;
|
||||
};
|
||||
if is_ignored_game_root_name(&name) {
|
||||
if is_ignored_games_root_name(&name) {
|
||||
continue;
|
||||
}
|
||||
roots.push(entry.path());
|
||||
@@ -303,7 +299,7 @@ fn game_id_from_event_path(game_dir: &Path, path: &Path) -> Option<String> {
|
||||
let relative = path.strip_prefix(game_dir).ok()?;
|
||||
let mut components = relative.components();
|
||||
let game_id = component_name(components.next()?)?;
|
||||
if is_ignored_game_root_name(game_id) {
|
||||
if is_ignored_games_root_name(game_id) {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -324,13 +320,7 @@ fn component_name(component: Component<'_>) -> Option<&str> {
|
||||
}
|
||||
|
||||
fn should_ignore_game_child(name: &str) -> bool {
|
||||
is_local_dir_name(name)
|
||||
|| name.starts_with(".local.")
|
||||
|| name.starts_with(".version.ini.")
|
||||
|| name == ".lanspread"
|
||||
|| name == ".lanspread.json"
|
||||
|| name == ".sync"
|
||||
|| name == ".softlan_game_installed"
|
||||
is_download_protected_root_name(name)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -12,7 +12,8 @@ use crate::{
|
||||
context::PeerCtx,
|
||||
error::PeerError,
|
||||
events,
|
||||
local_games::{get_game_file_descriptions, is_local_dir_name, local_download_matches_catalog},
|
||||
game_paths::is_local_dir_name,
|
||||
local_games::{get_game_file_descriptions, local_download_matches_catalog},
|
||||
peer::{send_game_file_chunk, send_game_file_data},
|
||||
services::handshake::{HandshakeCtx, accept_inbound_hello, spawn_library_resync},
|
||||
stream_install::{send_game_install_stream, send_stream_install_error},
|
||||
|
||||
Reference in new issue
Block a user