Add Tauri desktop app scaffolding for offline KJV Study
Introduces a complete Tauri v2 project structure for building a native macOS desktop application. The app runs FastAPI as a sidecar process on port 31102 (number of KJV verses) and renders the existing web UI in a native WebKit webview. Key additions: - src-tauri/: Complete Tauri configuration and Rust source - Desktop entry point (kjvstudy_org/desktop.py) - PyInstaller bundling script for Python sidecar - Desktop-specific pyproject.toml without WeasyPrint - App icons for macOS (.icns) and Windows (.ico) - Makefile.desktop with build targets - Comprehensive DESKTOP.md documentation WeasyPrint is intentionally excluded from the desktop build to avoid native library bundling complexity. PDF buttons are automatically hidden when WeasyPrint is unavailable (existing graceful degradation). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@@ -0,0 +1,142 @@
|
||||
# KJV Study Desktop App
|
||||
|
||||
A fully offline desktop application for studying the King James Bible, built with [Tauri](https://tauri.app/).
|
||||
|
||||
## Features
|
||||
|
||||
Everything from kjvstudy.org, completely offline:
|
||||
|
||||
- **Complete KJV Bible** - All 31,102 verses from the 1769 Cambridge edition
|
||||
- **Verse Commentary** - In-depth theological analysis for 12,321+ verses
|
||||
- **Interlinear Bible** - Hebrew (OT) and Greek (NT) word-by-word analysis
|
||||
- **Strong's Concordance** - 14,298 Hebrew and Greek word definitions
|
||||
- **Cross-References** - Treasury of Scripture Knowledge
|
||||
- **Study Resources** - 36 study guides, 38 topics, 12 reading plans
|
||||
- **Family Trees** - 429+ biblical figures with genealogies
|
||||
- **Full-Text Search** - Fast SQLite FTS5 search across all verses
|
||||
- **Dark Mode** - System-aware theme switching
|
||||
- **Accessibility** - Full keyboard navigation, screen reader support
|
||||
|
||||
**Note:** PDF export is not available in the desktop version (WeasyPrint system dependencies are not bundled).
|
||||
|
||||
## Requirements
|
||||
|
||||
### For Development
|
||||
- macOS 10.15+ (Catalina or later)
|
||||
- Rust (install via [rustup](https://rustup.rs/))
|
||||
- Python 3.11+
|
||||
- Node.js 18+ (for Tauri CLI)
|
||||
|
||||
### For Users
|
||||
- macOS 10.15+ (Catalina or later)
|
||||
- ~200MB disk space
|
||||
|
||||
## Quick Start (Development)
|
||||
|
||||
```bash
|
||||
# 1. Install Tauri CLI
|
||||
cargo install tauri-cli
|
||||
|
||||
# 2. Start the Python server (in one terminal)
|
||||
make -f Makefile.desktop dev
|
||||
|
||||
# 3. Run Tauri in dev mode (in another terminal)
|
||||
make -f Makefile.desktop dev-tauri
|
||||
```
|
||||
|
||||
## Building for Distribution
|
||||
|
||||
```bash
|
||||
# Full build (bundle Python + build Tauri app)
|
||||
make -f Makefile.desktop build
|
||||
|
||||
# Or step by step:
|
||||
make -f Makefile.desktop bundle-python # Create Python executable
|
||||
make -f Makefile.desktop build-tauri # Build macOS app
|
||||
```
|
||||
|
||||
The app bundle will be in `src-tauri/target/release/bundle/`.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Tauri Shell │
|
||||
│ ┌───────────────────────────────────────────┐ │
|
||||
│ │ Native WebKit WebView │ │
|
||||
│ │ │ │
|
||||
│ │ ┌──────────────────────────────────┐ │ │
|
||||
│ │ │ http://127.0.0.1:31102 │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ KJV Study Web Interface │ │ │
|
||||
│ │ │ (Jinja2 templates + Tufte CSS) │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ └──────────────────────────────────┘ │ │
|
||||
│ │ │ │ │
|
||||
│ └────────────────────│───────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────────────────▼───────────────────────┐ │
|
||||
│ │ FastAPI Server (Sidecar) │ │
|
||||
│ │ │ │
|
||||
│ │ • Bible data (JSON) • Search (SQLite)│ │
|
||||
│ │ • Commentary • Cross-refs │ │
|
||||
│ │ • Interlinear • Strong's │ │
|
||||
│ │ • Study guides • Reading plans │ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. Tauri app launches and spawns the Python/FastAPI server as a sidecar process
|
||||
2. Server runs on `127.0.0.1:31102` (port = number of KJV verses)
|
||||
3. WebView navigates to the local server
|
||||
4. All data is served from bundled JSON/SQLite files
|
||||
5. On quit, Tauri terminates the sidecar process
|
||||
|
||||
## Port Selection
|
||||
|
||||
The app uses port **31102** - the exact number of verses in the King James Bible. This avoids conflicts with common development ports (3000, 5000, 8000, 8080).
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
kjvstudy.org/
|
||||
├── src-tauri/ # Tauri application
|
||||
│ ├── Cargo.toml # Rust dependencies
|
||||
│ ├── tauri.conf.json # Tauri configuration
|
||||
│ ├── src/
|
||||
│ │ └── main.rs # Sidecar launcher
|
||||
│ └── icons/ # App icons
|
||||
├── sidecar/ # Bundled Python executable (after build)
|
||||
├── kjvstudy_org/ # Python application
|
||||
│ ├── server.py # FastAPI app
|
||||
│ ├── desktop.py # Desktop entry point
|
||||
│ ├── templates/ # Jinja2 templates
|
||||
│ └── static/ # CSS, JS, fonts
|
||||
├── data/ # Bible data (JSON)
|
||||
├── Makefile.desktop # Build commands
|
||||
├── pyproject-desktop.toml # Desktop dependencies (no WeasyPrint)
|
||||
└── DESKTOP.md # This file
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Server won't start
|
||||
Check if port 31102 is already in use:
|
||||
```bash
|
||||
lsof -i :31102
|
||||
```
|
||||
|
||||
### App shows blank screen
|
||||
The server may not be ready. Check Console.app for logs, or run in dev mode to see output.
|
||||
|
||||
### Icons not showing
|
||||
Regenerate icons:
|
||||
```bash
|
||||
make -f Makefile.desktop icons
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See LICENSE file for details.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Makefile for KJV Study Desktop App
|
||||
# Usage: make -f Makefile.desktop [target]
|
||||
|
||||
.PHONY: all clean bundle-python build-tauri build dev install-deps icons
|
||||
|
||||
# Default target: build everything
|
||||
all: install-deps bundle-python build-tauri
|
||||
|
||||
# Install required dependencies
|
||||
install-deps:
|
||||
@echo "=== Installing dependencies ==="
|
||||
pip install pyinstaller
|
||||
cd src-tauri && cargo fetch
|
||||
@echo "Dependencies installed!"
|
||||
|
||||
# Bundle Python application with PyInstaller
|
||||
bundle-python:
|
||||
@echo "=== Bundling Python server ==="
|
||||
./scripts/bundle-desktop.sh
|
||||
@echo "Python bundle complete!"
|
||||
|
||||
# Build Tauri application
|
||||
build-tauri:
|
||||
@echo "=== Building Tauri app ==="
|
||||
cd src-tauri && cargo tauri build
|
||||
@echo "Tauri build complete!"
|
||||
|
||||
# Full production build
|
||||
build: all
|
||||
@echo ""
|
||||
@echo "=== Build Complete! ==="
|
||||
@echo "App bundle: src-tauri/target/release/bundle/"
|
||||
|
||||
# Development mode (runs server + opens browser)
|
||||
dev:
|
||||
@echo "=== Starting development server ==="
|
||||
uv run uvicorn kjvstudy_org.server:app --host 127.0.0.1 --port 31102 --reload
|
||||
|
||||
# Development with Tauri
|
||||
dev-tauri:
|
||||
@echo "=== Starting Tauri dev mode ==="
|
||||
@echo "Make sure the Python server is running (make -f Makefile.desktop dev)"
|
||||
cd src-tauri && cargo tauri dev
|
||||
|
||||
# Generate app icons from source PNG (requires ImageMagick)
|
||||
icons:
|
||||
@echo "=== Generating icons ==="
|
||||
@if [ -f "kjvstudy_org/static/images/icon-source.png" ]; then \
|
||||
convert kjvstudy_org/static/images/icon-source.png -resize 32x32 src-tauri/icons/32x32.png; \
|
||||
convert kjvstudy_org/static/images/icon-source.png -resize 128x128 src-tauri/icons/128x128.png; \
|
||||
convert kjvstudy_org/static/images/icon-source.png -resize 256x256 src-tauri/icons/128x128@2x.png; \
|
||||
convert kjvstudy_org/static/images/icon-source.png -resize 512x512 src-tauri/icons/icon.png; \
|
||||
echo "Icons generated!"; \
|
||||
else \
|
||||
echo "No icon-source.png found. Using placeholders."; \
|
||||
fi
|
||||
|
||||
# Clean build artifacts
|
||||
clean:
|
||||
@echo "=== Cleaning build artifacts ==="
|
||||
rm -rf build/ dist/ *.spec
|
||||
rm -rf sidecar/
|
||||
rm -rf src-tauri/target/
|
||||
@echo "Clean complete!"
|
||||
|
||||
# Help
|
||||
help:
|
||||
@echo "KJV Study Desktop Build System"
|
||||
@echo ""
|
||||
@echo "Targets:"
|
||||
@echo " all - Build everything (default)"
|
||||
@echo " install-deps - Install Python and Rust dependencies"
|
||||
@echo " bundle-python- Bundle Python server with PyInstaller"
|
||||
@echo " build-tauri - Build Tauri application"
|
||||
@echo " build - Full production build"
|
||||
@echo " dev - Run development server on port 31102"
|
||||
@echo " dev-tauri - Run Tauri in development mode"
|
||||
@echo " icons - Generate icons from source PNG"
|
||||
@echo " clean - Remove build artifacts"
|
||||
@echo " help - Show this help"
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Desktop application entry point for KJV Study.
|
||||
|
||||
This module provides a standalone entry point for the desktop application,
|
||||
configured to run on a non-standard port (31102 - the number of verses in the KJV).
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Start the KJV Study server for desktop use."""
|
||||
import uvicorn
|
||||
|
||||
# Get port from environment or use default (31102 = number of KJV verses)
|
||||
port = int(os.environ.get("KJVSTUDY_PORT", "31102"))
|
||||
host = os.environ.get("KJVSTUDY_HOST", "127.0.0.1")
|
||||
|
||||
# Determine the base directory for resources
|
||||
if getattr(sys, "frozen", False):
|
||||
# Running as bundled executable (PyInstaller)
|
||||
base_dir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
# Running as script
|
||||
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# Change to base directory so relative paths work
|
||||
os.chdir(base_dir)
|
||||
|
||||
print(f"Starting KJV Study server on {host}:{port}")
|
||||
print(f"Base directory: {base_dir}")
|
||||
|
||||
uvicorn.run(
|
||||
"kjvstudy_org.server:app",
|
||||
host=host,
|
||||
port=port,
|
||||
log_level="warning",
|
||||
# Disable reload in production
|
||||
reload=False,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,32 @@
|
||||
# Desktop-specific pyproject.toml (without WeasyPrint for easier bundling)
|
||||
# Use this for building the Tauri desktop application
|
||||
|
||||
[project]
|
||||
name = "kjvstudy-desktop"
|
||||
version = "1.0.0"
|
||||
description = "KJV Study - Offline Bible Study Desktop Application"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"fastapi[standard]>=0.115.12",
|
||||
"ged4py>=0.5.2",
|
||||
"mistune>=3.0.2",
|
||||
"parse>=1.20.2",
|
||||
"python-gedcom>=1.0.0",
|
||||
# Note: weasyprint intentionally excluded - PDF buttons will be hidden
|
||||
# Note: requests excluded - not actually used in the codebase
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
kjvstudy-server = "kjvstudy_org.desktop:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=45", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["kjvstudy_org*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
kjvstudy_org = ["static/**/*", "templates/**/*"]
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/bin/bash
|
||||
# Bundle the KJV Study Python application for desktop distribution
|
||||
# This script creates a standalone executable using PyInstaller
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
OUTPUT_DIR="$PROJECT_DIR/sidecar"
|
||||
|
||||
echo "=== KJV Study Desktop Bundler ==="
|
||||
echo "Project directory: $PROJECT_DIR"
|
||||
echo "Output directory: $OUTPUT_DIR"
|
||||
|
||||
cd "$PROJECT_DIR"
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Install desktop dependencies (without weasyprint)
|
||||
echo ""
|
||||
echo "=== Installing desktop dependencies ==="
|
||||
pip install pyinstaller
|
||||
pip install "fastapi[standard]>=0.115.12" "ged4py>=0.5.2" "mistune>=3.0.2" "parse>=1.20.2" "python-gedcom>=1.0.0"
|
||||
|
||||
# Create PyInstaller spec file
|
||||
echo ""
|
||||
echo "=== Creating PyInstaller spec ==="
|
||||
cat > "$PROJECT_DIR/kjvstudy-server.spec" << 'EOF'
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
import os
|
||||
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
|
||||
|
||||
block_cipher = None
|
||||
|
||||
# Collect all kjvstudy_org submodules
|
||||
hiddenimports = collect_submodules('kjvstudy_org')
|
||||
hiddenimports += collect_submodules('fastapi')
|
||||
hiddenimports += collect_submodules('starlette')
|
||||
hiddenimports += collect_submodules('uvicorn')
|
||||
hiddenimports += ['kjvstudy_org.server', 'kjvstudy_org.desktop']
|
||||
|
||||
# Collect data files
|
||||
datas = [
|
||||
('kjvstudy_org/templates', 'kjvstudy_org/templates'),
|
||||
('kjvstudy_org/static', 'kjvstudy_org/static'),
|
||||
('data', 'data'),
|
||||
]
|
||||
|
||||
a = Analysis(
|
||||
['kjvstudy_org/desktop.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=['weasyprint', 'cairo', 'gi'],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='kjvstudy-server',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
EOF
|
||||
|
||||
# Run PyInstaller
|
||||
echo ""
|
||||
echo "=== Running PyInstaller ==="
|
||||
pyinstaller --clean --noconfirm kjvstudy-server.spec
|
||||
|
||||
# Move output to sidecar directory
|
||||
echo ""
|
||||
echo "=== Moving output to sidecar directory ==="
|
||||
cp -f "dist/kjvstudy-server" "$OUTPUT_DIR/"
|
||||
|
||||
echo ""
|
||||
echo "=== Bundle complete! ==="
|
||||
echo "Executable: $OUTPUT_DIR/kjvstudy-server"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. cd src-tauri"
|
||||
echo " 2. cargo tauri build"
|
||||
@@ -0,0 +1,23 @@
|
||||
[package]
|
||||
name = "kjvstudy"
|
||||
version = "1.0.0"
|
||||
description = "KJV Study - Offline Bible Study App"
|
||||
authors = ["Kenneth Reitz"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/kennethreitz/kjvstudy.org"
|
||||
edition = "2021"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "2", features = [] }
|
||||
|
||||
[dependencies]
|
||||
tauri = { version = "2", features = ["shell-open"] }
|
||||
tauri-plugin-shell = "2"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1", features = ["process", "time"] }
|
||||
reqwest = { version = "0.12", features = ["blocking"] }
|
||||
|
||||
[features]
|
||||
default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
tauri_build::build()
|
||||
}
|
||||
|
After Width: | Height: | Size: 985 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 268 B |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 692 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,146 @@
|
||||
// Prevents additional console window on Windows in release
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::Mutex;
|
||||
use std::time::Duration;
|
||||
use tauri::{AppHandle, Manager, RunEvent};
|
||||
|
||||
struct ServerProcess(Mutex<Option<Child>>);
|
||||
|
||||
fn find_python_executable(app: &AppHandle) -> Option<String> {
|
||||
// In development, use system Python
|
||||
if cfg!(debug_assertions) {
|
||||
return Some("python3".to_string());
|
||||
}
|
||||
|
||||
// In production, look for bundled Python sidecar
|
||||
let resource_path = app.path().resource_dir().ok()?;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let sidecar_path = resource_path.join("sidecar").join("kjvstudy-server");
|
||||
if sidecar_path.exists() {
|
||||
return Some(sidecar_path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let sidecar_path = resource_path.join("sidecar").join("kjvstudy-server.exe");
|
||||
if sidecar_path.exists() {
|
||||
return Some(sidecar_path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to system Python
|
||||
Some("python3".to_string())
|
||||
}
|
||||
|
||||
fn start_server(app: &AppHandle) -> Option<Child> {
|
||||
let python = find_python_executable(app)?;
|
||||
|
||||
// Get the resource directory for data files
|
||||
let resource_dir = app.path().resource_dir().ok()?;
|
||||
|
||||
// For development, use the project directory
|
||||
let working_dir = if cfg!(debug_assertions) {
|
||||
std::env::current_dir().ok()?
|
||||
} else {
|
||||
resource_dir.clone()
|
||||
};
|
||||
|
||||
println!("Starting KJV Study server...");
|
||||
println!("Python executable: {}", python);
|
||||
println!("Working directory: {:?}", working_dir);
|
||||
|
||||
let child = if python.ends_with("kjvstudy-server") || python.ends_with("kjvstudy-server.exe") {
|
||||
// Running bundled executable
|
||||
Command::new(&python)
|
||||
.current_dir(&working_dir)
|
||||
.env("KJVSTUDY_PORT", "31102")
|
||||
.spawn()
|
||||
.ok()?
|
||||
} else {
|
||||
// Running with Python interpreter (development)
|
||||
Command::new(&python)
|
||||
.args([
|
||||
"-m", "uvicorn",
|
||||
"kjvstudy_org.server:app",
|
||||
"--host", "127.0.0.1",
|
||||
"--port", "31102",
|
||||
"--log-level", "warning"
|
||||
])
|
||||
.current_dir(&working_dir)
|
||||
.spawn()
|
||||
.ok()?
|
||||
};
|
||||
|
||||
Some(child)
|
||||
}
|
||||
|
||||
fn wait_for_server(max_attempts: u32) -> bool {
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
.timeout(Duration::from_secs(1))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
for attempt in 1..=max_attempts {
|
||||
println!("Waiting for server... (attempt {}/{})", attempt, max_attempts);
|
||||
|
||||
match client.get("http://127.0.0.1:31102/api/health").send() {
|
||||
Ok(response) if response.status().is_success() => {
|
||||
println!("Server is ready!");
|
||||
return true;
|
||||
}
|
||||
_ => {
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Server failed to start after {} attempts", max_attempts);
|
||||
false
|
||||
}
|
||||
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.manage(ServerProcess(Mutex::new(None)))
|
||||
.setup(|app| {
|
||||
// Start the Python server
|
||||
let handle = app.handle().clone();
|
||||
|
||||
if let Some(child) = start_server(&handle) {
|
||||
let state = app.state::<ServerProcess>();
|
||||
*state.0.lock().unwrap() = Some(child);
|
||||
|
||||
// Wait for server to be ready
|
||||
if !wait_for_server(30) {
|
||||
eprintln!("Warning: Server may not be fully ready");
|
||||
}
|
||||
} else {
|
||||
eprintln!("Failed to start server process");
|
||||
}
|
||||
|
||||
// Navigate to the local server
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.eval("window.location.href = 'http://127.0.0.1:31102'");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.build(tauri::generate_context!())
|
||||
.expect("error while building tauri application")
|
||||
.run(|app_handle, event| {
|
||||
if let RunEvent::Exit = event {
|
||||
// Clean up: kill the server process
|
||||
let state = app_handle.state::<ServerProcess>();
|
||||
if let Some(mut child) = state.0.lock().unwrap().take() {
|
||||
println!("Shutting down server...");
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||