iris-chat 0.1.31

Iris Chat command line client and shared encrypted chat core
Documentation
use super::*;

pub(super) fn preferred_manifest_asset(
    manifest: &ReleaseManifest,
    request: &UpdateRequest,
) -> Option<ReleaseAsset> {
    match request.mode {
        UpdateMode::Cli => {
            preferred_cli_asset(&manifest.assets, &manifest.tag, request.preferred_kind())
        }
        UpdateMode::App => preferred_app_asset(&manifest.assets),
    }
}

pub(super) fn preferred_secure_asset(
    manifest: &UpdateManifest,
    request: &UpdateRequest,
) -> Option<UpdateAsset> {
    match request.mode {
        UpdateMode::Cli => preferred_secure_cli_asset(manifest, request.preferred_kind()),
        UpdateMode::App => preferred_secure_app_asset(manifest),
    }
}

pub(super) fn preferred_cli_asset(
    assets: &[ReleaseAsset],
    tag: &str,
    kind: Option<&str>,
) -> Option<ReleaseAsset> {
    if let Some(kind) = kind.filter(|value| !value.trim().is_empty()) {
        if let Some(asset) = assets.iter().find(|asset| asset.name.contains(kind)) {
            return Some(asset.clone());
        }
    }

    let target = current_target();
    let archive_ext = if cfg!(target_os = "windows") {
        ".zip"
    } else {
        ".tar.gz"
    };
    let exact = format!("iris-{tag}-{target}{archive_ext}");
    let unversioned = format!("iris-{target}{archive_ext}");
    assets
        .iter()
        .find(|asset| asset.name == exact)
        .or_else(|| assets.iter().find(|asset| asset.name == unversioned))
        .or_else(|| {
            assets.iter().find(|asset| {
                asset.name.starts_with("iris-")
                    && asset.name.contains(target)
                    && asset.name.ends_with(archive_ext)
            })
        })
        .cloned()
}

pub(super) fn preferred_secure_cli_asset(
    manifest: &UpdateManifest,
    kind: Option<&str>,
) -> Option<UpdateAsset> {
    if let Some(kind) = kind.filter(|value| !value.trim().is_empty()) {
        if let Some(asset) = manifest
            .assets
            .iter()
            .find(|asset| asset.name.contains(kind))
        {
            return Some(asset.clone());
        }
    }

    let tag = display_manifest_tag(manifest);
    let target = current_target();
    let archive_ext = if cfg!(target_os = "windows") {
        ".zip"
    } else {
        ".tar.gz"
    };
    let exact = format!("iris-{tag}-{target}{archive_ext}");
    let unversioned = format!("iris-{target}{archive_ext}");
    manifest
        .assets
        .iter()
        .find(|asset| asset.name == exact)
        .or_else(|| {
            manifest
                .assets
                .iter()
                .find(|asset| asset.name == unversioned)
        })
        .or_else(|| {
            manifest.assets.iter().find(|asset| {
                asset.name.starts_with("iris-")
                    && asset.name.contains(target)
                    && asset.name.ends_with(archive_ext)
            })
        })
        .cloned()
}

pub(super) fn preferred_app_asset(assets: &[ReleaseAsset]) -> Option<ReleaseAsset> {
    assets
        .iter()
        .find(|asset| app_asset_name_matches_current_target(&asset.name))
        .cloned()
}

pub(super) fn preferred_secure_app_asset(manifest: &UpdateManifest) -> Option<UpdateAsset> {
    manifest
        .assets
        .iter()
        .find(|asset| app_asset_name_matches_current_target(&asset.name))
        .cloned()
}

pub(super) fn app_asset_name_matches_current_target(name: &str) -> bool {
    let lower = name.to_ascii_lowercase();
    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
    {
        lower.ends_with("-macos-arm64.app.tar.gz")
            || lower.ends_with("-macos-arm64.dmg")
            || lower.ends_with("-macos-arm64.zip")
    }
    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    {
        lower.ends_with("-linux-x64.deb") || lower.ends_with("-linux-x64.tar.gz")
    }
    #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
    {
        lower.ends_with("-linux-arm64.deb") || lower.ends_with("-linux-arm64.tar.gz")
    }
    #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
    {
        lower.ends_with("-windows-x64-setup.exe")
    }
    #[cfg(not(any(
        all(target_os = "macos", target_arch = "aarch64"),
        all(target_os = "linux", target_arch = "x86_64"),
        all(target_os = "linux", target_arch = "aarch64"),
        all(target_os = "windows", target_arch = "x86_64"),
    )))]
    {
        let _ = lower;
        false
    }
}

pub(super) fn display_manifest_tag(manifest: &UpdateManifest) -> String {
    manifest
        .tag
        .clone()
        .filter(|tag| !tag.trim().is_empty())
        .unwrap_or_else(|| format!("v{}", manifest.effective_version()))
}

pub(super) fn current_target() -> &'static str {
    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
    {
        "aarch64-apple-darwin"
    }
    #[cfg(all(target_os = "macos", target_arch = "x86_64"))]
    {
        "x86_64-apple-darwin"
    }
    #[cfg(all(target_os = "linux", target_arch = "x86_64"))]
    {
        "x86_64-unknown-linux-gnu"
    }
    #[cfg(all(target_os = "linux", target_arch = "aarch64"))]
    {
        "aarch64-unknown-linux-gnu"
    }
    #[cfg(all(target_os = "windows", target_arch = "x86_64"))]
    {
        "x86_64-pc-windows-msvc"
    }
    #[cfg(not(any(
        all(target_os = "macos", target_arch = "aarch64"),
        all(target_os = "macos", target_arch = "x86_64"),
        all(target_os = "linux", target_arch = "x86_64"),
        all(target_os = "linux", target_arch = "aarch64"),
        all(target_os = "windows", target_arch = "x86_64"),
    )))]
    {
        "unsupported"
    }
}

pub(super) fn manifest_asset_url(manifest_url: &str, path: &str) -> String {
    if path.starts_with("http://") || path.starts_with("https://") || path.starts_with("file://") {
        return path.to_string();
    }
    let base = manifest_url
        .rsplit_once('/')
        .map(|(base, _)| base)
        .unwrap_or(manifest_url);
    format!("{}/{}", base, path.trim_start_matches('/'))
}