sendmer 0.5.1

A cli tool to send directories over the network, with NAT hole punching
Documentation
$ErrorActionPreference = "Stop"

$Repo = "bruceblink/sendmer"
$Bin = "sendmer"

# 允许用户指定版本
$Version = $env:SENDMER_VERSION

if (-not $Version) {
    Write-Host "Fetching latest release version..."
    $Api = "https://api.github.com/repos/$Repo/releases/latest"
    $Response = Invoke-RestMethod -Uri $Api -Headers @{
        "User-Agent" = "sendmer-installer"
    }
    $Version = $Response.tag_name
}

if ($Version -notmatch '^v\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$') {
    throw "Invalid release version: $Version"
}

# 架构检测
$Arch = if ([Environment]::Is64BitOperatingSystem) {
    "x86_64"
} else {
    Write-Error "32-bit Windows is not supported"
}

$InstallDir = "$env:USERPROFILE\.sendmer\bin"
$ZipName = "$Bin-$Version-$Arch-pc-windows-msvc.zip"
$TempRoot = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath())
$TempDir = [System.IO.Path]::GetFullPath((Join-Path $TempRoot (
            "sendmer-install-{0}" -f [Guid]::NewGuid().ToString("N")
        )))
if (-not $TempDir.StartsWith($TempRoot, [System.StringComparison]::OrdinalIgnoreCase)) {
    throw "Refusing to create installer files outside the system temp directory"
}

$ZipPath = Join-Path $TempDir $ZipName
$Url = "https://github.com/$Repo/releases/download/$Version/$ZipName"
$ChecksumPath = "$ZipPath.sha256"
$ChecksumUrl = "$Url.sha256"

Write-Host "Installing sendmer $Version"
Write-Host "Downloading $Url"

try {
    New-Item -ItemType Directory -Path $TempDir | Out-Null
    Invoke-WebRequest $Url -OutFile $ZipPath
    Invoke-WebRequest $ChecksumUrl -OutFile $ChecksumPath

    $ChecksumFields = @((Get-Content -Raw -LiteralPath $ChecksumPath).Trim() -split '\s+')
    $ExpectedHash = $ChecksumFields[0].ToLowerInvariant()
    $ExpectedFile = if ($ChecksumFields.Count -gt 1) { $ChecksumFields[1] } else { "" }
    if ($ExpectedHash -notmatch '^[0-9a-f]{64}$' -or $ExpectedFile -ne $ZipName) {
        throw "Invalid checksum file for $ZipName"
    }

    $ActualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $ZipPath).Hash.ToLowerInvariant()
    if ($ActualHash -ne $ExpectedHash) {
        throw "Checksum verification failed for $ZipName"
    }

    Write-Host "Extracting..."
    New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
    Expand-Archive -Path $ZipPath -DestinationPath $InstallDir -Force

    $ExePath = Join-Path $InstallDir "$Bin.exe"
    if (-not (Test-Path $ExePath)) {
        Write-Error "sendmer.exe not found after extraction"
    }
}
finally {
    # Every install attempt owns one isolated directory, so failure cleanup cannot clash.
    Remove-Item -LiteralPath $TempDir -Recurse -Force -ErrorAction SilentlyContinue
}

# 添加到 PATH(用户级)
$UserPath = [Environment]::GetEnvironmentVariable("PATH", "User")
if ($UserPath -notlike "*$InstallDir*") {
    Write-Host "Adding sendmer to PATH"
    [Environment]::SetEnvironmentVariable(
            "PATH",
            "$UserPath;$InstallDir",
            "User"
    )
}

Write-Host ""
Write-Host "sendmer $Version installed successfully!"
Write-Host "Restart your terminal and run:"
Write-Host "  sendmer --help"