ODIAN Launcher: hub, installer, local stack and remembered sign-in (M2)
- Tauri 2 + Svelte 5 hub in ODIAN dark: patch notes and roadmap, install and update progress, local stack status, settings with DHP and MCP addresses. - crates/odian-packs: Rust installer for pack format v1 (signed manifests, resumable verified downloads from a DHP or an ODIAN drive), byte-compatible with ODIAN_MCP_Server's Python odian_packs. - Local stack on 127.0.0.1: Postgres -> Engine API -> tile server -> Odian.exe, one Job Object, clean shutdown; database snapshot restore on a fresh PC only. - Keycloak sign-in through the DHP's MCP, remembered until Sign out with a launcher session that renews the Engine token silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
// The ONLY module that touches Tauri. Everything else talks to `backend`.
|
||||
// Inside the Tauri webview this is a thin typed wrapper over invoke/listen
|
||||
// (docs/CONTRACT.md); in a plain browser it is the timer-driven mock.
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { createMockBackend } from "./mock";
|
||||
import type {
|
||||
Backend,
|
||||
InstallProgress,
|
||||
LogEvent,
|
||||
Settings,
|
||||
SignInResult,
|
||||
StackEvent,
|
||||
Status,
|
||||
Unlisten,
|
||||
} from "./types";
|
||||
|
||||
export const IN_TAURI = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||
|
||||
function subscribe<T>(event: string, handler: (payload: T) => void): Promise<Unlisten> {
|
||||
return listen<T>(event, (e) => handler(e.payload));
|
||||
}
|
||||
|
||||
function createTauriBackend(): Backend {
|
||||
const win = getCurrentWindow();
|
||||
|
||||
return {
|
||||
kind: "tauri",
|
||||
mock: null,
|
||||
window: {
|
||||
minimize: () => win.minimize(),
|
||||
toggleMaximize: () => win.toggleMaximize(),
|
||||
close: () => win.close(),
|
||||
isMaximized: () => win.isMaximized(),
|
||||
onResized: (handler) => win.onResized(() => handler()),
|
||||
},
|
||||
|
||||
getStatus: () => invoke<Status>("get_status"),
|
||||
refresh: () => invoke<Status>("refresh"),
|
||||
signIn: () => invoke<SignInResult>("sign_in"),
|
||||
cancelSignIn: () => invoke<void>("cancel_sign_in"),
|
||||
signOut: () => invoke<Status>("sign_out"),
|
||||
getNotes: (version) => invoke<string>("get_notes", version === undefined ? {} : { version }),
|
||||
openExternal: (url) => invoke<void>("open_external", { url }),
|
||||
getStack: () => invoke<StackEvent[]>("get_stack"),
|
||||
startInstall: () => invoke<void>("start_install"),
|
||||
startInstallFromDrive: (path) => invoke<void>("start_install_from_drive", { path }),
|
||||
cancelInstall: () => invoke<void>("cancel_install"),
|
||||
launch: () => invoke<void>("launch"),
|
||||
stop: () => invoke<void>("stop"),
|
||||
getSettings: () => invoke<Settings>("get_settings"),
|
||||
setSettings: (settings) => invoke<Status>("set_settings", { settings }),
|
||||
pickFolder: () => invoke<string | null>("pick_folder"),
|
||||
|
||||
onStatus: (handler) => subscribe<Status>("status", handler),
|
||||
onInstallProgress: (handler) => subscribe<InstallProgress>("install-progress", handler),
|
||||
onStack: (handler) => subscribe<StackEvent>("stack", handler),
|
||||
onLog: (handler) => subscribe<LogEvent>("log", handler),
|
||||
};
|
||||
}
|
||||
|
||||
export const backend: Backend = IN_TAURI
|
||||
? createTauriBackend()
|
||||
: createMockBackend(new URLSearchParams(window.location.search));
|
||||
Reference in New Issue
Block a user