From d043f9c4164bacdb3682a7a7ddbb95552471f9c4 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Wed, 10 Jun 2026 00:06:12 -0400 Subject: [PATCH] fix(windows): fix PermissionKind out-param and add AppImage support - Fix COREWEBVIEW2_PERMISSION_KIND out-param pattern in PermissionRequestedEventHandler - Add "wry" feature to tauri dep so with_webview compiles on Windows - Build both appimage and deb on Linux for auto-update compatibility - Commit AppRun-x86_64 binary to avoid GitHub download timeout in CI Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/release.yml | 51 ++++++++++++++++++++++------------- src-tauri/Cargo.toml | 2 +- src-tauri/src/lib.rs | 4 ++- tools/AppRun-x86_64 | Bin 0 -> 31552 bytes 4 files changed, 36 insertions(+), 21 deletions(-) create mode 100755 tools/AppRun-x86_64 diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index d32e9f2..5eec231 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -40,11 +40,9 @@ jobs: env: TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | - # Read version from tauri.conf.json — no fragile filename parsing $VERSION = (Get-Content "src-tauri\tauri.conf.json" | ConvertFrom-Json).version Write-Host "Version: $VERSION" - # Get or create the latest release $release = Invoke-RestMethod -Uri "$env:GITEA_URL/api/v1/repos/$env:REPO/releases/tags/latest" ` -Headers @{ Authorization = "token $env:TOKEN" } -ErrorAction SilentlyContinue if (-not $release) { @@ -63,7 +61,6 @@ jobs: ) $names = @("LotusChat-x86_64-setup.exe", "LotusChat-x86_64-setup.nsis.zip", "LotusChat-x86_64-setup.nsis.zip.sig") for ($i = 0; $i -lt $files.Length; $i++) { - # Delete existing asset with same name if present $existing = (Invoke-RestMethod -Uri "$env:GITEA_URL/api/v1/repos/$env:REPO/releases/$releaseId/assets" ` -Headers @{ Authorization = "token $env:TOKEN" }) | Where-Object { $_.name -eq $names[$i] } if ($existing) { @@ -113,26 +110,29 @@ jobs: - name: Install Tauri deps run: npm ci + - name: Stage AppRun for AppImage bundler + run: | + mkdir -p ~/.cache/tauri + cp tools/AppRun-x86_64 ~/.cache/tauri/AppRun-x86_64 + chmod +x ~/.cache/tauri/AppRun-x86_64 + - name: Build env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: '' NODE_OPTIONS: '--max_old_space_size=4096' - # AppImage requires downloading AppRun from GitHub which times out in this runner. - # Build deb only; AppImage can be re-enabled once network access to GitHub is confirmed. - run: npm run tauri -- build --bundles deb + run: npm run tauri -- build --bundles appimage,deb - name: Upload to release env: TOKEN: ${{ secrets.RELEASE_TOKEN }} run: | - # Read version from tauri.conf.json — no fragile filename parsing VERSION=$(python3 -c "import json; print(json.load(open('src-tauri/tauri.conf.json'))['version'])") echo "Version: $VERSION" - DEB="src-tauri/target/release/bundle/deb/Lotus Chat_${VERSION}_amd64.deb" + APPIMAGE_DIR="src-tauri/target/release/bundle/appimage" + DEB_DIR="src-tauri/target/release/bundle/deb" - # Get or create the latest release RELEASE=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" \ -H "Authorization: token $TOKEN" 2>/dev/null || true) RELEASE_ID=$(echo "$RELEASE" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) @@ -144,10 +144,9 @@ jobs: | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") fi - for file in \ - "LotusChat-x86_64.deb|$DEB"; do - name="${file%%|*}" - path="${file##*|}" + upload() { + local name="$1" path="$2" + local existing_id existing_id=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/$RELEASE_ID/assets" \ -H "Authorization: token $TOKEN" \ | python3 -c "import sys,json; assets=json.load(sys.stdin); print(next((str(a['id']) for a in assets if a['name']=='$name'), ''))" 2>/dev/null || true) @@ -161,7 +160,12 @@ jobs: -H "Authorization: token $TOKEN" \ -H "Content-Type: application/octet-stream" \ --data-binary @"$path" - done + } + + upload "LotusChat-x86_64.AppImage" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage" + upload "LotusChat-x86_64.AppImage.tar.gz" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage.tar.gz" + upload "LotusChat-x86_64.AppImage.tar.gz.sig" "$APPIMAGE_DIR/Lotus Chat_${VERSION}_amd64.AppImage.tar.gz.sig" + upload "LotusChat-x86_64.deb" "$DEB_DIR/Lotus Chat_${VERSION}_amd64.deb" update-manifest: needs: [build-windows, build-linux] @@ -177,6 +181,7 @@ jobs: BASE="$GITEA_URL/LotusGuild/cinny-desktop/releases/download/latest" WIN_SIG=$(curl -sf "$BASE/LotusChat-x86_64-setup.nsis.zip.sig") + LIN_SIG=$(curl -sf "$BASE/LotusChat-x86_64.AppImage.tar.gz.sig") RELEASE=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/tags/latest" \ -H "Authorization: token $TOKEN") @@ -187,14 +192,22 @@ jobs: jq -n \ --arg version "$VERSION" \ --arg date "$DATE" \ - --arg url "$BASE/LotusChat-x86_64-setup.nsis.zip" \ - --arg sig "$WIN_SIG" \ - '{"version":$version,"notes":"Latest Lotus Chat release","pub_date":$date,"platforms":{"windows-x86_64":{"url":$url,"signature":$sig}}}' \ - > release.json + --arg win_url "$BASE/LotusChat-x86_64-setup.nsis.zip" \ + --arg win_sig "$WIN_SIG" \ + --arg lin_url "$BASE/LotusChat-x86_64.AppImage.tar.gz" \ + --arg lin_sig "$LIN_SIG" \ + '{ + version: $version, + notes: "Latest Lotus Chat release", + pub_date: $date, + platforms: { + "windows-x86_64": { url: $win_url, signature: $win_sig }, + "linux-x86_64": { url: $lin_url, signature: $lin_sig } + } + }' > release.json cat release.json - # Delete old manifest asset if present OLD=$(curl -sf "$GITEA_URL/api/v1/repos/$REPO/releases/$RELEASE_ID/assets" \ -H "Authorization: token $TOKEN" \ | python3 -c "import sys,json; print(next((str(a['id']) for a in json.load(sys.stdin) if a['name']=='release.json'), ''))" 2>/dev/null || true) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ea3f824..2fcaa81 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -17,7 +17,7 @@ tauri-build = { version = "2", features = [] } [dependencies] serde_json = "1.0.109" serde = { version = "1.0.193", features = ["derive"] } -tauri = { version = "2", features = [ "devtools"] } +tauri = { version = "2", features = ["devtools", "wry"] } tauri-plugin-localhost = "2" tauri-plugin-window-state = "2" tauri-plugin-clipboard-manager = "2" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 1791219..acd7de7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -53,7 +53,9 @@ pub fn run() { let handler = PermissionRequestedEventHandler::create(Box::new( |_sender, args| { if let Some(args) = args { - let kind = unsafe { args.PermissionKind() }?; + // PermissionKind uses a COM out-param pattern + let mut kind = COREWEBVIEW2_PERMISSION_KIND(0); + unsafe { args.PermissionKind(&mut kind) }?; if kind == COREWEBVIEW2_PERMISSION_KIND_MICROPHONE || kind == COREWEBVIEW2_PERMISSION_KIND_CAMERA { diff --git a/tools/AppRun-x86_64 b/tools/AppRun-x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..c0f36d57ca342337e65c0d20c80dd501acf4a0a0 GIT binary patch literal 31552 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 f&=9|UJ+h3cjP*~$Y>Wt3JlQAoH^eB!u