mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
fix desktop bundles (#6773)
# Description of Changes Changes - Use 127.0.0.1 instead of localhost for the local backend. The bundled backend starts on a random port and binds the IPv4 wildcard, but the frontend health-checked http://localhost:{port}. On macOS (and some Linux) localhost resolves to IPv6 ::1 first, so the connection is refused and every backend-dependent tool shows "backend offline" even though the backend started fine. Switched getBackendUrl() and the health-check URL to the 127.0.0.1 loopback literal (already in the Tauri HTTP capability allowlist, and what the OAuth loopback server already uses). Client-side tools were unaffected, which matches the reports. - Fail the desktop build when the bundled JRE is older than the app JAR. The app JAR is compiled for Java 25, but the bundle could ship an older runtime/jre (jlink:runtime short-circuits on an existing runtime, and nothing checked its version), producing UnsupportedClassVersionError at launch so the backend never starts. Added a jlink:verify task that reads the jlink release file and fails the build if the bundled JRE major is below REQUIRED_JAVA (25, kept in sync with build.gradle modernJavaVersion). It runs after the runtime is staged - including the short-circuit reuse path that lets a stale JRE slip through. Cross-platform Node script, no new dependencies. --- ## Checklist ### General - [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [ ] I have performed a self-review of my own code - [ ] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details.
This commit is contained in:
+25
-2
@@ -5,6 +5,11 @@ vars:
|
||||
# NoClassDefFoundError: jdk/dynalink/Namespace at runtime in get-info-on-pdf and verify-pdf
|
||||
JLINK_MODULES: "java.base,java.compiler,java.desktop,java.instrument,java.logging,java.management,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.transaction.xa,java.xml,java.xml.crypto,jdk.crypto.ec,jdk.crypto.cryptoki,jdk.unsupported,jdk.dynalink"
|
||||
|
||||
# Minimum Java major the bundled JRE must be. Keep in sync with build.gradle
|
||||
# `modernJavaVersion` - the app JAR is compiled for this, so an older runtime
|
||||
# fails at launch with UnsupportedClassVersionError. Enforced by jlink:verify.
|
||||
REQUIRED_JAVA: "25"
|
||||
|
||||
# Override via JPDFIUM_PLATFORMS env (csv of platform keys, or 'all').
|
||||
JPDFIUM_PLATFORMS:
|
||||
sh: |
|
||||
@@ -102,6 +107,20 @@ tasks:
|
||||
jlink:
|
||||
desc: "Build backend JAR and create JLink runtime for Tauri"
|
||||
deps: [jlink:jar, jlink:runtime]
|
||||
# Runs after the runtime is in place. Lives here (not in jlink:runtime's
|
||||
# cmds) so it still fires when jlink:runtime short-circuits on its `status:`
|
||||
# check and reuses an existing runtime/jre - that reuse path is exactly how
|
||||
# a stale, too-old JRE slips through.
|
||||
cmds:
|
||||
- task: jlink:verify
|
||||
|
||||
jlink:verify:
|
||||
desc: "Fail the build if the bundled JRE is older than the app JAR requires"
|
||||
dir: editor
|
||||
env:
|
||||
REQUIRED_JAVA: "{{.REQUIRED_JAVA}}"
|
||||
cmds:
|
||||
- node scripts/verify-bundled-jre.mjs src-tauri/runtime/jre/release
|
||||
|
||||
jlink:jar:
|
||||
desc: "Build backend JAR for Tauri bundling (host-OS natives only by default)"
|
||||
@@ -127,9 +146,13 @@ tasks:
|
||||
cmds:
|
||||
- rm -rf runtime/jre
|
||||
- mkdir -p runtime
|
||||
# Pin jlink to JAVA_HOME so the bundled JRE matches the JDK the build
|
||||
# uses. Bare `jlink` on PATH can resolve to an older system Java (the
|
||||
# ubuntu runner ships Java 11), producing a runtime jlink:verify rejects.
|
||||
- |
|
||||
JLINK_COMPRESS="$(jlink --help 2>&1 | grep -q 'zip-\[0-9\]' && echo zip-6 || echo 2)"
|
||||
jlink \
|
||||
JLINK="${JAVA_HOME:+$JAVA_HOME/bin/}jlink"
|
||||
JLINK_COMPRESS="$("$JLINK" --help 2>&1 | grep -q 'zip-\[0-9\]' && echo zip-6 || echo 2)"
|
||||
"$JLINK" \
|
||||
--add-modules {{.JLINK_MODULES}} \
|
||||
--strip-debug \
|
||||
--compress="$JLINK_COMPRESS" \
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Fail the desktop build if the bundled jlink runtime is older than the Java
|
||||
// version the app JAR is compiled for. A too-old runtime ships happily today
|
||||
// (the jlink task short-circuits on a stale runtime/jre, and nothing checks the
|
||||
// version), then dies at launch with UnsupportedClassVersionError -> the
|
||||
// backend never starts and every tool shows "backend offline".
|
||||
//
|
||||
// Reads JAVA_VERSION from the jlink `release` file (always present in a jlink
|
||||
// output) so it needs no shell and behaves identically on Windows/macOS/Linux.
|
||||
//
|
||||
// Required major comes from REQUIRED_JAVA (wired from .taskfiles/desktop.yml,
|
||||
// which mirrors build.gradle `modernJavaVersion`). Keep them in sync.
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
const required = Number(process.env.REQUIRED_JAVA ?? "25");
|
||||
const releasePath = process.argv[2] ?? "runtime/jre/release";
|
||||
|
||||
let raw;
|
||||
try {
|
||||
raw = readFileSync(releasePath, "utf8");
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`FATAL: cannot read bundled JRE release file at "${releasePath}": ${err.message}. ` +
|
||||
`Is the runtime built? Run 'task desktop:jlink'.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const match = raw.match(/JAVA_VERSION="?(\d+)/);
|
||||
const major = match ? Number(match[1]) : 0;
|
||||
|
||||
console.log(
|
||||
`Bundled JRE major: ${major || "unknown"} (required >= ${required})`,
|
||||
);
|
||||
|
||||
if (!major || major < required) {
|
||||
console.error(
|
||||
`FATAL: bundled runtime/jre is Java ${major || "unknown"} but the app JAR requires ` +
|
||||
`Java ${required}. Run 'task desktop:jlink:clean' and rebuild with JDK ${required} active ` +
|
||||
`(check 'java -version' / JAVA_HOME).`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -308,7 +308,7 @@ fn monitor_backend_output(mut rx: tauri::async_runtime::Receiver<tauri_plugin_sh
|
||||
let mut port_guard = BACKEND_PORT.lock().unwrap();
|
||||
*port_guard = Some(port);
|
||||
add_log(format!("🎉 Backend started on port: {}", port));
|
||||
add_log(format!("🔌 Navigate to: http://localhost:{}/", port));
|
||||
add_log(format!("🔌 Navigate to: http://127.0.0.1:{}/", port));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,11 @@ export class TauriBackendService {
|
||||
}
|
||||
|
||||
getBackendUrl(): string | null {
|
||||
return this.backendPort ? `http://localhost:${this.backendPort}` : null;
|
||||
// Use the IPv4 loopback literal, not "localhost": on macOS (and some Linux)
|
||||
// "localhost" can resolve to IPv6 ::1 first, but the bundled backend binds
|
||||
// the IPv4 wildcard, so a ::1 connection is refused and every tool shows
|
||||
// "backend offline" even though the backend is up.
|
||||
return this.backendPort ? `http://127.0.0.1:${this.backendPort}` : null;
|
||||
}
|
||||
|
||||
subscribeToStatus(listener: (status: BackendStatus) => void): () => void {
|
||||
@@ -227,7 +231,7 @@ export class TauriBackendService {
|
||||
});
|
||||
}
|
||||
|
||||
/** Always checks the local bundled backend at localhost:{port}. */
|
||||
/** Always checks the local bundled backend at 127.0.0.1:{port}. */
|
||||
async checkBackendHealth(): Promise<boolean> {
|
||||
if (!this.backendStarted) {
|
||||
console.debug("[TauriBackendService] Health check: backend not started");
|
||||
@@ -241,7 +245,7 @@ export class TauriBackendService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const configUrl = `http://localhost:${this.backendPort}/api/v1/config/app-config`;
|
||||
const configUrl = `http://127.0.0.1:${this.backendPort}/api/v1/config/app-config`;
|
||||
console.debug(
|
||||
`[TauriBackendService] Checking local backend health at: ${configUrl}`,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user