Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
draft: false
prerelease: ${{ contains(env.APP_VERSION, '-beta') || contains(env.APP_VERSION, '-alpha') || contains(env.APP_VERSION, '-rc') }}
files: |
dist/stasis-backend-v*.exe
dist/stasis-backend-v*.zip
frontend/src-tauri/target/release/bundle/nsis/*.exe
frontend/src-tauri/target/release/bundle/nsis/*.msi
frontend/src-tauri/target/release/bundle/zip/*.zip
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,16 +303,16 @@ From PowerShell in the project root:
|---|---|
| **1** | Syncs the version string into `tauri.conf.json`, `package.json`, and `Cargo.toml` |
| **2** | Generates `file_version_info.txt` for Windows EXE metadata |
| **3** | Runs PyInstaller using `stasis-backend.spec` → `dist/stasis-backend.exe` |
| **4** | Copies the backend EXE to `frontend/src-tauri/bin/` |
| **3** | Runs PyInstaller using `stasis-backend.spec` → `dist/stasis-backend/` (onedir) |
| **4** | Copies the backend directory to `frontend/src-tauri/bin/stasis-backend/` |
| **5** | Runs `npm install` inside `frontend/` |
| **6** | Runs `npm run tauri:build` (Vite + Rust + NSIS bundling) |

**Output artifacts:**

```
dist/
stasis-backend-v<version>.exe # Standalone backend (≈100 MB)
stasis-backend-v<version>.zip # Standalone backend directory (zipped)
frontend/src-tauri/target/release/bundle/
nsis/
Stasis-<version>-setup.exe # Full installer
Expand Down
29 changes: 17 additions & 12 deletions build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ $ProjectRoot = $PSScriptRoot
$FrontendDir = Join-Path $ProjectRoot "frontend"
$BinDir = Join-Path $ProjectRoot "frontend\src-tauri\bin"
$SpecFile = Join-Path $ProjectRoot "stasis-backend.spec"
$BackendExe = Join-Path $BinDir "stasis-backend.exe"
$DistExe = Join-Path $ProjectRoot "dist\stasis-backend.exe"
$BackendDir = Join-Path $BinDir "stasis-backend"
$DistDir = Join-Path $ProjectRoot "dist\stasis-backend"
$DistExe = Join-Path $DistDir "stasis-backend.exe"

$TauriConf = Join-Path $FrontendDir "src-tauri\tauri.conf.json"
$PkgJson = Join-Path $FrontendDir "package.json"
Expand Down Expand Up @@ -196,16 +197,19 @@ if (-not (Test-Path $DistExe)) {
exit 1
}

Write-Host " Copying EXE to src-tauri/bin/ ..." -ForegroundColor Yellow
Copy-Item -Force $DistExe $BackendExe
Write-Host " Copying backend directory to src-tauri/bin/ ..." -ForegroundColor Yellow
if (Test-Path $BackendDir) {
Remove-Item -Recurse -Force $BackendDir
}
Copy-Item -Recurse -Force $DistDir $BackendDir

$exeSize = [math]::Round((Get-Item $BackendExe).Length / 1MB, 1)
Write-Host " [OK] stasis-backend.exe copied ($exeSize MB)" -ForegroundColor Green
$dirSizeMB = [math]::Round((Get-ChildItem $BackendDir -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB, 1)
Write-Host " [OK] stasis-backend dir copied ($dirSizeMB MB)" -ForegroundColor Green

$VersionedExeName = "stasis-backend-v$Version.exe"
$VersionedExePath = Join-Path $ProjectRoot "dist\$VersionedExeName"
Rename-Item -Path $DistExe -NewName $VersionedExeName -Force
Write-Host " [OK] Standalone backend saved as dist\$VersionedExeName" -ForegroundColor Green
$VersionedZipName = "stasis-backend-v$Version.zip"
$VersionedZipPath = Join-Path $ProjectRoot "dist\$VersionedZipName"
Compress-Archive -Path $DistDir -DestinationPath $VersionedZipPath -Force
Write-Host " [OK] Standalone backend saved as dist\$VersionedZipName" -ForegroundColor Green

# -------------------------------------------------------
# 3. npm install (if needed)
Expand Down Expand Up @@ -257,8 +261,9 @@ else {
Write-Host " Bundle directory not found. Check Tauri build output above." -ForegroundColor Yellow
}

if (Test-Path $VersionedExePath) {
Write-Host " $VersionedExePath ($exeSize MB)" -ForegroundColor Green
if (Test-Path $VersionedZipPath) {
$zipSizeMB = [math]::Round((Get-Item $VersionedZipPath).Length / 1MB, 1)
Write-Host " $VersionedZipPath ($zipSizeMB MB)" -ForegroundColor Green
}

# Cleanup
Expand Down
4 changes: 2 additions & 2 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Stasis uses a **dual-process architecture**: a compiled Python telemetry engine

## Python backend

The backend is a single compiled `.exe` (PyInstaller) that spawns several daemon threads on startup.
The backend is a compiled directory (PyInstaller `--onedir`) that spawns several daemon threads on startup.

### Entry point (`src/main.py`)

Expand Down Expand Up @@ -177,7 +177,7 @@ frontend/src-tauri/target/release/bundle/

## Process communication

The Tauri shell launches `stasis-backend.exe` as a **sidecar process** (configured in `tauri.conf.json`). The React frontend communicates with the backend exclusively via HTTP requests to `http://127.0.0.1:7432`. There are no Tauri IPC commands used for data retrieval — the HTTP API is the single source of truth.
The Tauri shell launches `stasis-backend.exe` (from `bin/stasis-backend/`) as a **sidecar process** (configured in `tauri.conf.json`). The React frontend communicates with the backend exclusively via HTTP requests to `http://127.0.0.1:7432`. There are no Tauri IPC commands used for data retrieval — the HTTP API is the single source of truth.

This design means the Python backend can be run and tested independently of the Tauri shell.

Expand Down
10 changes: 5 additions & 5 deletions docs/developer-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,16 @@ The `build.ps1` script automates the entire release pipeline.
|---|---|
| **Version sync** | Updates the version string in `tauri.conf.json`, `package.json`, and `Cargo.toml` |
| **Win32 metadata** | Generates `file_version_info.txt` so the compiled EXE has correct version metadata in Windows Explorer |
| **PyInstaller** | Runs `pyinstaller stasis-backend.spec` → `dist/stasis-backend.exe` |
| **Copy sidecar** | Moves backend EXE to `frontend/src-tauri/bin/` so Tauri bundles it |
| **PyInstaller** | Runs `pyinstaller stasis-backend.spec` → `dist/stasis-backend/` (onedir) |
| **Copy sidecar** | Copies backend directory to `frontend/src-tauri/bin/stasis-backend/` so Tauri bundles it |
| **npm install** | Installs frontend dependencies (skipped if `node_modules` is up to date) |
| **Tauri build** | Runs `npm run tauri:build` inside `frontend/` — compiles Vite + Rust + generates NSIS installer |

### Output artifacts

```
dist/
stasis-backend-v1.2.3.exe ← Standalone backend (~100 MB)
stasis-backend-v1.2.3.zip ← Standalone backend directory (zipped)
frontend/src-tauri/target/release/bundle/
nsis/
Stasis-1.2.3-setup.exe ← Full NSIS installer
Expand All @@ -124,10 +124,10 @@ Key settings in the spec file:
| Setting | Value | Reason |
|---|---|---|
| `console = False` | Windowed mode | No terminal window pops up |
| `upx = True` | Compress with UPX | Reduces EXE size (requires UPX in PATH) |
| `upx = True` | Compress with UPX | Reduces binary sizes (requires UPX in PATH) |
| `hidden_imports` | flask, psutil, win32api, … | Ensure PyInstaller bundles all dynamic imports |
| `excludes` | unittest, matplotlib, scipy, pandas, … | Strips unused heavy libraries |
| `datas` | `app_categories.json`, `ignored_apps.json` | Bundle config JSONs into the EXE |
| `datas` | `app_categories.json`, `ignored_apps.json` | Bundle config JSONs into the output dir |

---

Expand Down
2 changes: 1 addition & 1 deletion frontend/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ fn start_backend(app: &AppHandle) {
// Resolve the bundled backend EXE path relative to the Resources dir
let resource_path = app
.path()
.resolve("bin/stasis-backend.exe", tauri::path::BaseDirectory::Resource)
.resolve("bin/stasis-backend/stasis-backend.exe", tauri::path::BaseDirectory::Resource)
.expect("Failed to resolve backend EXE path");

#[cfg(not(debug_assertions))]
Expand Down
6 changes: 3 additions & 3 deletions frontend/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@
"silent": true
}
},
"resources": {
"bin/stasis-backend.exe": "bin/stasis-backend.exe"
},
"resources": [
"bin/stasis-backend/**/*"
],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
Expand Down
14 changes: 10 additions & 4 deletions stasis-backend.spec
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='stasis-backend',
icon='backend-app-icon.ico',
Expand All @@ -48,12 +46,20 @@ exe = EXE(
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,

)

coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='stasis-backend',
)
Loading