-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Finnegan's Owner edited this page Mar 1, 2026
·
4 revisions
Launcher is a Tauri v2 desktop application with a Rust backend and a Nuxt 4 / Vue 3 frontend.
launcher/
├── app/ # Frontend (Nuxt 4)
│ ├── assets/css/main.css # Tailwind CSS v4 design tokens
│ ├── components/ # Vue components
│ │ ├── BriefServerInfo.vue # Server row in the list
│ │ ├── ConnectionInput.vue # Reusable form input
│ │ ├── InsertableDropdown.vue # Dropdown with inline creation
│ │ └── TrustCertModal.vue # Certificate trust dialog
│ ├── composables/ # Vue composables
│ │ ├── useConfirmRejectModal.ts # Imperative modal mounting
│ │ └── useZoom.ts # Keyboard zoom (Cmd/Ctrl +/-/0)
│ ├── pages/ # File-based routing
│ │ ├── index.vue # Main server list
│ │ └── connections/[id].vue # Connection editor
│ └── types.d.ts # TypeScript interfaces
├── src-tauri/ # Backend (Rust)
│ ├── src/
│ │ ├── main.rs # Tauri commands and app setup
│ │ ├── connection.rs # ConnectionStore, persistence, cert trust
│ │ ├── webstart.rs # JNLP parsing, JAR downloading, Java process
│ │ ├── verify.rs # JAR signature verification (CMS/PKCS#7)
│ │ └── errors.rs # VerificationError types
│ ├── lib/java-console.jar # Bundled Java console
│ ├── capabilities/default.json # Tauri permission declarations
│ ├── Cargo.toml # Rust dependencies
│ └── tauri.conf.json # Tauri app configuration
└── nuxt.config.ts # Nuxt configuration
Commands are the IPC bridge between frontend and backend. They use rename_all = "snake_case", so the JavaScript side must use snake_case parameter names.
| Command | Returns | Description |
|---|---|---|
launch |
Result<String, String> |
Downloads JARs, verifies signatures, launches Java process |
save |
Result<String, String> |
Saves a connection entry |
delete |
Result<String, String> |
Deletes a connection |
import |
Result<String, String> |
Imports connections from a JSON file (with duplicate detection) |
load_connections |
String |
Returns all connections as JSON array |
load_single_connection |
Result<Value, String> |
Returns one connection by ID |
get_default_connectionentry |
Result<Value, String> |
Returns a default connection template |
get_all_groups |
Result<Value, String> |
Returns all group names |
trust_cert |
Result<String, String> |
Adds a certificate to the trust store |
get_launcher_info |
String |
Returns app version info |
- Frontend calls
launchwith connection ID and a progressChannel - Backend downloads JNLP from server address
- Parses JNLP for JAR URLs and main class
- Downloads JARs (with progress updates via Channel)
- Optionally verifies JAR signatures (CMS/PKCS#7)
- If untrusted cert found, returns cert info to frontend for user approval
- Sanitizes JVM arguments (blocks dangerous flags like
-javaagent:) - Launches Java process with classpath; credentials passed via environment variables
- Optionally pipes stdout to a Java console process
-
ConnectionStoremanages all connections in aMutex<HashMap<String, Arc<ConnectionEntry>>> - Persisted to
~/.launcher/launcher-data.json - Trusted certs persisted to
~/.launcher/launcher-trusted-certs.json - JAR cache stored in
~/.launcher/cache/
- TLS certificate validation is intentionally disabled (
danger_accept_invalid_certs) because integration engine servers commonly use self-signed certificates - JAR signature verification is the actual trust boundary — JARs are verified against CMS/PKCS#7 signatures before execution
- Users explicitly approve untrusted certificates through the trust dialog
- JNLP version attributes are sanitized to prevent path traversal
- JVM arguments from JNLP are filtered to block code execution flags (
-javaagent:,-agentpath:, etc.) - Credentials are passed to Java processes via environment variables (not command-line arguments)
Capabilities are declared in src-tauri/capabilities/default.json:
| Permission | Purpose |
|---|---|
core:default |
Core IPC and event system |
dialog:default |
Native file picker and confirm dialogs |
notification:default |
Desktop notifications |
fs:default |
File system access |
http:default |
HTTP requests (all URLs, for server connectivity checks) |
shell:allow-open |
Open URLs in default browser (restricted to wiki URL only) |
core:webview:allow-set-webview-zoom |
Keyboard zoom support |
Tailwind CSS v4 with @theme design tokens in app/assets/css/main.css:
| Token | Value | Usage |
|---|---|---|
surface-0 |
#24272e |
Page background |
surface-1 |
#2c2f37 |
Cards, inputs |
surface-2 |
#353840 |
Hover, selected states |
surface-3 |
#3e414a |
Highest elevation |
accent |
#4f7df7 |
Primary actions |
text-primary |
#e2e5eb |
Main text |
text-secondary |
#9ca3b0 |
Supporting text |
Icons use Phosphor Icons via the ph: prefix with the @nuxt/icon module.
-
Channel API:
launchusestauri::ipc::Channelfor streaming progress updates from Rust to the frontend -
Imperative modals:
useConfirmRejectModalmounts Vue components programmatically for the cert trust dialog, returning a Promise -
Module-level state:
useZoomuses a module-scopedreffor app-wide singleton zoom state -
CSS tooltips: Custom
[data-tooltip]attribute with::afterpseudo-element (nativetitletooltips are unreliable in Tauri's WKWebView). Usedata-tooltip-belowfor elements near the top of the window. - localStorage persistence: Sort mode, collapsed groups, and zoom level all persist to localStorage
-
Rust: Prefer
?operator and.map_err()over.unwrap(). Return errors to frontend viaResult<T, String>. Use.expect("descriptive message")only for mutex locks (poisoning is unrecoverable). -
Frontend: Wrap
invokecalls in try/catch and display errors inline via the error bar at the bottom of the main screen.