Files
tuliprox/shared/src/model/stream_probe_failure.rs
T
euzuandGitHub 99e5044599 Feature/refactor (#848)
* **New Features**
  * Added HLS live and catch-up playback for archived streams, manifests, segments, and provider failover.
  * Improved playlist processing with filtering, renaming, mapping, EPG handling, favourites, watch groups, staged overlays, and disk-based processing.
* **Documentation**
  * Added guidance for environment variables, credentials, password hashes, and authentication secrets.
* **Changes**
  * Removed target editing from the target menu; refresh and delete remain available.
* **Bug Fixes**
  * Improved recovery when cached playlist data is unreadable and strengthened archive stream URL handling.
2026-08-31 01:20:31 +02:00

71 lines
2.8 KiB
Rust

//! A stream probe that did not come back with metadata.
//!
//! Failed `ffprobe` outcomes are persisted and published so notification
//! subscribers can alert operators when a provider stream becomes unavailable.
//!
//! # Why there is no success variant
//!
//! A metadata run probes every stream it does not already know about, so a
//! success event would fire thousands of times per refresh and carry news
//! nobody asked for. The failure is the occurrence; the success is the
//! expected case.
use serde::{Deserialize, Serialize};
use std::sync::Arc;
/// Why a probe produced no metadata.
///
/// Mirrors the actionable half of
/// `tuliprox_core::utils::ffmpeg::ProbeFailureKind`. Its `Cancelled` variant
/// has no counterpart here on purpose: a cancelled probe is a shutdown or a
/// preemption, not a statement about the stream, and reporting it as a
/// failure would teach subscribers to act on server lifecycle noise.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StreamProbeFailureReason {
/// The provider answered, with a 404.
NotFound,
/// The probe failed or timed out.
Unreachable,
}
/// One stream failed to probe.
///
/// # Redaction
///
/// `url` must be passed through
/// [`sanitize_sensitive_info`](crate::utils::sanitize_sensitive_info) by the
/// emitter: a provider stream URL carries the account username and password
/// in its path or query, and this record is rendered into notification
/// channels. The field is documented rather than typed as pre-sanitized
/// because the sanitizer is configuration-dependent, and a newtype implying
/// a guarantee the emitter may not have honoured would be worse than a
/// contract stated once.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StreamProbeFailure {
/// The input whose stream this is.
pub input: Arc<str>,
/// The stream's id within that input, for correlating with the store.
pub unique_id: Arc<str>,
/// The probed URL, already sanitized. See the note above.
pub url: Arc<str>,
pub reason: StreamProbeFailureReason,
}
impl StreamProbeFailure {
#[must_use]
pub fn new(input: Arc<str>, unique_id: Arc<str>, url: Arc<str>, reason: StreamProbeFailureReason) -> Self {
Self { input, unique_id, url, reason }
}
/// Deliberately per *input*, not per stream.
///
/// When a provider goes down, every stream behind it fails in the same
/// run. An operator wants to hear "this input is failing" once; a
/// per-stream key would deliver one notification per channel and bury
/// the signal. Plugins still see every event on the bus — this only
/// bounds what reaches a phone.
#[must_use]
pub fn dedup_key(&self) -> String { format!("stream-probe:{}", self.input) }
}