2026-01-27 23:06:18 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
|
|
/// The main data model that mirrors the frontend's DataModel type.
|
|
|
|
|
/// This is sent via WebSocket as the initial state and updated via patches.
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct DataModel {
|
|
|
|
|
#[serde(rename = "server-info")]
|
|
|
|
|
pub server_info: ServerInfo,
|
|
|
|
|
#[serde(rename = "package-data")]
|
|
|
|
|
pub package_data: HashMap<String, PackageDataEntry>,
|
chore(ci): rustfmt + clippy clean-up to unblock the Rust CI job
The .github/workflows/ci.yml Rust job runs cargo fmt --check, clippy
with -D warnings, and tests. All three were failing. This commit:
- Applies rustfmt across the tree (the bulk of the diff — untouched
since the last toolchain bump, so a wide sweep was unavoidable).
- Fixes the correctness-level clippy errors:
container/bitcoin_simulator.rs wildcard-in-or-pattern
container/manifest.rs from_str rename to parse (reserved name)
container/podman_client.rs .get(0) -> .first()
container/runtime.rs manual += collapse
archipelago/src/constants.rs doc-comment → module-doc
api/rpc/package/install.rs stray /// comment above a non-item
container/docker_packages.rs redundant field init
streaming/advertisement.rs missing Metric import in tests
tests/orchestration_tests.rs `vec!` in non-Vec contexts
mesh/listener/dispatch.rs unused store_plain_message import
api/rpc/tor/mod.rs and mesh/steganography.rs: push-after-new → vec!
- Quiets wide legacy surfaces with crate-level allows in main.rs for
stylistic lints (too_many_arguments, type_complexity, doc indent,
enum variant prefix, wildcard-in-or, assertions-on-constants,
drop_non_drop, unused_io_amount, ptr_arg) — these fired in dozens
of places with no correctness payoff and have been churning every
toolchain bump.
- Tags intentional-dead-code helpers: wallet/ and streaming/ modules
are WIP, mesh::send_chunked_payload and DM_V1_MARKER are kept for
rollback compatibility, vpn::get_nostr_vpn_status is surface-area
for a not-yet-landed RPC.
cargo fmt --check, cargo clippy --all-targets --all-features
-- -D warnings, and cargo test --all-features now all pass locally.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:23:46 -04:00
|
|
|
#[serde(
|
|
|
|
|
rename = "peer-health",
|
|
|
|
|
default,
|
|
|
|
|
skip_serializing_if = "HashMap::is_empty"
|
|
|
|
|
)]
|
2026-03-09 07:43:12 +00:00
|
|
|
pub peer_health: HashMap<String, bool>,
|
2026-03-12 00:19:30 +00:00
|
|
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
|
|
|
|
pub notifications: Vec<Notification>,
|
2026-01-27 23:06:18 +00:00
|
|
|
pub ui: UIData,
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-12 00:19:30 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
|
|
|
pub struct Notification {
|
|
|
|
|
pub id: String,
|
|
|
|
|
pub level: NotificationLevel,
|
|
|
|
|
pub title: String,
|
|
|
|
|
pub message: String,
|
|
|
|
|
pub timestamp: String,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub app_id: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
|
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
|
pub enum NotificationLevel {
|
|
|
|
|
Info,
|
|
|
|
|
Warning,
|
|
|
|
|
Error,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct ServerInfo {
|
|
|
|
|
pub id: String,
|
|
|
|
|
pub version: String,
|
|
|
|
|
pub name: Option<String>,
|
|
|
|
|
pub pubkey: String,
|
|
|
|
|
#[serde(rename = "status-info")]
|
|
|
|
|
pub status_info: StatusInfo,
|
|
|
|
|
#[serde(rename = "lan-address")]
|
|
|
|
|
pub lan_address: Option<String>,
|
2026-02-17 15:03:34 +00:00
|
|
|
#[serde(rename = "tor-address")]
|
|
|
|
|
pub tor_address: Option<String>,
|
|
|
|
|
#[serde(rename = "node-address", skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub node_address: Option<String>,
|
2026-01-27 23:06:18 +00:00
|
|
|
pub unread: u32,
|
|
|
|
|
#[serde(rename = "wifi-ssids")]
|
|
|
|
|
pub wifi_ssids: Vec<String>,
|
|
|
|
|
#[serde(rename = "zram-enabled")]
|
|
|
|
|
pub zram_enabled: bool,
|
2026-03-31 01:41:24 +01:00
|
|
|
/// True if this node's keys are derived from a BIP-39 seed.
|
|
|
|
|
#[serde(rename = "seed-backed", default)]
|
|
|
|
|
pub seed_backed: bool,
|
2026-01-27 23:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct StatusInfo {
|
|
|
|
|
pub restarting: bool,
|
|
|
|
|
#[serde(rename = "shutting-down")]
|
|
|
|
|
pub shutting_down: bool,
|
|
|
|
|
pub updated: bool,
|
|
|
|
|
#[serde(rename = "backup-progress")]
|
|
|
|
|
pub backup_progress: Option<f32>,
|
|
|
|
|
#[serde(rename = "update-progress")]
|
|
|
|
|
pub update_progress: Option<f32>,
|
2026-03-18 11:46:38 +00:00
|
|
|
/// True after the first container scan completes. Frontend should
|
|
|
|
|
/// not show install buttons until this is true.
|
|
|
|
|
#[serde(rename = "containers-scanned", default)]
|
|
|
|
|
pub containers_scanned: bool,
|
2026-01-27 23:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct UIData {
|
|
|
|
|
pub name: Option<String>,
|
|
|
|
|
#[serde(rename = "ack-welcome")]
|
|
|
|
|
pub ack_welcome: String,
|
|
|
|
|
pub marketplace: UIMarketplaceData,
|
|
|
|
|
pub theme: String,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct UIMarketplaceData {
|
|
|
|
|
#[serde(rename = "selected-hosts")]
|
|
|
|
|
pub selected_hosts: Vec<String>,
|
|
|
|
|
#[serde(rename = "known-hosts")]
|
|
|
|
|
pub known_hosts: HashMap<String, MarketplaceHost>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct MarketplaceHost {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub url: String,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
#[serde(rename_all = "kebab-case")]
|
|
|
|
|
pub enum PackageState {
|
|
|
|
|
Installing,
|
|
|
|
|
Installed,
|
|
|
|
|
Stopping,
|
|
|
|
|
Stopped,
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
Exited,
|
2026-01-27 23:06:18 +00:00
|
|
|
Starting,
|
|
|
|
|
Running,
|
|
|
|
|
Restarting,
|
|
|
|
|
#[serde(rename = "creating-backup")]
|
|
|
|
|
CreatingBackup,
|
|
|
|
|
#[serde(rename = "restoring-backup")]
|
|
|
|
|
RestoringBackup,
|
|
|
|
|
Removing,
|
|
|
|
|
#[serde(rename = "backing-up")]
|
|
|
|
|
BackingUp,
|
2026-04-09 11:47:35 +02:00
|
|
|
Updating,
|
2026-01-27 23:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct PackageDataEntry {
|
|
|
|
|
pub state: PackageState,
|
security+feat: v1.3.0 — pentest remediation, container reliability, UI overhaul
Security (33 pentest findings addressed):
- CRITICAL: backend binds 127.0.0.1, path traversal in tor.rs/dwn fixed
- HIGH: federation requires signatures, XSS login redirect, RBAC viewer restricted
- HIGH: tar slip prevention, S3 SSRF validation, backup ID validation
- MEDIUM: remember-me random secret, TOTP session rotation, password re-auth
- LOW: CSP unsafe-inline removed, CORS dev-only, onion/webhook validation
Container reliability:
- Memory limits on all 37 containers (OOM prevention)
- Exited vs stopped state distinction with health-aware status badges
- Crash recovery coordination (no more restart cascade)
- User-stopped tracking survives reboots
- Tiered boot recovery (databases → core → services → apps)
UI:
- Wallet TransactionsModal, health-aware app status badges
- Restart button on containers, exited/crashed red state
- Mesh view overhaul, glass button updates, BaseModal/ToggleSwitch
- Apps sticky header removed, dev faucet, mutable mock wallet
Infrastructure:
- LND REST port 8080 exposed over Tor (LND Connect fix)
- Nginx cookie_session fix, deploy script Tor config updated
- Dev environment: podman auto-start, boot mode simulation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 12:44:31 +00:00
|
|
|
/// Container health: "healthy", "unhealthy", "starting", or null
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub health: Option<String>,
|
fix: overhaul container lifecycle — recovery, health, uninstall, UI state
Container recovery:
- Health monitor: MAX_RESTART_ATTEMPTS 3→10, interval 60s→120s
- Dependency-aware restarts: won't restart services before their deps
- Reset dependent counters when a dependency recovers
- Handle "created" state containers (were invisible to health monitor)
- Added IndeedHub, mempool-api, mysql to tier system
- Crash recovery: podman start timeout 30s→120s with retry
- Podman client: socket timeout 5s→30s, added restart policy
UI state representation:
- Exit code 0 shows "stopped" (gray), not "crashed" (red)
- Exit code 137 shows "killed (OOM)"
- Non-zero exit shows "crashed" (red)
- Added exit_code field to PackageDataEntry
Install/uninstall fixes:
- Install returns error when container doesn't start (was silent success)
- Post-install hooks awaited instead of fire-and-forget tokio::spawn
- Uninstall: graceful rm before force, volume prune, network cleanup
- Uninstall returns error on partial failure (was 200 OK)
Config consistency:
- DB passwords read from /var/lib/archipelago/secrets/ (was hardcoded)
- Bitcoin: added ZMQ ports 28332/28333 for LND block notifications
- IndeedHub port 7777→8190 (was conflicting with strfry)
- Marketplace versions: LND 0.17.4→0.18.4, Mempool 2.5.0→3.0.0
Performance:
- Metrics collector interval 60s→300s (was duplicating health monitor)
- Podman client: proper error propagation instead of unwrap_or_default
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 07:03:57 +01:00
|
|
|
/// Container exit code (only set when state is Exited): 0 = clean, non-zero = crash
|
|
|
|
|
#[serde(rename = "exit-code", skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub exit_code: Option<i32>,
|
2026-01-27 23:06:18 +00:00
|
|
|
#[serde(rename = "static-files")]
|
|
|
|
|
pub static_files: StaticFiles,
|
|
|
|
|
pub manifest: Manifest,
|
|
|
|
|
pub installed: Option<InstalledPackageDataEntry>,
|
|
|
|
|
#[serde(rename = "install-progress")]
|
|
|
|
|
pub install_progress: Option<InstallProgress>,
|
2026-04-09 11:47:35 +02:00
|
|
|
/// Pinned image version from image-versions.sh when it differs from running version
|
|
|
|
|
#[serde(rename = "available-update", skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub available_update: Option<String>,
|
2026-01-27 23:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct StaticFiles {
|
|
|
|
|
pub license: String,
|
|
|
|
|
pub instructions: String,
|
|
|
|
|
pub icon: String,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct Manifest {
|
|
|
|
|
pub id: String,
|
|
|
|
|
pub title: String,
|
|
|
|
|
pub version: String,
|
|
|
|
|
pub description: Description,
|
|
|
|
|
#[serde(rename = "release-notes")]
|
|
|
|
|
pub release_notes: String,
|
|
|
|
|
pub license: String,
|
|
|
|
|
#[serde(rename = "wrapper-repo")]
|
|
|
|
|
pub wrapper_repo: String,
|
|
|
|
|
#[serde(rename = "upstream-repo")]
|
|
|
|
|
pub upstream_repo: String,
|
|
|
|
|
#[serde(rename = "support-site")]
|
|
|
|
|
pub support_site: String,
|
|
|
|
|
#[serde(rename = "marketing-site")]
|
|
|
|
|
pub marketing_site: String,
|
|
|
|
|
#[serde(rename = "donation-url")]
|
|
|
|
|
pub donation_url: Option<String>,
|
|
|
|
|
pub author: Option<String>,
|
|
|
|
|
pub website: Option<String>,
|
|
|
|
|
pub interfaces: Option<Interfaces>,
|
feat: add app tier system — core/recommended/optional (SCALE-02, SCALE-03)
get_app_tier() classifies all apps:
- core: Bitcoin, LND, Electrs, Mempool, BTCPay, DWN, FileBrowser
- recommended: Fedimint, Grafana, Vaultwarden, Kuma, SearXNG, etc.
- optional: everything else
Tier field added to Manifest struct (data_model.rs) and exposed
via WebSocket package data for frontend tier badges.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 03:27:51 +00:00
|
|
|
/// App tier: "core", "recommended", or "optional"
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub tier: Option<String>,
|
2026-01-27 23:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct Description {
|
|
|
|
|
pub short: String,
|
|
|
|
|
pub long: String,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct Interfaces {
|
|
|
|
|
pub main: Option<MainInterface>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct MainInterface {
|
|
|
|
|
pub ui: Option<String>,
|
|
|
|
|
#[serde(rename = "tor-config")]
|
|
|
|
|
pub tor_config: Option<String>,
|
|
|
|
|
#[serde(rename = "lan-config")]
|
|
|
|
|
pub lan_config: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct InstalledPackageDataEntry {
|
|
|
|
|
#[serde(rename = "current-dependents")]
|
|
|
|
|
pub current_dependents: HashMap<String, CurrentDependencyInfo>,
|
|
|
|
|
#[serde(rename = "current-dependencies")]
|
|
|
|
|
pub current_dependencies: HashMap<String, CurrentDependencyInfo>,
|
|
|
|
|
#[serde(rename = "last-backup")]
|
|
|
|
|
pub last_backup: Option<String>,
|
|
|
|
|
#[serde(rename = "interface-addresses")]
|
|
|
|
|
pub interface_addresses: HashMap<String, InterfaceAddress>,
|
|
|
|
|
pub status: ServiceStatus,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct CurrentDependencyInfo {
|
|
|
|
|
#[serde(rename = "health-checks")]
|
|
|
|
|
pub health_checks: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct InterfaceAddress {
|
|
|
|
|
#[serde(rename = "tor-address")]
|
|
|
|
|
pub tor_address: String,
|
|
|
|
|
#[serde(rename = "lan-address")]
|
|
|
|
|
pub lan_address: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
|
pub enum ServiceStatus {
|
|
|
|
|
Stopped,
|
|
|
|
|
Starting,
|
|
|
|
|
Running,
|
|
|
|
|
Stopping,
|
|
|
|
|
Restarting,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 13:24:03 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
2026-01-27 23:06:18 +00:00
|
|
|
pub struct InstallProgress {
|
|
|
|
|
pub size: u64,
|
|
|
|
|
pub downloaded: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// WebSocket message sent to clients
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct WebSocketMessage {
|
|
|
|
|
pub rev: u32,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub data: Option<DataModel>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub patch: Option<Vec<PatchOperation>>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct PatchOperation {
|
|
|
|
|
pub op: String,
|
|
|
|
|
pub path: String,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub value: Option<serde_json::Value>,
|
|
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub from: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DataModel {
|
2026-03-31 23:43:32 +01:00
|
|
|
/// Read build version from /opt/archipelago/build-info.txt if available,
|
|
|
|
|
/// falling back to Cargo.toml version. This allows sequential CI build
|
|
|
|
|
/// numbers to be reflected in the UI without recompiling the binary.
|
|
|
|
|
fn detect_build_version() -> String {
|
2026-04-20 11:44:59 -04:00
|
|
|
// Always use the binary's compiled-in version. The ISO installer
|
|
|
|
|
// writes /opt/archipelago/build-info.txt at install time, but that
|
|
|
|
|
// file is never rewritten by OTA or sideload, so trusting it made
|
|
|
|
|
// the sidebar permanently advertise whatever the ISO shipped with
|
|
|
|
|
// even after the running binary had moved on. CARGO_PKG_VERSION is
|
|
|
|
|
// baked into the binary at compile time, so it always matches what
|
|
|
|
|
// is actually running.
|
2026-03-31 23:43:32 +01:00
|
|
|
env!("CARGO_PKG_VERSION").to_string()
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-27 23:06:18 +00:00
|
|
|
/// Create a new empty data model with default values
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
server_info: ServerInfo {
|
|
|
|
|
id: uuid::Uuid::new_v4().to_string(),
|
2026-03-31 23:43:32 +01:00
|
|
|
version: Self::detect_build_version(),
|
2026-01-27 23:06:18 +00:00
|
|
|
name: Some("Archipelago".to_string()),
|
|
|
|
|
pubkey: String::new(),
|
|
|
|
|
status_info: StatusInfo {
|
|
|
|
|
restarting: false,
|
|
|
|
|
shutting_down: false,
|
|
|
|
|
updated: false,
|
|
|
|
|
backup_progress: None,
|
|
|
|
|
update_progress: None,
|
2026-03-18 11:46:38 +00:00
|
|
|
containers_scanned: false,
|
2026-01-27 23:06:18 +00:00
|
|
|
},
|
|
|
|
|
lan_address: Some("http://localhost:8100".to_string()),
|
2026-02-17 15:03:34 +00:00
|
|
|
tor_address: None,
|
|
|
|
|
node_address: None,
|
2026-01-27 23:06:18 +00:00
|
|
|
unread: 0,
|
|
|
|
|
wifi_ssids: vec![],
|
|
|
|
|
zram_enabled: false,
|
2026-03-31 01:41:24 +01:00
|
|
|
seed_backed: false,
|
2026-01-27 23:06:18 +00:00
|
|
|
},
|
|
|
|
|
package_data: HashMap::new(),
|
2026-03-09 07:43:12 +00:00
|
|
|
peer_health: HashMap::new(),
|
2026-03-12 00:19:30 +00:00
|
|
|
notifications: Vec::new(),
|
2026-01-27 23:06:18 +00:00
|
|
|
ui: UIData {
|
|
|
|
|
name: None,
|
|
|
|
|
ack_welcome: String::new(),
|
|
|
|
|
marketplace: UIMarketplaceData {
|
|
|
|
|
selected_hosts: vec![],
|
|
|
|
|
known_hosts: HashMap::new(),
|
|
|
|
|
},
|
|
|
|
|
theme: "dark".to_string(),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for DataModel {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self::new()
|
|
|
|
|
}
|
|
|
|
|
}
|