tauri-plugin-video 0.3.0

Native video playback for Tauri using platform media engines
Documentation
use tauri::{command, AppHandle, Runtime};

use crate::{models::*, Error, Result, VideoExt};

#[command]
pub(crate) fn native_diagnostics() -> NativePluginDiagnostics {
    NativePluginDiagnostics::current()
}

#[command]
pub(crate) async fn native_open<R: Runtime>(
    app: AppHandle<R>,
    payload: NativeOpenRequest,
) -> Result<NativePlaybackSnapshot> {
    require_native_protocol(payload.protocol_version, payload.package_version.as_deref())?;
    #[cfg(mobile)]
    {
        return app.video().mobile().open_native(payload);
    }
    #[cfg(desktop)]
    {
        app.video().desktop().open_native(payload)
    }
}

fn require_native_protocol(actual: Option<u32>, package_version: Option<&str>) -> Result<()> {
    let package_version = package_version.filter(|version| !version.trim().is_empty());
    if actual == Some(VIDEO_PLUGIN_PROTOCOL_VERSION) && package_version.is_some() {
        return Ok(());
    }
    Err(Error::ProtocolMismatch {
        expected: VIDEO_PLUGIN_PROTOCOL_VERSION,
        actual,
        package_version: package_version.map(str::to_owned),
    })
}

#[command]
pub(crate) async fn native_control<R: Runtime>(
    app: AppHandle<R>,
    payload: NativeControlRequest,
) -> Result<NativePlaybackSnapshot> {
    #[cfg(mobile)]
    {
        return app.video().mobile().control_native(payload);
    }
    #[cfg(desktop)]
    {
        app.video().desktop().control_native(payload)
    }
}

#[command]
pub(crate) async fn native_layout<R: Runtime>(
    app: AppHandle<R>,
    payload: NativeLayoutRequest,
) -> Result<()> {
    #[cfg(mobile)]
    {
        return app.video().mobile().layout_native(payload);
    }
    #[cfg(desktop)]
    {
        app.video().desktop().layout_native(payload)
    }
}

#[command]
pub(crate) async fn native_stats<R: Runtime>(
    app: AppHandle<R>,
    payload: NativeSessionRequest,
) -> Result<NativePlaybackSnapshot> {
    #[cfg(mobile)]
    {
        return app.video().mobile().stats_native(payload);
    }
    #[cfg(desktop)]
    {
        app.video().desktop().stats_native(payload)
    }
}

#[command]
pub(crate) async fn native_close<R: Runtime>(
    app: AppHandle<R>,
    payload: NativeSessionRequest,
) -> Result<()> {
    #[cfg(mobile)]
    {
        return app.video().mobile().close_native(payload);
    }
    #[cfg(desktop)]
    {
        app.video().desktop().close_native(payload)
    }
}

#[cfg(test)]
mod tests {
    use crate::{Error, VIDEO_PLUGIN_PROTOCOL_VERSION};

    #[test]
    fn native_diagnostics_command_reports_the_current_contract() {
        let diagnostics = super::native_diagnostics();

        assert_eq!(diagnostics.protocol_version, VIDEO_PLUGIN_PROTOCOL_VERSION);
        assert_eq!(diagnostics.crate_name, env!("CARGO_PKG_NAME"));
        assert_eq!(diagnostics.crate_version, env!("CARGO_PKG_VERSION"));
    }

    #[test]
    fn native_open_requires_the_current_protocol() {
        assert!(
            super::require_native_protocol(Some(VIDEO_PLUGIN_PROTOCOL_VERSION), Some("0.2.0"),)
                .is_ok()
        );

        for (actual, package_version) in [
            (None, Some("legacy-test-version")),
            (
                Some(VIDEO_PLUGIN_PROTOCOL_VERSION + 1),
                Some("future-test-version"),
            ),
            (Some(VIDEO_PLUGIN_PROTOCOL_VERSION), None),
            (Some(VIDEO_PLUGIN_PROTOCOL_VERSION), Some("")),
        ] {
            let error = super::require_native_protocol(actual, package_version)
                .expect_err("missing metadata or an unequal protocol must fail");
            assert_eq!(error.code(), "PROTOCOL_MISMATCH");
            match error {
                Error::ProtocolMismatch {
                    expected,
                    actual: received,
                    package_version: received_package,
                } => {
                    assert_eq!(expected, VIDEO_PLUGIN_PROTOCOL_VERSION);
                    assert_eq!(received, actual);
                    assert_eq!(
                        received_package.as_deref(),
                        package_version.filter(|version| !version.trim().is_empty()),
                    );
                }
                other => panic!("expected a protocol mismatch, received {other}"),
            }
        }
    }
}