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,73 @@
|
||||
//! ODIAN packs, format v1: verify a signed version manifest and install that version from a
|
||||
//! site's update service or from an ODIAN drive, checking every byte.
|
||||
//!
|
||||
//! A byte-for-byte compatible port of the Python installer (`odian_packs.fetch` in
|
||||
//! ODIAN_MCP_Server; the format is its `src/odian_packs/README.md`). An install made by
|
||||
//! either one is resumed and re-verified by the other: same layout, same progress files.
|
||||
//!
|
||||
//! ```text
|
||||
//! dest/versions/<v>/manifest.json written LAST: its presence means "installed"
|
||||
//! dest/versions/<v>/<app paths>
|
||||
//! dest/data/db/<snapshot>/...
|
||||
//! dest/data/src/<paths> + <path>.chunks.json while partial, <path>.ok when done
|
||||
//! dest/data/tiles/<style>/<dataset>/<z>/<x>/<y><ext> + .blocks-done.json
|
||||
//! ```
|
||||
|
||||
pub mod canonical;
|
||||
pub mod error;
|
||||
pub mod hashing;
|
||||
pub mod manifest;
|
||||
pub mod signing;
|
||||
pub mod tiles;
|
||||
|
||||
mod copy;
|
||||
mod install;
|
||||
mod progress;
|
||||
mod source;
|
||||
mod tileblocks;
|
||||
|
||||
pub use canonical::canonical_bytes;
|
||||
pub use error::{Error, IntegrityKind, Result};
|
||||
pub use install::{
|
||||
install, AppSummary, DbSummary, InstallOptions, SrcFileSummary, Summary, TileSetSummary,
|
||||
};
|
||||
pub use manifest::{safe_relpath, validate, Manifest, VerifiedManifest};
|
||||
pub use progress::{Progress, Stage};
|
||||
pub use source::Source;
|
||||
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
/// The ODIAN release public key that ships with the launcher (`ed25519:<base64>`).
|
||||
pub fn bundled_public_key() -> &'static str {
|
||||
include_str!("../keys/odian-release.pub").trim()
|
||||
}
|
||||
|
||||
/// The source's CURRENT version manifest: fetched, validated and signature-checked.
|
||||
/// The raw bytes are kept ([`VerifiedManifest::raw`]) because the install writes them verbatim.
|
||||
pub async fn current_manifest(source: &Source, public_key: &str) -> Result<VerifiedManifest> {
|
||||
let backend = source::Backend::new(source)?;
|
||||
let raw = backend.current_manifest(&CancellationToken::new()).await?;
|
||||
VerifiedManifest::from_bytes(raw, public_key)
|
||||
}
|
||||
|
||||
/// A specific version's manifest, verified, and checked to really be that version.
|
||||
pub async fn version_manifest(source: &Source, version: &str, public_key: &str) -> Result<VerifiedManifest> {
|
||||
let backend = source::Backend::new(source)?;
|
||||
let raw = backend.version_manifest(version, &CancellationToken::new()).await?;
|
||||
let verified = VerifiedManifest::from_bytes(raw, public_key)?;
|
||||
if verified.version() != version {
|
||||
return Err(Error::integrity(
|
||||
IntegrityKind::Version,
|
||||
format!("manifest for {version}"),
|
||||
format!("asked for {version}, the signed manifest says {}", verified.version()),
|
||||
));
|
||||
}
|
||||
Ok(verified)
|
||||
}
|
||||
|
||||
/// A version's patch notes (Markdown). **Untrusted text**: not covered by the signature.
|
||||
pub async fn fetch_notes(source: &Source, version: &str) -> Result<String> {
|
||||
let backend = source::Backend::new(source)?;
|
||||
let raw = backend.notes(version, &CancellationToken::new()).await?;
|
||||
Ok(String::from_utf8_lossy(&raw).into_owned())
|
||||
}
|
||||
Reference in New Issue
Block a user