Initial release

This commit is contained in:
Jake
2026-05-11 19:29:55 +01:00
commit d4d1215874
16967 changed files with 4075897 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
@echo off
setlocal
where pwsh >nul 2>nul
if %errorlevel%==0 (
pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0install_runtime.ps1" %*
) else (
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0install_runtime.ps1" %*
)
set "EXIT_CODE=%ERRORLEVEL%"
endlocal & exit /b %EXIT_CODE%

View File

@@ -0,0 +1,456 @@
param(
[string]$PackageDir = "",
[string]$PluginDir = "",
[string]$PluginCacheDir = "",
[string]$DistroName = "",
[string]$InstallDir = "",
[switch]$ReplaceExisting,
[switch]$SkipCopyToPluginDir
)
$ErrorActionPreference = 'Stop'
function Get-ScriptDir {
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
return $PSScriptRoot
}
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
return (Split-Path -Parent $PSCommandPath)
}
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
}
return (Get-Location).Path
}
function Convert-FileToLf([string]$Path) {
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
return
}
$content = [System.IO.File]::ReadAllText($Path)
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText($Path, $content, $utf8NoBom)
}
function Copy-IfExists([string]$Source, [string]$Destination) {
if (Test-Path $Source) {
$srcFull = [System.IO.Path]::GetFullPath($Source)
$dstFull = [System.IO.Path]::GetFullPath($Destination)
if ($srcFull -ieq $dstFull) {
return
}
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $Destination) | Out-Null
Copy-Item -Force $Source $Destination
}
}
function Sync-Directory([string]$SourceDir, [string]$DestinationDir) {
if (!(Test-Path $SourceDir)) {
return
}
if (Test-Path $DestinationDir) {
Remove-Item -Recurse -Force $DestinationDir
}
New-Item -ItemType Directory -Force -Path $DestinationDir | Out-Null
Copy-Item -Recurse -Force (Join-Path $SourceDir '*') $DestinationDir
}
function Resolve-DistroName([string]$Dir, [string]$Current) {
if (-not [string]::IsNullOrWhiteSpace($Current)) {
return $Current
}
$distroFile = Join-Path $Dir 'pjarczak_wsl_distro.txt'
if (Test-Path $distroFile) {
$value = (Get-Content $distroFile -Raw).Trim()
if (-not [string]::IsNullOrWhiteSpace($value)) {
return $value
}
}
if ($env:PJARCZAK_WSL_DISTRO) {
return $env:PJARCZAK_WSL_DISTRO.Trim()
}
return 'PJARCZAK-BAMBU'
}
function Get-FileSha256([string]$Path) {
return (Get-FileHash -Algorithm SHA256 -Path $Path).Hash.ToLowerInvariant()
}
function Get-RootFsHashMarkerPath([string]$Dir) {
return (Join-Path $Dir 'pjarczak-rootfs-sha256.txt')
}
function Write-RootFsHashMarker([string]$Dir, [string]$Hash) {
if ([string]::IsNullOrWhiteSpace($Dir) -or [string]::IsNullOrWhiteSpace($Hash)) {
return
}
New-Item -ItemType Directory -Force -Path $Dir | Out-Null
Set-Content -Path (Get-RootFsHashMarkerPath $Dir) -Value ($Hash.Trim().ToLowerInvariant()) -NoNewline
}
function Read-RootFsHashMarker([string]$Dir) {
$path = Get-RootFsHashMarkerPath $Dir
if (!(Test-Path $path)) {
return ''
}
return ((Get-Content $path -Raw).Trim().ToLowerInvariant())
}
function Resolve-PluginCacheDir([string]$Dir, [string]$Current) {
if (-not [string]::IsNullOrWhiteSpace($Current)) {
return [System.IO.Path]::GetFullPath($Current.Trim())
}
if ($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR) {
return [System.IO.Path]::GetFullPath($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR.Trim())
}
$subdirFile = Join-Path $Dir 'pjarczak_plugin_cache_subdir.txt'
if (Test-Path $subdirFile) {
$subdir = (Get-Content $subdirFile -Raw).Trim()
if (-not [string]::IsNullOrWhiteSpace($subdir)) {
if (-not $env:APPDATA) { throw 'APPDATA is not available' }
return [System.IO.Path]::GetFullPath((Join-Path $env:APPDATA $subdir))
}
}
if (-not $env:APPDATA) { throw 'APPDATA is not available' }
return [System.IO.Path]::GetFullPath((Join-Path $env:APPDATA 'OrcaSlicer\ota\plugins'))
}
function Normalize-PluginCacheDir([string]$Path) {
if ([string]::IsNullOrWhiteSpace($Path)) {
return $Path
}
$full = [System.IO.Path]::GetFullPath($Path)
$pluginsChild = Join-Path $full 'plugins'
if ((Split-Path -Leaf $full) -ieq 'ota' -and (Test-Path $pluginsChild)) {
return [System.IO.Path]::GetFullPath($pluginsChild)
}
if ((Test-Path $pluginsChild) -and !(Test-Path (Join-Path $full 'libbambu_networking.so')) -and !(Test-Path (Join-Path $full 'libBambuSource.so'))) {
return [System.IO.Path]::GetFullPath($pluginsChild)
}
return $full
}
function Read-TextAuto([string]$Path) {
if (!(Test-Path $Path)) {
return ''
}
$bytes = [System.IO.File]::ReadAllBytes($Path)
if ($bytes.Length -eq 0) {
return ''
}
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
return ([System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
}
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
return ([System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
}
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
return ([System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) -replace "`0", '')
}
for ($i = 1; $i -lt [Math]::Min($bytes.Length, 64); $i += 2) {
if ($bytes[$i] -eq 0) {
return ([System.Text.Encoding]::Unicode.GetString($bytes) -replace "`0", '')
}
}
return ([System.Text.Encoding]::UTF8.GetString($bytes) -replace "`0", '')
}
function Normalize-NativeText([string]$Text) {
if ([string]::IsNullOrEmpty($Text)) {
return ''
}
$value = $Text -replace "`0", ''
$value = $value -replace "`r`n", "`n"
$value = $value -replace "`r", "`n"
return $value
}
function Invoke-NativeCapture([string]$FilePath, [string[]]$ArgumentList) {
$stdoutPath = [System.IO.Path]::GetTempFileName()
$stderrPath = [System.IO.Path]::GetTempFileName()
try {
$proc = Start-Process -FilePath $FilePath -ArgumentList $ArgumentList -Wait -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -WindowStyle Hidden
$stdoutText = if (Test-Path $stdoutPath) { Normalize-NativeText (Read-TextAuto $stdoutPath) } else { '' }
$stderrText = if (Test-Path $stderrPath) { Normalize-NativeText (Read-TextAuto $stderrPath) } else { '' }
$combined = (($stdoutText + "`n" + $stderrText).Trim())
return @{
ExitCode = $proc.ExitCode
StdOut = $stdoutText
StdErr = $stderrText
Combined = $combined
}
} finally {
Remove-Item -Force -ErrorAction SilentlyContinue $stdoutPath, $stderrPath
}
}
function Test-WslDistroExists([string]$WslPath, [string]$Name, [ref]$Reason) {
$list = Invoke-NativeCapture $WslPath @('--list', '--quiet')
if ($list.ExitCode -ne 0) {
$text = $list.Combined
if ([string]::IsNullOrWhiteSpace($text)) {
throw 'Failed to query WSL distributions'
}
throw ("Failed to query WSL distributions: {0}" -f $text)
}
$exists = $false
foreach ($line in ($list.StdOut -split "`n")) {
$item = $line.Trim()
if ([string]::IsNullOrWhiteSpace($item)) {
continue
}
if ($item -ieq $Name) {
$exists = $true
break
}
}
if (-not $exists) {
$Reason.Value = "WSL distro '$Name' is not installed"
return $false
}
$probe = Invoke-NativeCapture $WslPath @('-d', $Name, '--user', 'root', '--', 'sh', '-lc', 'true')
if ($probe.ExitCode -eq 0) {
$Reason.Value = ''
return $true
}
$text = $probe.Combined
if ([string]::IsNullOrWhiteSpace($text)) {
throw "Failed to start WSL distro '$Name'"
}
throw ("Failed to start WSL distro '{0}': {1}" -f $Name, $text)
}
$scriptDir = Get-ScriptDir
$defaultPackageDir = $scriptDir
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
$PackageDir = $defaultPackageDir
}
$PackageDir = [System.IO.Path]::GetFullPath($PackageDir)
$DistroName = Resolve-DistroName $PackageDir $DistroName
$PluginCacheDir = Normalize-PluginCacheDir (Resolve-PluginCacheDir $PackageDir $PluginCacheDir)
if ([string]::IsNullOrWhiteSpace($PluginDir)) {
if (-not $env:APPDATA) {
throw 'APPDATA is not available'
}
$PluginDir = Join-Path $env:APPDATA 'OrcaSlicer\plugins'
}
$PluginDir = [System.IO.Path]::GetFullPath($PluginDir)
if ([string]::IsNullOrWhiteSpace($InstallDir)) {
if (-not $env:LOCALAPPDATA) {
throw 'LOCALAPPDATA is not available'
}
$InstallDir = Join-Path $env:LOCALAPPDATA $DistroName
}
$InstallDir = [System.IO.Path]::GetFullPath($InstallDir)
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
if (!(Test-Path $wsl)) {
throw 'wsl.exe not found'
}
if (-not $SkipCopyToPluginDir) {
New-Item -ItemType Directory -Force -Path $PluginDir | Out-Null
$fileNames = @(
'pjarczak_bambu_networking_bridge.dll',
'pjarczak_bambu_linux_host',
'pjarczak_bambu_linux_host_abi1',
'pjarczak_bambu_linux_host_abi0',
'pjarczak_wsl_distro.txt',
'pjarczak_plugin_cache_subdir.txt',
'pjarczak_wsl_run_host.sh',
'pjarczak-wsl-run-host.sh',
'install_runtime.ps1',
'install_runtime.cmd',
'verify_runtime.ps1',
'windows-wsl2-rootfs.tar',
'README_runtime_bridge.txt',
'assemble_windows_runtime_bundle.ps1',
'linux_payload_manifest.json',
'libbambu_networking.so',
'libBambuSource.so',
'liblive555.so',
'libagora_rtc_sdk.so',
'libagora-fdkaac.so',
'ca-certificates.crt',
'slicer_base64.cer'
)
foreach ($name in $fileNames) {
Copy-IfExists (Join-Path $PackageDir $name) (Join-Path $PluginDir $name)
}
Get-ChildItem -Path $PackageDir -File -ErrorAction SilentlyContinue | ForEach-Object {
$name = $_.Name
if ($name -match '^lib.+\.so(\..+)?$') {
Copy-IfExists $_.FullName (Join-Path $PluginDir $name)
}
}
$legacyRuntimeDir = Join-Path $PluginDir 'pjarczak_bambu_linux_host.runtime'
if (Test-Path $legacyRuntimeDir) {
Remove-Item -Recurse -Force $legacyRuntimeDir
}
$PackageDir = $PluginDir
Write-Host "Bridge package dir: $PackageDir"
Write-Host "Plugin dir: $PluginDir"
Write-Host "Plugin cache dir: $PluginCacheDir"
Write-Host "WSL distro: $DistroName"
}
$requiredFiles = @(
'pjarczak_bambu_networking_bridge.dll',
'pjarczak_bambu_linux_host',
'pjarczak_bambu_linux_host_abi1',
'pjarczak_bambu_linux_host_abi0',
'pjarczak_wsl_distro.txt',
'install_runtime.ps1',
'verify_runtime.ps1',
'windows-wsl2-rootfs.tar',
'ca-certificates.crt',
'slicer_base64.cer'
)
foreach ($name in $requiredFiles) {
$path = Join-Path $PackageDir $name
if (!(Test-Path $path)) {
throw "Missing package file: $name"
}
}
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
if (!(Test-Path $bootstrapPath)) {
throw 'Missing package file: pjarczak_wsl_run_host.sh'
}
try {
& $wsl --status | Out-Null
} catch {
throw 'WSL is not ready. Run as Administrator once and enable Microsoft-Windows-Subsystem-Linux and VirtualMachinePlatform, then reboot.'
}
Convert-FileToLf $bootstrapPath
$rootFsTar = Join-Path $PackageDir 'windows-wsl2-rootfs.tar'
$currentRootFsHash = Get-FileSha256 $rootFsTar
$storedRootFsHash = Read-RootFsHashMarker $InstallDir
$distroReason = ''
$alreadyInstalled = Test-WslDistroExists $wsl $DistroName ([ref]$distroReason)
if ($alreadyInstalled) {
if (-not $ReplaceExisting) {
if ([string]::IsNullOrWhiteSpace($storedRootFsHash) -or $storedRootFsHash -ne $currentRootFsHash) {
Write-Host "WSL rootfs changed or marker missing - reinstalling distro $DistroName"
$ReplaceExisting = $true
}
}
if ($ReplaceExisting) {
& $wsl --terminate $DistroName 2>$null | Out-Null
& $wsl --unregister $DistroName
if ($LASTEXITCODE -ne 0) {
throw "Failed to unregister existing distro '$DistroName'"
}
$alreadyInstalled = $null
}
}
if (-not $alreadyInstalled) {
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
& $wsl --import $DistroName $InstallDir $rootFsTar --version 2
if ($LASTEXITCODE -ne 0) {
throw "wsl --import failed for distro '$DistroName'"
}
$wslConf = @'
[automount]
enabled=true
root=/mnt/
mountFsTab=false
[interop]
enabled=true
appendWindowsPath=false
'@
$setupCmd = @"
cat > /etc/wsl.conf <<'WSL_EOF'
$wslConf
WSL_EOF
mkdir -p /root/.pjarczak-bambu-runtime
"@
& $wsl -d $DistroName --user root -- sh -lc $setupCmd
if ($LASTEXITCODE -ne 0) {
throw "Failed to initialize distro '$DistroName'"
}
& $wsl --terminate $DistroName
if ($LASTEXITCODE -ne 0) {
throw "Failed to terminate distro '$DistroName' after initialization"
}
Write-RootFsHashMarker $InstallDir $currentRootFsHash
} elseif ($storedRootFsHash -ne $currentRootFsHash) {
Write-RootFsHashMarker $InstallDir $currentRootFsHash
}
$verifyArgs = @(
'-NoProfile',
'-ExecutionPolicy', 'Bypass',
'-File', (Join-Path $PackageDir 'verify_runtime.ps1'),
'-PackageDir', $PackageDir,
'-DistroName', $DistroName,
'-PluginCacheDir', $PluginCacheDir,
'-AllowMissingLinuxPlugin',
'-SkipProbe'
)
$verifyShell = $null
$pwshCmd = Get-Command pwsh -ErrorAction SilentlyContinue
if ($pwshCmd) {
$verifyShell = $pwshCmd.Source
} else {
$powershellCmd = Get-Command powershell -ErrorAction SilentlyContinue
if ($powershellCmd) {
$verifyShell = $powershellCmd.Source
}
}
if ([string]::IsNullOrWhiteSpace($verifyShell)) {
throw 'No PowerShell host found to run verify_runtime.ps1'
}
& $verifyShell @verifyArgs
if ($LASTEXITCODE -ne 0) {
throw 'verify_runtime.ps1 failed'
}
Write-Host ''
Write-Host "WSL runtime installed to: $PackageDir"
Write-Host "WSL distro: $DistroName"
Write-Host "WSL install dir: $InstallDir"
Write-Host 'Now start OrcaSlicer.'

View File

@@ -0,0 +1,61 @@
#!/bin/sh
set -eu
DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
CACHE_FILE="$DIR/.selected_host_abi"
run_probe() {
bin="$1"
[ -x "$bin" ] || return 1
LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
PJARCZAK_BAMBU_PROBE_LOG_DIR="${PJARCZAK_BAMBU_PROBE_LOG_DIR:-$DIR}" \
PJARCZAK_BAMBU_COUNTRY_CODE="${PJARCZAK_BAMBU_COUNTRY_CODE:-PL}" \
"$bin" --probe-auth >/dev/null 2>&1
}
choose_bin() {
forced="${PJARCZAK_FORCE_HOST_ABI:-}"
if [ -n "$forced" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$forced" ]; then
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$forced"
return 0
fi
if [ -f "$CACHE_FILE" ]; then
cached=$(cat "$CACHE_FILE" 2>/dev/null || true)
if [ -n "$cached" ] && [ -x "$DIR/pjarczak_bambu_linux_host_$cached" ]; then
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$cached"
return 0
fi
fi
for abi in abi1 abi0; do
if run_probe "$DIR/pjarczak_bambu_linux_host_$abi"; then
printf '%s' "$abi" > "$CACHE_FILE"
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_$abi"
return 0
fi
done
if [ -x "$DIR/pjarczak_bambu_linux_host_abi1" ]; then
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi1"
return 0
fi
if [ -x "$DIR/pjarczak_bambu_linux_host_abi0" ]; then
printf '%s\n' "$DIR/pjarczak_bambu_linux_host_abi0"
return 0
fi
return 1
}
BIN=$(choose_bin) || {
echo "no compatible host ABI variant found" >&2
exit 127
}
if [ "${1:-}" = "--print-bin" ]; then
printf '%s\n' "$BIN"
exit 0
fi
export LD_LIBRARY_PATH="$DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
exec "$BIN" "$@"

View File

@@ -0,0 +1 @@
OrcaSlicer\ota\plugins

View File

@@ -0,0 +1 @@
PJARCZAK-BAMBU

View File

@@ -0,0 +1,229 @@
#!/bin/sh
set -eu
log() {
printf '%s\n' "[pjarczak_wsl_run_host] $*" >&2
}
MODE="run"
if [ "${1:-}" = "--probe" ]; then
MODE="probe"
shift
fi
PACKAGE_DIR="${1:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_DIR:-}}"
PLUGIN_CACHE_DIR="${2:-${PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR:-}}"
if [ -z "$PACKAGE_DIR" ]; then
log "missing Windows package directory path"
exit 127
fi
if [ -n "$PLUGIN_CACHE_DIR" ] && [ ! -d "$PLUGIN_CACHE_DIR" ] && [ -d "$PLUGIN_CACHE_DIR/plugins" ]; then
PLUGIN_CACHE_DIR="$PLUGIN_CACHE_DIR/plugins"
fi
if [ -n "$PLUGIN_CACHE_DIR" ] && [ -d "$PLUGIN_CACHE_DIR/plugins" ] && [ ! -f "$PLUGIN_CACHE_DIR/libbambu_networking.so" ] && [ ! -f "$PLUGIN_CACHE_DIR/libBambuSource.so" ]; then
PLUGIN_CACHE_DIR="$PLUGIN_CACHE_DIR/plugins"
fi
HOST_SRC="$PACKAGE_DIR/pjarczak_bambu_linux_host"
if [ ! -f "$HOST_SRC" ]; then
log "missing runtime file: $HOST_SRC"
exit 127
fi
find_preferred_file() {
name="$1"
if [ -f "$PACKAGE_DIR/$name" ]; then
printf '%s\n' "$PACKAGE_DIR/$name"
return 0
fi
if [ -n "$PLUGIN_CACHE_DIR" ] && [ -f "$PLUGIN_CACHE_DIR/$name" ]; then
printf '%s\n' "$PLUGIN_CACHE_DIR/$name"
return 0
fi
return 1
}
resolve_payload_sources() {
NETWORK_SRC="$(find_preferred_file libbambu_networking.so || true)"
SOURCE_SRC="$(find_preferred_file libBambuSource.so || true)"
ABI1_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi1 || true)"
ABI0_SRC="$(find_preferred_file pjarczak_bambu_linux_host_abi0 || true)"
CA_BUNDLE_SRC="$(find_preferred_file ca-certificates.crt || true)"
SLICER_CERT_SRC="$(find_preferred_file slicer_base64.cer || true)"
MANIFEST_SRC="$(find_preferred_file linux_payload_manifest.json || true)"
}
wait_for_payload_sources() {
if [ "$MODE" = "probe" ]; then
return 1
fi
WAIT_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_SECS:-300}"
SLEEP_SECS="${PJARCZAK_BAMBU_PLUGIN_WAIT_INTERVAL_SECS:-2}"
DEADLINE=$(( $(date +%s) + WAIT_SECS ))
while :; do
resolve_payload_sources
if [ -n "$NETWORK_SRC" ] && [ -n "$SOURCE_SRC" ]; then
return 0
fi
NOW=$(date +%s)
[ "$NOW" -lt "$DEADLINE" ] || return 1
sleep "$SLEEP_SECS"
done
}
append_source() {
dst_name="$1"
src_path="$2"
[ -n "$src_path" ] || return 0
[ -f "$src_path" ] || return 0
printf '%s\t%s\n' "$dst_name" "$src_path" >> "$SOURCE_LIST"
}
append_package_extras() {
for path in "$PACKAGE_DIR"/*; do
[ -f "$path" ] || continue
base="$(basename "$path")"
case "$base" in
pjarczak_bambu_linux_host|pjarczak_bambu_linux_host_abi1|pjarczak_bambu_linux_host_abi0|libbambu_networking.so|libBambuSource.so|linux_payload_manifest.json|ca-certificates.crt|slicer_base64.cer)
continue
;;
*.dll|*.ps1|*.txt|*.tar|*.zip|*.cmd|*.bat|*.sh)
continue
;;
esac
append_source "$base" "$path"
done
}
copy_source_list() {
while IFS="$(printf '\t')" read -r dst_name src_path; do
[ -n "$dst_name" ] || continue
cp "$src_path" "$TMP_DIR/$dst_name"
done < "$SOURCE_LIST"
}
compute_runtime_hash() {
{
while IFS="$(printf '\t')" read -r dst_name src_path; do
[ -n "$dst_name" ] || continue
printf '%s\n' "$dst_name"
sha256sum "$src_path"
done < "$SOURCE_LIST"
} | sha256sum | cut -d ' ' -f1
}
list_runtime_files() {
find -L "$CURRENT_DIR" -maxdepth 1 -type f -printf '%f\n' | sort | tr '\n' ',' | sed 's/,$//'
}
resolve_payload_sources
if [ -z "$NETWORK_SRC" ] || [ -z "$SOURCE_SRC" ]; then
log "plugin_not_downloaded package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
if [ "$MODE" = "probe" ]; then
exit 3
fi
if ! wait_for_payload_sources; then
log "plugin_not_downloaded_timeout package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
exit 127
fi
fi
if [ -z "$ABI1_SRC" ] && [ -z "$ABI0_SRC" ]; then
log "missing host ABI binaries in package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none}"
exit 127
fi
if ! command -v sha256sum >/dev/null 2>&1; then
log "sha256sum not found inside WSL distro"
exit 127
fi
export HOME="${HOME:-/root}"
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
mkdir -p "$XDG_CONFIG_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$XDG_DATA_HOME" "$HOME/.pjarczak-bambu-runtime"
unset APPDATA LOCALAPPDATA USERPROFILE HOMEDRIVE HOMEPATH TEMP TMP TMPDIR
RUNTIME_BASE="${PJARCZAK_BAMBU_WSL_RUNTIME_DIR:-$HOME/.pjarczak-bambu-runtime}"
mkdir -p "$RUNTIME_BASE"
SOURCE_LIST="$(mktemp "$RUNTIME_BASE/.sources.XXXXXX")"
trap 'rm -f "$SOURCE_LIST"' EXIT INT TERM
append_source "pjarczak_bambu_linux_host" "$HOST_SRC"
append_source "libbambu_networking.so" "$NETWORK_SRC"
append_source "libBambuSource.so" "$SOURCE_SRC"
append_source "pjarczak_bambu_linux_host_abi1" "$ABI1_SRC"
append_source "pjarczak_bambu_linux_host_abi0" "$ABI0_SRC"
append_source "linux_payload_manifest.json" "$MANIFEST_SRC"
append_source "ca-certificates.crt" "$CA_BUNDLE_SRC"
append_source "slicer_base64.cer" "$SLICER_CERT_SRC"
append_package_extras
RUNTIME_HASH="$(compute_runtime_hash)"
TARGET_DIR="$RUNTIME_BASE/$RUNTIME_HASH"
CURRENT_DIR="$RUNTIME_BASE/current"
log "mode=$MODE package_dir=$PACKAGE_DIR plugin_cache_dir=${PLUGIN_CACHE_DIR:-none} runtime_hash=$RUNTIME_HASH"
log "wrapper_src=$HOST_SRC"
log "network_src=${NETWORK_SRC:-missing}"
log "source_src=${SOURCE_SRC:-missing}"
log "abi1_src=${ABI1_SRC:-missing}"
log "abi0_src=${ABI0_SRC:-missing}"
log "manifest_src=${MANIFEST_SRC:-missing}"
log "ca_bundle_src=${CA_BUNDLE_SRC:-missing}"
log "slicer_cert_src=${SLICER_CERT_SRC:-missing}"
if [ ! -d "$TARGET_DIR" ]; then
TMP_DIR="$RUNTIME_BASE/.tmp-$RUNTIME_HASH-$$"
rm -rf "$TMP_DIR"
mkdir -p "$TMP_DIR"
copy_source_list
chmod 755 "$TMP_DIR/pjarczak_bambu_linux_host" "$TMP_DIR"/pjarczak_bambu_linux_host_abi* 2>/dev/null || true
mv "$TMP_DIR" "$TARGET_DIR"
log "created_runtime_dir=$TARGET_DIR"
else
log "reusing_runtime_dir=$TARGET_DIR"
fi
rm -rf "$CURRENT_DIR"
ln -s "$TARGET_DIR" "$CURRENT_DIR"
export PJARCZAK_BAMBU_PLUGIN_DIR="$CURRENT_DIR"
export PJARCZAK_BAMBU_NETWORK_SO="$CURRENT_DIR/libbambu_networking.so"
export PJARCZAK_BAMBU_SOURCE_SO="$CURRENT_DIR/libBambuSource.so"
export LD_LIBRARY_PATH="$CURRENT_DIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
if [ -f "$CURRENT_DIR/ca-certificates.crt" ]; then
export SSL_CERT_FILE="$CURRENT_DIR/ca-certificates.crt"
export CURL_CA_BUNDLE="$CURRENT_DIR/ca-certificates.crt"
fi
if [ -d /etc/ssl/certs ]; then
export SSL_CERT_DIR="/etc/ssl/certs"
fi
BIN_PATH=$("$CURRENT_DIR/pjarczak_bambu_linux_host" --print-bin 2>/tmp/pjarczak-bin.txt || true)
if [ -z "$BIN_PATH" ] || [ ! -x "$BIN_PATH" ]; then
log "failed to resolve host binary"
cat /tmp/pjarczak-bin.txt >&2 || true
exit 127
fi
log "selected_bin=$BIN_PATH"
log "runtime_files=$(list_runtime_files)"
if command -v ldd >/dev/null 2>&1; then
LDD_OUT="$(ldd "$BIN_PATH" 2>&1 || true)"
if printf '%s\n' "$LDD_OUT" | grep -q 'not found'; then
log "ldd reported missing libraries for $BIN_PATH"
printf '%s\n' "$LDD_OUT" >&2
exit 127
fi
fi
if [ "$MODE" = "probe" ]; then
echo "probe_ok runtime_dir=$CURRENT_DIR runtime_hash=$RUNTIME_HASH bin=$BIN_PATH"
exit 0
fi
exec "$CURRENT_DIR/pjarczak_bambu_linux_host"

View File

@@ -0,0 +1,245 @@
param(
[string]$PackageDir = "",
[string]$DistroName = "",
[string]$PluginCacheDir = "",
[switch]$AllowMissingLinuxPlugin,
[switch]$SkipProbe
)
$ErrorActionPreference = 'Stop'
if (Get-Variable -Name PSNativeCommandUseErrorActionPreference -ErrorAction SilentlyContinue) {
$script:__pj_prev_native_pref = $PSNativeCommandUseErrorActionPreference
$PSNativeCommandUseErrorActionPreference = $false
}
function Get-ScriptDir {
if (-not [string]::IsNullOrWhiteSpace($PSScriptRoot)) {
return $PSScriptRoot
}
if (-not [string]::IsNullOrWhiteSpace($PSCommandPath)) {
return (Split-Path -Parent $PSCommandPath)
}
if ($MyInvocation.MyCommand -and -not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
return (Split-Path -Parent $MyInvocation.MyCommand.Path)
}
return (Get-Location).Path
}
function Convert-FileToLf([string]$Path) {
if ([string]::IsNullOrWhiteSpace($Path) -or !(Test-Path $Path)) {
return
}
$content = [System.IO.File]::ReadAllText($Path)
$content = $content.Replace("`r`n", "`n").Replace("`r", "`n")
$utf8NoBom = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllText($Path, $content, $utf8NoBom)
}
function To-WslPath([string]$Path) {
$full = [System.IO.Path]::GetFullPath($Path)
if ($full.Length -ge 2 -and $full[1] -eq ':') {
$drive = $full.Substring(0, 1).ToLowerInvariant()
$tail = ($full.Substring(2) -replace '\\', '/')
if ($tail.StartsWith('/')) {
$tail = $tail.Substring(1)
}
return "/mnt/$drive/$tail"
}
return ($full -replace '\\', '/')
}
function Read-TextAuto([string]$Path) {
if (!(Test-Path $Path)) {
return ''
}
$bytes = [System.IO.File]::ReadAllBytes($Path)
if ($bytes.Length -eq 0) {
return ''
}
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
return ([System.Text.Encoding]::Unicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
}
if ($bytes.Length -ge 2 -and $bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
return ([System.Text.Encoding]::BigEndianUnicode.GetString($bytes, 2, $bytes.Length - 2) -replace "`0", '')
}
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
return ([System.Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) -replace "`0", '')
}
for ($i = 1; $i -lt [Math]::Min($bytes.Length, 64); $i += 2) {
if ($bytes[$i] -eq 0) {
return ([System.Text.Encoding]::Unicode.GetString($bytes) -replace "`0", '')
}
}
return ([System.Text.Encoding]::UTF8.GetString($bytes) -replace "`0", '')
}
function Normalize-NativeText([string]$Text) {
if ([string]::IsNullOrEmpty($Text)) {
return ''
}
$value = $Text -replace "`0", ''
$value = $value -replace "`r`n", "`n"
$value = $value -replace "`r", "`n"
return $value
}
function Invoke-NativeCapture([string]$FilePath, [string[]]$ArgumentList) {
$stdoutPath = [System.IO.Path]::GetTempFileName()
$stderrPath = [System.IO.Path]::GetTempFileName()
try {
$proc = Start-Process -FilePath $FilePath -ArgumentList $ArgumentList -Wait -PassThru -RedirectStandardOutput $stdoutPath -RedirectStandardError $stderrPath -WindowStyle Hidden
$stdoutText = if (Test-Path $stdoutPath) { Normalize-NativeText (Read-TextAuto $stdoutPath) } else { '' }
$stderrText = if (Test-Path $stderrPath) { Normalize-NativeText (Read-TextAuto $stderrPath) } else { '' }
$combined = (($stdoutText + "`n" + $stderrText).Trim())
return @{
ExitCode = $proc.ExitCode
StdOut = $stdoutText
StdErr = $stderrText
Combined = $combined
}
} finally {
Remove-Item -Force -ErrorAction SilentlyContinue $stdoutPath, $stderrPath
}
}
function Test-WslDistroExists([string]$WslPath, [string]$Name) {
$probe = Invoke-NativeCapture $WslPath @('-d', $Name, '--user', 'root', '--', 'sh', '-lc', 'true')
if ($probe.ExitCode -eq 0) {
return @{
Exists = $true
Reason = ''
}
}
$text = $probe.Combined
$lower = $text.ToLowerInvariant()
if ($lower.Contains('there is no distribution with the supplied name') -or
$lower.Contains('wsl_e_distribution_not_found') -or
($lower.Contains('distribution') -and $lower.Contains('not') -and $lower.Contains('found'))) {
return @{
Exists = $false
Reason = "WSL distro '$Name' is not installed"
}
}
if ([string]::IsNullOrWhiteSpace($text)) {
throw "Failed to start WSL distro '$Name'"
}
throw ("Failed to start WSL distro '{0}': {1}" -f $Name, $text)
}
if ([string]::IsNullOrWhiteSpace($PackageDir)) {
$PackageDir = Get-ScriptDir
}
$PackageDir = [System.IO.Path]::GetFullPath($PackageDir)
if ([string]::IsNullOrWhiteSpace($PluginCacheDir)) {
if ($env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR) {
$PluginCacheDir = $env:PJARCZAK_BAMBU_WINDOWS_PLUGIN_CACHE_DIR
} else {
$subdirFile = Join-Path $PackageDir 'pjarczak_plugin_cache_subdir.txt'
if ((-not [string]::IsNullOrWhiteSpace($env:APPDATA)) -and (Test-Path $subdirFile)) {
$subdir = (Get-Content $subdirFile -Raw).Trim()
if (-not [string]::IsNullOrWhiteSpace($subdir)) {
$PluginCacheDir = Join-Path $env:APPDATA $subdir
}
}
if ([string]::IsNullOrWhiteSpace($PluginCacheDir) -and $env:APPDATA) {
$PluginCacheDir = Join-Path $env:APPDATA 'OrcaSlicer\ota\plugins'
}
}
}
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
$PluginCacheDir = [System.IO.Path]::GetFullPath($PluginCacheDir)
$pluginsChild = Join-Path $PluginCacheDir 'plugins'
if ((Split-Path -Leaf $PluginCacheDir) -ieq 'ota' -and (Test-Path $pluginsChild)) {
$PluginCacheDir = [System.IO.Path]::GetFullPath($pluginsChild)
} elseif ((Test-Path $pluginsChild) -and !(Test-Path (Join-Path $PluginCacheDir 'libbambu_networking.so')) -and !(Test-Path (Join-Path $PluginCacheDir 'libBambuSource.so'))) {
$PluginCacheDir = [System.IO.Path]::GetFullPath($pluginsChild)
}
}
if ([string]::IsNullOrWhiteSpace($DistroName)) {
$distroFile = Join-Path $PackageDir 'pjarczak_wsl_distro.txt'
if (Test-Path $distroFile) {
$DistroName = (Get-Content $distroFile -Raw).Trim()
}
}
if ([string]::IsNullOrWhiteSpace($DistroName)) {
throw 'Missing distro name. Set PJARCZAK_WSL_DISTRO or provide pjarczak_wsl_distro.txt.'
}
$requiredFiles = @(
'pjarczak_bambu_networking_bridge.dll',
'pjarczak_wsl_distro.txt',
'install_runtime.ps1',
'verify_runtime.ps1',
'pjarczak_bambu_linux_host',
'pjarczak_bambu_linux_host_abi1',
'pjarczak_bambu_linux_host_abi0',
'windows-wsl2-rootfs.tar',
'ca-certificates.crt',
'slicer_base64.cer'
)
foreach ($name in $requiredFiles) {
$path = Join-Path $PackageDir $name
if (!(Test-Path $path)) {
throw "Missing package file: $name"
}
}
$bootstrapPath = Join-Path $PackageDir 'pjarczak_wsl_run_host.sh'
if (!(Test-Path $bootstrapPath)) { $bootstrapPath = Join-Path $PackageDir 'pjarczak-wsl-run-host.sh' }
if (!(Test-Path $bootstrapPath)) {
throw 'Missing package file: pjarczak_wsl_run_host.sh'
}
Convert-FileToLf $bootstrapPath
$wsl = Join-Path $env:WINDIR 'System32\wsl.exe'
if (!(Test-Path $wsl)) {
throw 'wsl.exe not found'
}
$distroStatus = Test-WslDistroExists $wsl $DistroName
if (-not $distroStatus.Exists) {
throw $distroStatus.Reason
}
$packageDirWsl = To-WslPath $PackageDir
$pluginCacheDirWsl = ""
if (-not [string]::IsNullOrWhiteSpace($PluginCacheDir)) {
$pluginCacheDirWsl = To-WslPath $PluginCacheDir
}
$bootstrapWsl = "$packageDirWsl/$([System.IO.Path]::GetFileName($bootstrapPath))"
Write-Host "Bridge package dir: $PackageDir"
Write-Host "Plugin cache dir: $PluginCacheDir"
Write-Host "WSL distro: $DistroName"
Write-Host "Bootstrap script: $bootstrapPath"
if ($SkipProbe) {
Write-Host 'WSL runtime core OK'
exit 0
}
$probe = Invoke-NativeCapture $wsl @('-d', $DistroName, '--user', 'root', '--', 'sh', $bootstrapWsl, '--probe', $packageDirWsl, $pluginCacheDirWsl)
if ($probe.ExitCode -ne 0) {
$probeText = $probe.Combined
if ($AllowMissingLinuxPlugin -and $probeText -match 'plugin_not_downloaded') {
Write-Host 'WSL runtime package OK, linux plugin not downloaded yet.'
Write-Host $probeText
exit 0
}
throw "WSL runtime probe failed: $probeText"
}
Write-Host 'WSL runtime probe OK'
Write-Host $probe.Combined