diff --git a/Cargo.lock b/Cargo.lock index 4c53144..5397366 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,7 +1652,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lesavka_client" -version = "0.22.25" +version = "0.22.26" dependencies = [ "anyhow", "async-stream", @@ -1686,7 +1686,7 @@ dependencies = [ [[package]] name = "lesavka_common" -version = "0.22.25" +version = "0.22.26" dependencies = [ "anyhow", "base64", @@ -1698,7 +1698,7 @@ dependencies = [ [[package]] name = "lesavka_server" -version = "0.22.25" +version = "0.22.26" dependencies = [ "anyhow", "base64", diff --git a/client/Cargo.toml b/client/Cargo.toml index b409c26..f328b5e 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -4,7 +4,7 @@ path = "src/main.rs" [package] name = "lesavka_client" -version = "0.22.25" +version = "0.22.26" edition = "2024" [dependencies] diff --git a/common/Cargo.toml b/common/Cargo.toml index 5400362..5580039 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "lesavka_common" -version = "0.22.25" +version = "0.22.26" edition = "2024" build = "build.rs" diff --git a/server/Cargo.toml b/server/Cargo.toml index 850fa89..ac73087 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -10,7 +10,7 @@ bench = false [package] name = "lesavka_server" -version = "0.22.25" +version = "0.22.26" edition = "2024" autobins = false diff --git a/server/src/video_sinks/mjpeg_spool.rs b/server/src/video_sinks/mjpeg_spool.rs index 6318183..7a6b7c2 100644 --- a/server/src/video_sinks/mjpeg_spool.rs +++ b/server/src/video_sinks/mjpeg_spool.rs @@ -8,6 +8,7 @@ use gstreamer as gst; use gstreamer_app as gst_app; static SPOOL_SEQUENCE: AtomicU64 = AtomicU64::new(1); +static SPOOL_TEMP_SEQUENCE: AtomicU64 = AtomicU64::new(1); #[derive(Clone, Copy)] pub(super) struct MjpegSpoolTiming { @@ -226,7 +227,11 @@ pub(super) fn spool_mjpeg_frame_with_timing( if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } - let tmp = path.with_extension(format!("mjpg.{}.tmp", std::process::id())); + let tmp = path.with_extension(format!( + "mjpg.{}.{}.tmp", + std::process::id(), + SPOOL_TEMP_SEQUENCE.fetch_add(1, Ordering::Relaxed) + )); fs::write(&tmp, data)?; fs::rename(&tmp, path)?; diff --git a/tests/integration/server/video_sinks/hevc_mjpeg_spool_integration.rs b/tests/integration/server/video_sinks/hevc_mjpeg_spool_integration.rs index 9284436..97b440d 100644 --- a/tests/integration/server/video_sinks/hevc_mjpeg_spool_integration.rs +++ b/tests/integration/server/video_sinks/hevc_mjpeg_spool_integration.rs @@ -101,3 +101,17 @@ fn mjpeg_passthrough_spool_keeps_decode_timing_null() { assert!(sidecar_text.contains("\"source_pts_us\":55000")); assert!(sidecar_text.contains("\"decoded_pts_us\":null")); } + +#[test] +fn mjpeg_spool_uses_unique_temporary_paths_per_publish() { + let source = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/server/src/video_sinks/mjpeg_spool.rs" + )); + + assert!(source.contains("static SPOOL_TEMP_SEQUENCE")); + assert!( + source.contains("SPOOL_TEMP_SEQUENCE.fetch_add(1, Ordering::Relaxed)"), + "shared MJPEG spool writers must not reuse a single process-wide temp path" + ); +}