mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-12 10:35:03 +00:00
Building tauri on windows
This commit is contained in:
parent
da1c4f1c44
commit
aed4ccd07b
28
build-tauri.bat
Normal file
28
build-tauri.bat
Normal file
@ -0,0 +1,28 @@
|
||||
@echo off
|
||||
echo 🔨 Building Stirling PDF with Tauri integration...
|
||||
|
||||
REM Build the Java backend
|
||||
echo 📦 Building Java backend...
|
||||
call gradlew.bat bootJar
|
||||
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo ❌ Failed to build Java backend
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ✅ Java backend built successfully
|
||||
|
||||
REM Copy the JAR to Tauri resources
|
||||
echo 📋 Copying JAR file to Tauri resources...
|
||||
if not exist "frontend\src-tauri\libs" mkdir frontend\src-tauri\libs
|
||||
copy "build\libs\Stirling-PDF-*.jar" "frontend\src-tauri\libs\"
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo ❌ Failed to copy JAR file
|
||||
exit /b 1
|
||||
)
|
||||
echo ✅ JAR copied successfully
|
||||
|
||||
REM Navigate to frontend and run Tauri
|
||||
echo 🚀 Starting Tauri development server...
|
||||
cd frontend
|
||||
npx tauri dev
|
31
build-tauri.sh
Normal file
31
build-tauri.sh
Normal file
@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "🔨 Building Stirling PDF with Tauri integration..."
|
||||
|
||||
# Build the Java backend
|
||||
echo "📦 Building Java backend..."
|
||||
./gradlew bootJar
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Failed to build Java backend"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Java backend built successfully"
|
||||
|
||||
# Copy the JAR to Tauri resources
|
||||
echo "📋 Copying JAR file to Tauri resources..."
|
||||
mkdir -p frontend/src-tauri/libs
|
||||
cp build/libs/Stirling-PDF-*.jar frontend/src-tauri/libs/
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "✅ JAR copied successfully"
|
||||
else
|
||||
echo "❌ Failed to copy JAR file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Navigate to frontend and run Tauri
|
||||
echo "🚀 Starting Tauri development server..."
|
||||
cd frontend
|
||||
npm run tauri dev
|
@ -68,3 +68,15 @@ This section has moved here: [https://facebook.github.io/create-react-app/docs/d
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
|
||||
|
||||
## Tauri
|
||||
### Dev
|
||||
To run Tauri in development. Use the command:
|
||||
````npm run tauri-dev```
|
||||
This will run the gradle runboot command and the tauri dev command concurrently, starting the app once both are stable.
|
||||
|
||||
### Build
|
||||
To build a deployment of the Tauri app. Use the command:
|
||||
```npm run tauri-build```
|
||||
This will bundle the backend and frontend into one executable for each target. Targets can be set within the `tauri.conf.json` file.
|
||||
|
11
frontend/package-lock.json
generated
11
frontend/package-lock.json
generated
@ -16,6 +16,7 @@
|
||||
"@mui/icons-material": "^7.1.0",
|
||||
"@mui/material": "^7.1.0",
|
||||
"@tailwindcss/postcss": "^4.1.8",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
@ -2001,6 +2002,16 @@
|
||||
"tailwindcss": "4.1.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/api": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.5.0.tgz",
|
||||
"integrity": "sha512-Ldux4ip+HGAcPUmuLT8EIkk6yafl5vK0P0c0byzAKzxJh7vxelVtdPONjfgTm96PbN24yjZNESY8CKo8qniluA==",
|
||||
"license": "Apache-2.0 OR MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/tauri"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/cli": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.5.0.tgz",
|
||||
|
@ -12,6 +12,7 @@
|
||||
"@mui/icons-material": "^7.1.0",
|
||||
"@mui/material": "^7.1.0",
|
||||
"@tailwindcss/postcss": "^4.1.8",
|
||||
"@tauri-apps/api": "^2.5.0",
|
||||
"@testing-library/dom": "^10.4.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/react": "^16.3.0",
|
||||
|
564
frontend/src-tauri/Cargo.lock
generated
564
frontend/src-tauri/Cargo.lock
generated
@ -95,11 +95,14 @@ name = "app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"reqwest 0.11.27",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
"tauri-build",
|
||||
"tauri-plugin-log",
|
||||
"tauri-plugin-shell",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -476,6 +479,16 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.10.1"
|
||||
@ -499,9 +512,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics-types",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -512,7 +525,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.1",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@ -782,7 +795,7 @@ dependencies = [
|
||||
"rustc_version",
|
||||
"toml",
|
||||
"vswhom",
|
||||
"winreg",
|
||||
"winreg 0.55.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -791,6 +804,15 @@ version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
@ -817,6 +839,22 @@ dependencies = [
|
||||
"typeid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.7"
|
||||
@ -861,6 +899,15 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared 0.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
@ -868,7 +915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||
dependencies = [
|
||||
"foreign-types-macros",
|
||||
"foreign-types-shared",
|
||||
"foreign-types-shared 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -882,6 +929,12 @@ dependencies = [
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.3.1"
|
||||
@ -1291,6 +1344,25 @@ dependencies = [
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"indexmap 2.9.0",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
@ -1338,6 +1410,17 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa 1.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
@ -1349,6 +1432,17 @@ dependencies = [
|
||||
"itoa 1.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http 0.2.12",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "1.0.1"
|
||||
@ -1356,7 +1450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1367,8 +1461,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@ -1378,6 +1472,36 @@ version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa 1.0.15",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "1.6.0"
|
||||
@ -1387,8 +1511,8 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
"itoa 1.0.15",
|
||||
"pin-project-lite",
|
||||
@ -1397,6 +1521,19 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"hyper 0.14.32",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.14"
|
||||
@ -1408,9 +1545,9 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"hyper 1.6.0",
|
||||
"ipnet",
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
@ -1615,6 +1752,25 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-docker"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-wsl"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5"
|
||||
dependencies = [
|
||||
"is-docker",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
@ -1784,6 +1940,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
version = "0.8.0"
|
||||
@ -1898,6 +2060,23 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.9.0"
|
||||
@ -2214,12 +2393,78 @@ version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "open"
|
||||
version = "5.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95"
|
||||
dependencies = [
|
||||
"dunce",
|
||||
"is-wsl",
|
||||
"libc",
|
||||
"pathdiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"cfg-if",
|
||||
"foreign-types 0.3.2",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db335f4760b14ead6290116f2427bf33a14d4f0617d49f78a246de10c1831224"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pango"
|
||||
version = "0.18.3"
|
||||
@ -2268,6 +2513,12 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathdiff"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@ -2744,6 +2995,46 @@ dependencies = [
|
||||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"hyper 0.14.32",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper 0.1.2",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg 0.50.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.19"
|
||||
@ -2754,10 +3045,10 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
"hyper",
|
||||
"hyper 1.6.0",
|
||||
"hyper-util",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
@ -2769,7 +3060,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower",
|
||||
@ -2842,6 +3133,28 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.21"
|
||||
@ -2863,6 +3176,15 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.22"
|
||||
@ -2902,6 +3224,29 @@ version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation 0.9.4",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "selectors"
|
||||
version = "0.22.0"
|
||||
@ -3090,6 +3435,16 @@ dependencies = [
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shared_child"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e297bd52991bbe0686c086957bee142f13df85d1e79b0b21630a99d374ae9dc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
@ -3154,7 +3509,7 @@ dependencies = [
|
||||
"bytemuck",
|
||||
"cfg_aliases",
|
||||
"core-graphics",
|
||||
"foreign-types",
|
||||
"foreign-types 0.5.0",
|
||||
"js-sys",
|
||||
"log",
|
||||
"objc2 0.5.2",
|
||||
@ -3263,6 +3618,12 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
|
||||
|
||||
[[package]]
|
||||
name = "sync_wrapper"
|
||||
version = "1.0.2"
|
||||
@ -3283,6 +3644,27 @@ dependencies = [
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation 0.9.4",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "6.2.2"
|
||||
@ -3303,7 +3685,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"core-foundation",
|
||||
"core-foundation 0.10.1",
|
||||
"core-graphics",
|
||||
"crossbeam-channel",
|
||||
"dispatch",
|
||||
@ -3374,7 +3756,7 @@ dependencies = [
|
||||
"glob",
|
||||
"gtk",
|
||||
"heck 0.5.0",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"jni",
|
||||
"libc",
|
||||
"log",
|
||||
@ -3387,7 +3769,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"plist",
|
||||
"raw-window-handle",
|
||||
"reqwest",
|
||||
"reqwest 0.12.19",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
@ -3511,6 +3893,27 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-plugin-shell"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d5eb3368b959937ad2aeaf6ef9a8f5d11e01ffe03629d3530707bbcb27ff5d"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"log",
|
||||
"open",
|
||||
"os_pipe",
|
||||
"regex",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shared_child",
|
||||
"tauri",
|
||||
"tauri-plugin",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tauri-runtime"
|
||||
version = "2.6.0"
|
||||
@ -3520,7 +3923,7 @@ dependencies = [
|
||||
"cookie",
|
||||
"dpi",
|
||||
"gtk",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"jni",
|
||||
"objc2 0.6.1",
|
||||
"objc2-ui-kit",
|
||||
@ -3540,7 +3943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2"
|
||||
dependencies = [
|
||||
"gtk",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"jni",
|
||||
"log",
|
||||
"objc2 0.6.1",
|
||||
@ -3573,7 +3976,7 @@ dependencies = [
|
||||
"dunce",
|
||||
"glob",
|
||||
"html5ever",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"infer",
|
||||
"json-patch",
|
||||
"kuchikiki",
|
||||
@ -3609,6 +4012,19 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tendril"
|
||||
version = "0.4.3"
|
||||
@ -3739,6 +4155,16 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.15"
|
||||
@ -3824,7 +4250,7 @@ dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"pin-project-lite",
|
||||
"sync_wrapper",
|
||||
"sync_wrapper 1.0.2",
|
||||
"tokio",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@ -3839,8 +4265,8 @@ dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
"bytes",
|
||||
"futures-util",
|
||||
"http",
|
||||
"http-body",
|
||||
"http 1.3.1",
|
||||
"http-body 1.0.1",
|
||||
"iri-string",
|
||||
"pin-project-lite",
|
||||
"tower",
|
||||
@ -4032,6 +4458,12 @@ version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
@ -4435,6 +4867,15 @@ dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@ -4468,6 +4909,21 @@ dependencies = [
|
||||
"windows_x86_64_msvc 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
@ -4508,6 +4964,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -4520,6 +4982,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
@ -4532,6 +5000,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
@ -4550,6 +5024,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
@ -4562,6 +5042,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
@ -4574,6 +5060,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
@ -4586,6 +5078,12 @@ version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
@ -4610,6 +5108,16 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.55.0"
|
||||
@ -4650,7 +5158,7 @@ dependencies = [
|
||||
"gdkx11",
|
||||
"gtk",
|
||||
"html5ever",
|
||||
"http",
|
||||
"http 1.3.1",
|
||||
"javascriptcore-rs",
|
||||
"jni",
|
||||
"kuchikiki",
|
||||
|
@ -23,3 +23,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
log = "0.4"
|
||||
tauri = { version = "2.5.0", features = [] }
|
||||
tauri-plugin-log = "2.0.0-rc"
|
||||
tauri-plugin-shell = "2.1.0"
|
||||
tokio = { version = "1.0", features = ["time"] }
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
|
@ -1,3 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
tauri_build::build()
|
||||
}
|
||||
|
@ -1,6 +1,426 @@
|
||||
use tauri_plugin_shell::ShellExt;
|
||||
use tauri::Manager;
|
||||
|
||||
// Store backend process handle and logs globally
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Arc;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
static BACKEND_PROCESS: Mutex<Option<Arc<tauri_plugin_shell::process::CommandChild>>> = Mutex::new(None);
|
||||
static BACKEND_LOGS: Mutex<VecDeque<String>> = Mutex::new(VecDeque::new());
|
||||
|
||||
// Helper function to add log entry
|
||||
fn add_log(message: String) {
|
||||
let mut logs = BACKEND_LOGS.lock().unwrap();
|
||||
logs.push_back(format!("{}: {}", std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(), message));
|
||||
// Keep only last 100 log entries
|
||||
if logs.len() > 100 {
|
||||
logs.pop_front();
|
||||
}
|
||||
println!("{}", message); // Also print to console
|
||||
}
|
||||
|
||||
// Command to get backend logs
|
||||
#[tauri::command]
|
||||
async fn get_backend_logs() -> Result<Vec<String>, String> {
|
||||
let logs = BACKEND_LOGS.lock().unwrap();
|
||||
Ok(logs.iter().cloned().collect())
|
||||
}
|
||||
|
||||
// Command to start the backend sidecar
|
||||
#[tauri::command]
|
||||
async fn start_backend(app: tauri::AppHandle) -> Result<String, String> {
|
||||
add_log("🚀 Attempting to start backend sidecar...".to_string());
|
||||
|
||||
// Check if backend is already running
|
||||
{
|
||||
let process_guard = BACKEND_PROCESS.lock().unwrap();
|
||||
if process_guard.is_some() {
|
||||
add_log("⚠️ Backend already running, skipping start".to_string());
|
||||
return Ok("Backend already running".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
add_log("📋 Creating Java command to run JAR directly".to_string());
|
||||
|
||||
// Use Tauri's resource API to find the JAR file
|
||||
let resource_dir = app.path().resource_dir().map_err(|e| {
|
||||
let error_msg = format!("❌ Failed to get resource directory: {}", e);
|
||||
add_log(error_msg.clone());
|
||||
error_msg
|
||||
})?;
|
||||
|
||||
add_log(format!("🔍 Looking for JAR in Tauri resource directory: {:?}", resource_dir));
|
||||
|
||||
// In dev mode, resources are in target/debug/libs, in production they're bundled
|
||||
let libs_dir = resource_dir.join("libs");
|
||||
add_log(format!("🔍 Checking libs directory: {:?}", libs_dir));
|
||||
|
||||
// Find all Stirling-PDF JAR files and pick the latest version
|
||||
let mut jar_files: Vec<_> = std::fs::read_dir(&libs_dir)
|
||||
.map_err(|e| {
|
||||
let error_msg = format!("Failed to read libs directory: {}. Make sure the JAR is copied to frontend/src-tauri/libs/", e);
|
||||
add_log(error_msg.clone());
|
||||
error_msg
|
||||
})?
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter(|entry| {
|
||||
let path = entry.path();
|
||||
path.extension().and_then(|s| s.to_str()) == Some("jar")
|
||||
&& path.file_name().unwrap().to_string_lossy().contains("Stirling-PDF")
|
||||
})
|
||||
.collect();
|
||||
|
||||
if jar_files.is_empty() {
|
||||
let error_msg = "No Stirling-PDF JAR found in Tauri resources/libs directory. Please run the build script to generate and copy the JAR.".to_string();
|
||||
add_log(error_msg.clone());
|
||||
return Err(error_msg);
|
||||
}
|
||||
|
||||
// Sort by filename to get the latest version (assumes semantic versioning in filename)
|
||||
jar_files.sort_by(|a, b| {
|
||||
let name_a = a.file_name().to_string_lossy().to_string();
|
||||
let name_b = b.file_name().to_string_lossy().to_string();
|
||||
name_b.cmp(&name_a) // Reverse order to get latest first
|
||||
});
|
||||
|
||||
let jar_path = jar_files[0].path();
|
||||
add_log(format!("📋 Selected latest JAR from {} available: {:?}", jar_files.len(), jar_path.file_name().unwrap()));
|
||||
|
||||
// Normalize the path to remove Windows UNC prefix \\?\
|
||||
let normalized_jar_path = if cfg!(windows) {
|
||||
let path_str = jar_path.to_string_lossy();
|
||||
if path_str.starts_with(r"\\?\") {
|
||||
std::path::PathBuf::from(&path_str[4..]) // Remove \\?\ prefix
|
||||
} else {
|
||||
jar_path.clone()
|
||||
}
|
||||
} else {
|
||||
jar_path.clone()
|
||||
};
|
||||
|
||||
add_log(format!("📦 Found JAR file in resources: {:?}", jar_path));
|
||||
add_log(format!("📦 Normalized JAR path: {:?}", normalized_jar_path));
|
||||
|
||||
// Log the equivalent command for external testing
|
||||
let java_command = format!(
|
||||
"java -Xmx2g -DBROWSER_OPEN=false -DSTIRLING_PDF_DESKTOP_UI=true -jar \"{}\"",
|
||||
normalized_jar_path.display()
|
||||
);
|
||||
add_log(format!("🔧 Equivalent command to run externally: {}", java_command));
|
||||
|
||||
// Create Java command directly
|
||||
let sidecar_command = app
|
||||
.shell()
|
||||
.command("java")
|
||||
.args([
|
||||
"-Xmx2g",
|
||||
"-DBROWSER_OPEN=false",
|
||||
"-jar",
|
||||
normalized_jar_path.to_str().unwrap()
|
||||
]);
|
||||
|
||||
add_log("⚙️ Sidecar command created, attempting to spawn...".to_string());
|
||||
|
||||
let (mut rx, child) = sidecar_command
|
||||
.spawn()
|
||||
.map_err(|e| {
|
||||
let error_msg = format!("❌ Failed to spawn sidecar: {}", e);
|
||||
add_log(error_msg.clone());
|
||||
error_msg
|
||||
})?;
|
||||
|
||||
// Store the process handle
|
||||
{
|
||||
let mut process_guard = BACKEND_PROCESS.lock().unwrap();
|
||||
*process_guard = Some(Arc::new(child));
|
||||
}
|
||||
|
||||
add_log("✅ Sidecar spawned successfully, monitoring output...".to_string());
|
||||
|
||||
// Listen to sidecar output for debugging
|
||||
tokio::spawn(async move {
|
||||
let mut startup_detected = false;
|
||||
let mut error_count = 0;
|
||||
|
||||
while let Some(event) = rx.recv().await {
|
||||
match event {
|
||||
tauri_plugin_shell::process::CommandEvent::Stdout(output) => {
|
||||
let output_str = String::from_utf8_lossy(&output);
|
||||
add_log(format!("📤 Backend stdout: {}", output_str));
|
||||
|
||||
// Look for startup indicators
|
||||
if output_str.contains("Started SPDFApplication") ||
|
||||
output_str.contains("Tomcat started") ||
|
||||
output_str.contains("Started on port") ||
|
||||
output_str.contains("Netty started") ||
|
||||
output_str.contains("Started StirlingPDF") {
|
||||
startup_detected = true;
|
||||
add_log(format!("🎉 Backend startup detected: {}", output_str));
|
||||
}
|
||||
|
||||
// Look for port binding
|
||||
if output_str.contains("8080") {
|
||||
add_log(format!("🔌 Port 8080 related output: {}", output_str));
|
||||
}
|
||||
}
|
||||
tauri_plugin_shell::process::CommandEvent::Stderr(output) => {
|
||||
let output_str = String::from_utf8_lossy(&output);
|
||||
add_log(format!("📥 Backend stderr: {}", output_str));
|
||||
|
||||
// Look for error indicators
|
||||
if output_str.contains("ERROR") || output_str.contains("Exception") || output_str.contains("FATAL") {
|
||||
error_count += 1;
|
||||
add_log(format!("⚠️ Backend error #{}: {}", error_count, output_str));
|
||||
}
|
||||
|
||||
// Look for specific common issues
|
||||
if output_str.contains("Address already in use") {
|
||||
add_log("🚨 CRITICAL: Port 8080 is already in use by another process!".to_string());
|
||||
}
|
||||
if output_str.contains("java.lang.ClassNotFoundException") {
|
||||
add_log("🚨 CRITICAL: Missing Java dependencies!".to_string());
|
||||
}
|
||||
if output_str.contains("java.io.FileNotFoundException") {
|
||||
add_log("🚨 CRITICAL: Required file not found!".to_string());
|
||||
}
|
||||
}
|
||||
tauri_plugin_shell::process::CommandEvent::Error(error) => {
|
||||
add_log(format!("❌ Backend process error: {}", error));
|
||||
}
|
||||
tauri_plugin_shell::process::CommandEvent::Terminated(payload) => {
|
||||
add_log(format!("💀 Backend terminated with code: {:?}", payload.code));
|
||||
if let Some(code) = payload.code {
|
||||
match code {
|
||||
0 => println!("✅ Process terminated normally"),
|
||||
1 => println!("❌ Process terminated with generic error"),
|
||||
2 => println!("❌ Process terminated due to misuse"),
|
||||
126 => println!("❌ Command invoked cannot execute"),
|
||||
127 => println!("❌ Command not found"),
|
||||
128 => println!("❌ Invalid exit argument"),
|
||||
130 => println!("❌ Process terminated by Ctrl+C"),
|
||||
_ => println!("❌ Process terminated with code: {}", code),
|
||||
}
|
||||
}
|
||||
// Clear the stored process handle
|
||||
let mut process_guard = BACKEND_PROCESS.lock().unwrap();
|
||||
*process_guard = None;
|
||||
}
|
||||
_ => {
|
||||
println!("🔍 Unknown command event: {:?}", event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if error_count > 0 {
|
||||
println!("⚠️ Backend process ended with {} errors detected", error_count);
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the backend to start
|
||||
println!("⏳ Waiting for backend startup...");
|
||||
tokio::time::sleep(std::time::Duration::from_millis(5000)).await;
|
||||
|
||||
Ok("Backend startup initiated successfully".to_string())
|
||||
}
|
||||
|
||||
// Command to check if backend is healthy
|
||||
#[tauri::command]
|
||||
async fn check_backend_health() -> Result<bool, String> {
|
||||
println!("🔍 Checking backend health...");
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.build()
|
||||
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
|
||||
|
||||
match client.get("http://localhost:8080/actuator/health").send().await {
|
||||
Ok(response) => {
|
||||
let status = response.status();
|
||||
println!("💓 Health check response status: {}", status);
|
||||
if status.is_success() {
|
||||
match response.text().await {
|
||||
Ok(body) => {
|
||||
println!("💓 Health check response: {}", body);
|
||||
Ok(true)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("⚠️ Failed to read health response: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("⚠️ Health check failed with status: {}", status);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Health check error: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Command to get backend process status
|
||||
#[tauri::command]
|
||||
async fn get_backend_status() -> Result<String, String> {
|
||||
let process_guard = BACKEND_PROCESS.lock().unwrap();
|
||||
match process_guard.as_ref() {
|
||||
Some(child) => {
|
||||
// Try to check if process is still alive
|
||||
let pid = child.pid();
|
||||
println!("🔍 Checking backend process status, PID: {}", pid);
|
||||
Ok(format!("Backend process is running (PID: {})", pid))
|
||||
},
|
||||
None => Ok("Backend process is not running".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
// Command to check if backend port is accessible
|
||||
#[tauri::command]
|
||||
async fn check_backend_port() -> Result<bool, String> {
|
||||
println!("🔍 Checking if port 8080 is accessible...");
|
||||
let client = reqwest::Client::builder()
|
||||
.timeout(std::time::Duration::from_secs(3))
|
||||
.build()
|
||||
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
|
||||
|
||||
match client.head("http://localhost:8080/").send().await {
|
||||
Ok(response) => {
|
||||
println!("✅ Port 8080 responded with status: {}", response.status());
|
||||
Ok(true)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Port 8080 not accessible: {}", e);
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Command to check if JAR file exists
|
||||
#[tauri::command]
|
||||
async fn check_jar_exists(app: tauri::AppHandle) -> Result<String, String> {
|
||||
println!("🔍 Checking for JAR files in Tauri resources...");
|
||||
|
||||
// Check in the Tauri resource directory (bundled)
|
||||
if let Ok(resource_dir) = app.path().resource_dir() {
|
||||
let jar_path = resource_dir;
|
||||
println!("Checking bundled resources: {:?}", jar_path);
|
||||
|
||||
if jar_path.exists() {
|
||||
match std::fs::read_dir(&jar_path) {
|
||||
Ok(entries) => {
|
||||
let mut jar_files = Vec::new();
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("jar")
|
||||
&& path.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.contains("Stirling-PDF") {
|
||||
jar_files.push(path.file_name().unwrap().to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !jar_files.is_empty() {
|
||||
println!("✅ Found JAR files in bundled resources: {:?}", jar_files);
|
||||
return Ok(format!("Found JAR files: {:?}", jar_files));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Failed to read resource directory: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check in development mode location (libs directory)
|
||||
let dev_jar_path = std::path::PathBuf::from("libs");
|
||||
println!("Checking development libs directory: {:?}", dev_jar_path);
|
||||
|
||||
if dev_jar_path.exists() {
|
||||
match std::fs::read_dir(&dev_jar_path) {
|
||||
Ok(entries) => {
|
||||
let mut jar_files = Vec::new();
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("jar")
|
||||
&& path.file_name()
|
||||
.unwrap()
|
||||
.to_string_lossy()
|
||||
.contains("Stirling-PDF") {
|
||||
jar_files.push(path.file_name().unwrap().to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
if !jar_files.is_empty() {
|
||||
println!("✅ Found JAR files in development libs: {:?}", jar_files);
|
||||
return Ok(format!("Found JAR files: {:?}", jar_files));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Failed to read libs directory: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("❌ No Stirling-PDF JAR files found");
|
||||
Ok("No Stirling-PDF JAR files found. Please run './build-tauri.sh' or 'build-tauri.bat' to build and copy the JAR.".to_string())
|
||||
}
|
||||
|
||||
// Command to test sidecar binary directly
|
||||
#[tauri::command]
|
||||
async fn test_sidecar_binary(app: tauri::AppHandle) -> Result<String, String> {
|
||||
println!("🔍 Testing sidecar binary availability...");
|
||||
|
||||
// Test if we can create the sidecar command (this validates the binary exists)
|
||||
match app.shell().sidecar("stirling-pdf-backend") {
|
||||
Ok(_) => {
|
||||
println!("✅ Sidecar binary 'stirling-pdf-backend' is available");
|
||||
Ok("Sidecar binary 'stirling-pdf-backend' is available and can be executed".to_string())
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Failed to access sidecar binary: {}", e);
|
||||
Ok(format!("Sidecar binary not available: {}. Make sure the binary exists in the binaries/ directory with correct permissions.", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Command to check Java environment
|
||||
#[tauri::command]
|
||||
async fn check_java_environment() -> Result<String, String> {
|
||||
println!("🔍 Checking Java environment...");
|
||||
|
||||
let output = std::process::Command::new("java")
|
||||
.arg("--version")
|
||||
.output();
|
||||
|
||||
match output {
|
||||
Ok(output) => {
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
let version_info = if !stdout.is_empty() { stdout } else { stderr };
|
||||
println!("✅ Java found: {}", version_info);
|
||||
Ok(format!("Java available: {}", version_info.trim()))
|
||||
} else {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
println!("❌ Java command failed: {}", stderr);
|
||||
Ok(format!("Java command failed: {}", stderr))
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("❌ Java not found: {}", e);
|
||||
Ok(format!("Java not found or not in PATH: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.setup(|app| {
|
||||
if cfg!(debug_assertions) {
|
||||
app.handle().plugin(
|
||||
@ -9,8 +429,24 @@ pub fn run() {
|
||||
.build(),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Automatically start the backend when Tauri starts
|
||||
let app_handle = app.handle().clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
tokio::time::sleep(std::time::Duration::from_millis(1000)).await; // Small delay to ensure app is ready
|
||||
match start_backend(app_handle).await {
|
||||
Ok(result) => {
|
||||
add_log(format!("🚀 Auto-started backend on Tauri startup: {}", result));
|
||||
}
|
||||
Err(error) => {
|
||||
add_log(format!("❌ Failed to auto-start backend: {}", error));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![start_backend, check_backend_health, check_jar_exists, test_sidecar_binary, get_backend_status, check_backend_port, check_java_environment, get_backend_logs])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
{
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"productName": "Stirling-PDF",
|
||||
"version": "0.1.0",
|
||||
"identifier": "com.tauri.dev",
|
||||
"version": "2.0.0",
|
||||
"identifier": "stirling.pdf.dev",
|
||||
"build": {
|
||||
"frontendDist": "./public",
|
||||
"frontendDist": "../dist",
|
||||
"devUrl": "http://localhost:5173",
|
||||
"beforeDevCommand": "npm run dev",
|
||||
"beforeBuildCommand": "npm run build"
|
||||
@ -30,6 +30,14 @@
|
||||
"icons/32x32.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [
|
||||
"libs/*.jar"
|
||||
]
|
||||
},
|
||||
"plugins": {
|
||||
"shell": {
|
||||
"open": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,26 @@
|
||||
import './index.css';
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import HomePage from './pages/HomePage';
|
||||
import { SidecarTest } from './components/SidecarTest';
|
||||
|
||||
export default function App() {
|
||||
return <HomePage/>;
|
||||
const [showTests, setShowTests] = useState(true); // Start with tests visible
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100">
|
||||
<div className="bg-white shadow-sm border-b">
|
||||
<div className="max-w-4xl mx-auto px-4 py-3 flex justify-between items-center">
|
||||
<h1 className="text-xl font-bold">Stirling PDF - Tauri Integration</h1>
|
||||
<button
|
||||
onClick={() => setShowTests(!showTests)}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
>
|
||||
{showTests ? 'Show App' : 'Show Tests'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showTests ? <SidecarTest /> : <HomePage />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
124
frontend/src/components/BackendStatus.tsx
Normal file
124
frontend/src/components/BackendStatus.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { backendService } from '../services/backendService';
|
||||
|
||||
interface BackendStatusProps {}
|
||||
|
||||
export const BackendStatus: React.FC<BackendStatusProps> = () => {
|
||||
const [status, setStatus] = useState<'starting' | 'healthy' | 'error' | 'unknown'>('unknown');
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [debugInfo, setDebugInfo] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
runDiagnostics();
|
||||
}, []);
|
||||
|
||||
const runDiagnostics = async () => {
|
||||
const info: string[] = [];
|
||||
|
||||
try {
|
||||
// Check if JAR exists
|
||||
const jarCheck = await invoke('check_jar_exists') as string;
|
||||
info.push(`JAR Check: ${jarCheck}`);
|
||||
|
||||
// Check if sidecar binary exists
|
||||
const binaryCheck = await invoke('test_sidecar_binary') as string;
|
||||
info.push(`Binary Check: ${binaryCheck}`);
|
||||
|
||||
setDebugInfo(info);
|
||||
} catch (err) {
|
||||
info.push(`Diagnostic Error: ${err}`);
|
||||
setDebugInfo(info);
|
||||
}
|
||||
};
|
||||
|
||||
const initializeBackend = async () => {
|
||||
try {
|
||||
setStatus('starting');
|
||||
setError(null);
|
||||
|
||||
await backendService.startBackend();
|
||||
setStatus('healthy');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
||||
setStatus('error');
|
||||
}
|
||||
};
|
||||
|
||||
const checkHealth = async () => {
|
||||
const isHealthy = await backendService.checkHealth();
|
||||
setStatus(isHealthy ? 'healthy' : 'error');
|
||||
};
|
||||
|
||||
const getStatusColor = () => {
|
||||
switch (status) {
|
||||
case 'healthy': return 'text-green-600';
|
||||
case 'starting': return 'text-yellow-600';
|
||||
case 'error': return 'text-red-600';
|
||||
default: return 'text-gray-600';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = () => {
|
||||
switch (status) {
|
||||
case 'healthy': return 'Backend Running';
|
||||
case 'starting': return 'Starting Backend...';
|
||||
case 'error': return 'Backend Error';
|
||||
default: return 'Backend Status Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 border rounded-lg">
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-lg font-semibold">Backend Status</h3>
|
||||
<button
|
||||
onClick={checkHealth}
|
||||
className="px-3 py-1 text-sm bg-blue-500 text-white rounded hover:bg-blue-600"
|
||||
>
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={`mt-2 font-medium ${getStatusColor()}`}>
|
||||
{getStatusText()}
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className="mt-2 text-sm text-red-600 bg-red-50 p-2 rounded">
|
||||
Error: {error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === 'healthy' && (
|
||||
<div className="mt-2 text-sm text-gray-600">
|
||||
Backend URL: {backendService.getBackendUrl()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{status === 'error' && (
|
||||
<button
|
||||
onClick={initializeBackend}
|
||||
className="mt-2 px-3 py-1 text-sm bg-green-500 text-white rounded hover:bg-green-600"
|
||||
>
|
||||
Retry Start
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="mt-4">
|
||||
<h4 className="text-sm font-medium text-gray-700">Debug Information:</h4>
|
||||
<div className="mt-2 text-xs text-gray-600 bg-gray-50 p-2 rounded max-h-32 overflow-y-auto">
|
||||
{debugInfo.map((info, index) => (
|
||||
<div key={index}>{info}</div>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={runDiagnostics}
|
||||
className="mt-2 px-2 py-1 text-xs bg-gray-500 text-white rounded hover:bg-gray-600"
|
||||
>
|
||||
Refresh Diagnostics
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
315
frontend/src/components/SidecarTest.tsx
Normal file
315
frontend/src/components/SidecarTest.tsx
Normal file
@ -0,0 +1,315 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
interface DiagnosticResult {
|
||||
timestamp: string;
|
||||
level: 'info' | 'warning' | 'error' | 'success';
|
||||
message: string;
|
||||
details?: string;
|
||||
}
|
||||
|
||||
export const SidecarTest: React.FC = () => {
|
||||
const [logs, setLogs] = useState<DiagnosticResult[]>([]);
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
const [autoStart, setAutoStart] = useState(true);
|
||||
|
||||
const addLog = (level: DiagnosticResult['level'], message: string, details?: string) => {
|
||||
const timestamp = new Date().toLocaleTimeString();
|
||||
setLogs(prev => [...prev, { timestamp, level, message, details }]);
|
||||
console.log(`[${timestamp}] ${level.toUpperCase()}: ${message}`, details || '');
|
||||
};
|
||||
|
||||
const clearLogs = () => setLogs([]);
|
||||
|
||||
const runDiagnostics = async () => {
|
||||
setIsRunning(true);
|
||||
clearLogs();
|
||||
|
||||
addLog('info', 'Starting comprehensive sidecar diagnostics...');
|
||||
|
||||
try {
|
||||
// Step 1: Environment Check
|
||||
addLog('info', 'Checking environment...');
|
||||
|
||||
// Check Java first
|
||||
try {
|
||||
const javaResult = await invoke('check_java_environment') as string;
|
||||
addLog('info', 'Java Environment Check:', javaResult);
|
||||
if (javaResult.includes('not found') || javaResult.includes('failed')) {
|
||||
addLog('error', 'Java is not available', 'Please install Java 17+ and ensure it is in your PATH');
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('error', 'Failed to check Java environment', String(error));
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const jarResult = await invoke('check_jar_exists') as string;
|
||||
addLog('info', 'JAR Check Result:', jarResult);
|
||||
if (!jarResult.includes('Found JAR files')) {
|
||||
addLog('error', 'No JAR files found - build required!', 'You need to build the Java backend first');
|
||||
addLog('info', 'To fix this, run one of these commands:');
|
||||
addLog('info', '• Linux/Mac: ./build-tauri.sh');
|
||||
addLog('info', '• Windows: build-tauri.bat');
|
||||
addLog('info', '• Or manually: ./gradlew bootJar && cd frontend && npx tauri dev');
|
||||
addLog('info', 'The JAR should be created in build/libs/ directory');
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('error', 'Failed to check JAR files', String(error));
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const binaryResult = await invoke('test_sidecar_binary') as string;
|
||||
addLog('info', 'Binary Check Result:', binaryResult);
|
||||
if (!binaryResult.includes('Binary exists')) {
|
||||
addLog('error', 'Sidecar binary not found', binaryResult);
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('error', 'Failed to check sidecar binary', String(error));
|
||||
setIsRunning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Start Backend
|
||||
addLog('info', 'Attempting to start backend sidecar...');
|
||||
try {
|
||||
const startResult = await invoke('start_backend') as string;
|
||||
addLog('info', 'Backend start command result:', startResult);
|
||||
|
||||
// Wait a moment for process to initialize
|
||||
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
// Check if process is actually running
|
||||
const statusResult = await invoke('get_backend_status') as string;
|
||||
addLog('info', 'Backend process status:', statusResult);
|
||||
|
||||
if (statusResult.includes('not running')) {
|
||||
addLog('error', 'Backend process failed to start or crashed immediately');
|
||||
addLog('info', 'This could be due to:');
|
||||
addLog('info', '- Java not installed or not in PATH');
|
||||
addLog('info', '- Port 8080 already in use');
|
||||
addLog('info', '- JAR file corruption');
|
||||
addLog('info', '- Missing dependencies');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
addLog('error', 'Failed to start backend', String(error));
|
||||
}
|
||||
|
||||
// Step 3: Port Testing
|
||||
addLog('info', 'Testing port connectivity...');
|
||||
let attempts = 0;
|
||||
const maxAttempts = 15;
|
||||
let connected = false;
|
||||
|
||||
while (attempts < maxAttempts && !connected) {
|
||||
attempts++;
|
||||
addLog('info', `Port test attempt ${attempts}/${maxAttempts}...`);
|
||||
|
||||
try {
|
||||
const portResult = await invoke('check_backend_port') as boolean;
|
||||
if (portResult) {
|
||||
addLog('success', 'Port 8080 is responding!');
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('warning', `Port check via Rust failed: ${error}`);
|
||||
}
|
||||
|
||||
// Fallback: direct fetch
|
||||
try {
|
||||
const response = await fetch('http://localhost:8080/', {
|
||||
method: 'HEAD',
|
||||
signal: AbortSignal.timeout(3000)
|
||||
});
|
||||
addLog('success', `Direct HTTP test successful: ${response.status}`);
|
||||
connected = true;
|
||||
break;
|
||||
} catch (fetchError) {
|
||||
addLog('warning', `HTTP test failed: ${fetchError}`);
|
||||
}
|
||||
|
||||
if (attempts < maxAttempts) {
|
||||
await new Promise(resolve => setTimeout(resolve, 4000));
|
||||
}
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
addLog('error', 'Backend is not responding on port 8080 after 60 seconds');
|
||||
addLog('info', 'Possible solutions:');
|
||||
addLog('info', '1. Check if Java is installed: java --version');
|
||||
addLog('info', '2. Check if port 8080 is free: netstat -an | grep 8080');
|
||||
addLog('info', '3. Try running the JAR manually from terminal');
|
||||
addLog('info', '4. Check firewall settings');
|
||||
} else {
|
||||
// Step 4: Get detailed sidecar logs
|
||||
addLog('info', 'Fetching detailed sidecar logs...');
|
||||
try {
|
||||
const sidecarLogs = await invoke('get_backend_logs') as string[];
|
||||
if (sidecarLogs.length > 0) {
|
||||
addLog('info', 'Sidecar execution logs:');
|
||||
sidecarLogs.forEach(log => {
|
||||
addLog('info', log);
|
||||
});
|
||||
} else {
|
||||
addLog('warning', 'No sidecar logs available - this suggests the sidecar never started');
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('error', 'Failed to get sidecar logs', String(error));
|
||||
}
|
||||
|
||||
// Step 5: API Testing
|
||||
addLog('info', 'Testing API endpoints...');
|
||||
|
||||
const endpoints = [
|
||||
{ path: '/', description: 'Home page' },
|
||||
{ path: '/actuator/health', description: 'Health endpoint' },
|
||||
{ path: '/actuator/info', description: 'Info endpoint' }
|
||||
];
|
||||
|
||||
for (const endpoint of endpoints) {
|
||||
try {
|
||||
const response = await fetch(`http://localhost:8080${endpoint.path}`);
|
||||
if (response.ok) {
|
||||
const contentType = response.headers.get('content-type');
|
||||
let preview = '';
|
||||
if (contentType?.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
preview = JSON.stringify(data).substring(0, 100) + '...';
|
||||
} else {
|
||||
const text = await response.text();
|
||||
preview = text.substring(0, 100) + '...';
|
||||
}
|
||||
addLog('success', `${endpoint.description} working`, `Status: ${response.status}, Preview: ${preview}`);
|
||||
} else {
|
||||
addLog('warning', `${endpoint.description} returned ${response.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
addLog('error', `${endpoint.description} failed`, String(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
addLog('error', 'Diagnostic process failed', String(error));
|
||||
} finally {
|
||||
setIsRunning(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-run diagnostics on mount
|
||||
useEffect(() => {
|
||||
if (autoStart) {
|
||||
const timer = setTimeout(() => {
|
||||
runDiagnostics();
|
||||
}, 1000);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [autoStart]);
|
||||
|
||||
const getLogColor = (level: DiagnosticResult['level']) => {
|
||||
switch (level) {
|
||||
case 'info': return 'text-blue-700 bg-blue-50 border-blue-200';
|
||||
case 'warning': return 'text-yellow-700 bg-yellow-50 border-yellow-200';
|
||||
case 'error': return 'text-red-700 bg-red-50 border-red-200';
|
||||
case 'success': return 'text-green-700 bg-green-50 border-green-200';
|
||||
}
|
||||
};
|
||||
|
||||
const getLogIcon = (level: DiagnosticResult['level']) => {
|
||||
switch (level) {
|
||||
case 'info': return 'ℹ️';
|
||||
case 'warning': return '⚠️';
|
||||
case 'error': return '❌';
|
||||
case 'success': return '✅';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-6xl mx-auto">
|
||||
<div className="bg-white rounded-lg shadow-lg p-6">
|
||||
<h1 className="text-2xl font-bold mb-6 text-center">Backend Sidecar Diagnostics</h1>
|
||||
|
||||
<div className="mb-6 flex gap-4 justify-center">
|
||||
<button
|
||||
onClick={runDiagnostics}
|
||||
disabled={isRunning}
|
||||
className={`px-6 py-3 rounded-lg font-medium ${
|
||||
isRunning
|
||||
? 'bg-gray-400 cursor-not-allowed'
|
||||
: 'bg-blue-600 hover:bg-blue-700 text-white'
|
||||
}`}
|
||||
>
|
||||
{isRunning ? 'Running Diagnostics...' : 'Run Diagnostics'}
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={clearLogs}
|
||||
disabled={isRunning}
|
||||
className="px-6 py-3 rounded-lg font-medium bg-gray-600 hover:bg-gray-700 text-white disabled:bg-gray-400"
|
||||
>
|
||||
Clear Logs
|
||||
</button>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={autoStart}
|
||||
onChange={(e) => setAutoStart(e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
<span className="text-sm">Auto-start diagnostics</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="bg-gray-900 rounded-lg p-4 max-h-96 overflow-y-auto">
|
||||
{logs.length === 0 ? (
|
||||
<div className="text-gray-400 text-center py-8">
|
||||
No diagnostic logs yet. Click "Run Diagnostics" to start.
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{logs.map((log, index) => (
|
||||
<div key={index} className={`p-3 rounded border ${getLogColor(log.level)}`}>
|
||||
<div className="flex items-start gap-2">
|
||||
<span className="text-lg">{getLogIcon(log.level)}</span>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-mono text-gray-500">{log.timestamp}</span>
|
||||
<span className="font-medium">{log.message}</span>
|
||||
</div>
|
||||
{log.details && (
|
||||
<div className="mt-1 text-sm font-mono bg-gray-100 p-2 rounded">
|
||||
{log.details}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{logs.length > 0 && (
|
||||
<div className="mt-4 text-sm text-gray-600">
|
||||
Total logs: {logs.length} |
|
||||
Errors: {logs.filter(l => l.level === 'error').length} |
|
||||
Warnings: {logs.filter(l => l.level === 'warning').length} |
|
||||
Success: {logs.filter(l => l.level === 'success').length}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
73
frontend/src/services/backendService.ts
Normal file
73
frontend/src/services/backendService.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
export class BackendService {
|
||||
private static instance: BackendService;
|
||||
private backendStarted = false;
|
||||
|
||||
static getInstance(): BackendService {
|
||||
if (!BackendService.instance) {
|
||||
BackendService.instance = new BackendService();
|
||||
}
|
||||
return BackendService.instance;
|
||||
}
|
||||
|
||||
async startBackend(): Promise<void> {
|
||||
if (this.backendStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await invoke('start_backend');
|
||||
console.log('Backend started:', result);
|
||||
this.backendStarted = true;
|
||||
|
||||
// Wait for backend to be healthy
|
||||
await this.waitForHealthy();
|
||||
} catch (error) {
|
||||
console.error('Failed to start backend:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async checkHealth(): Promise<boolean> {
|
||||
try {
|
||||
return await invoke('check_backend_health');
|
||||
} catch (error) {
|
||||
console.error('Health check failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async waitForHealthy(maxAttempts = 30): Promise<void> {
|
||||
for (let i = 0; i < maxAttempts; i++) {
|
||||
const isHealthy = await this.checkHealth();
|
||||
if (isHealthy) {
|
||||
console.log('Backend is healthy');
|
||||
return;
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
throw new Error('Backend failed to become healthy after 30 seconds');
|
||||
}
|
||||
|
||||
getBackendUrl(): string {
|
||||
return 'http://localhost:8080';
|
||||
}
|
||||
|
||||
async makeApiCall(endpoint: string, options?: RequestInit): Promise<Response> {
|
||||
if (!this.backendStarted) {
|
||||
await this.startBackend();
|
||||
}
|
||||
|
||||
const url = `${this.getBackendUrl()}${endpoint}`;
|
||||
return fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const backendService = BackendService.getInstance();
|
Loading…
x
Reference in New Issue
Block a user