Files
VitosUpdater/src-tauri/src/commands/mod.rs
T

127 lines
4.7 KiB
Rust

//! Tauri-Befehle, die die Oberfläche aufruft.
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use tauri::State;
use crate::error::{AppError, AppResult};
use crate::managers::winget::WingetManager;
use crate::managers::PackageManager;
use crate::models::{ManagerId, ManagerInfo, Package, PackageDetails, Source};
use crate::process;
/// Registrierte Paketmanager.
pub struct Registry {
managers: HashMap<ManagerId, Arc<dyn PackageManager>>,
}
impl Registry {
/// Erstellt die Registry mit allen verfügbaren Implementierungen.
pub fn new() -> Self {
let mut managers: HashMap<ManagerId, Arc<dyn PackageManager>> = HashMap::new();
managers.insert(ManagerId::Winget, Arc::new(WingetManager::new()));
Self { managers }
}
fn get(&self, id: ManagerId) -> AppResult<Arc<dyn PackageManager>> {
self.managers
.get(&id)
.cloned()
.ok_or_else(|| AppError::Command("Dieser Paketmanager wird noch nicht unterstützt.".to_owned()))
}
async fn detect_all(&self) -> Vec<ManagerInfo> {
let mut infos = Vec::new();
for manager in self.managers.values() {
infos.push(manager.detect().await);
}
infos
}
}
impl Default for Registry {
fn default() -> Self {
Self::new()
}
}
fn logged<T>(what: &str, result: AppResult<T>) -> AppResult<T> {
if let Err(err) = &result {
tracing::error!(%err, "{what} fehlgeschlagen");
}
result
}
/// Erkennt alle Paketmanager (Pfad, Version, Zusatzkomponenten).
#[tauri::command]
pub async fn detect_managers(registry: State<'_, Registry>) -> AppResult<Vec<ManagerInfo>> {
Ok(registry.detect_all().await)
}
/// Sucht Pakete.
#[tauri::command]
pub async fn search_packages(registry: State<'_, Registry>, manager: ManagerId, query: String) -> AppResult<Vec<Package>> {
let query = query.trim().to_owned();
if query.is_empty() {
return Ok(Vec::new());
}
logged("Paketsuche", registry.get(manager)?.search(&query).await)
}
/// Listet installierte Pakete.
#[tauri::command]
pub async fn list_installed(registry: State<'_, Registry>, manager: ManagerId) -> AppResult<Vec<Package>> {
logged("Liste der installierten Pakete", registry.get(manager)?.list_installed().await)
}
/// Listet verfügbare Aktualisierungen.
#[tauri::command]
pub async fn list_updates(registry: State<'_, Registry>, manager: ManagerId) -> AppResult<Vec<Package>> {
logged("Suche nach Aktualisierungen", registry.get(manager)?.list_updates().await)
}
/// Lädt Paketdetails.
#[tauri::command]
pub async fn get_package_details(registry: State<'_, Registry>, package: Package) -> AppResult<PackageDetails> {
logged("Paketdetails", registry.get(package.manager)?.get_details(&package).await)
}
/// Listet die Quellen eines Managers.
#[tauri::command]
pub async fn list_sources(registry: State<'_, Registry>, manager: ManagerId) -> AppResult<Vec<Source>> {
logged("Quellenliste", registry.get(manager)?.list_sources().await)
}
async fn run_powershell(script: &str, timeout: Duration) -> AppResult<()> {
let shell = which::which("powershell")
.map_err(|_| AppError::ManagerMissing("Windows PowerShell".to_owned()))?;
let out = process::run(&shell, &["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], timeout).await?;
if out.code == Some(0) {
Ok(())
} else {
let detail = out.stderr.lines().find(|l| !l.trim().is_empty()).unwrap_or("unbekannter Fehler");
Err(AppError::Command(format!("Die Installation ist fehlgeschlagen: {detail}")))
}
}
/// Installiert das PowerShell-Modul `Microsoft.WinGet.Client` für den aktuellen Benutzer.
#[tauri::command]
pub async fn install_winget_module(registry: State<'_, Registry>) -> AppResult<Vec<ManagerInfo>> {
let script = "$ProgressPreference='SilentlyContinue'; $ErrorActionPreference='Stop'; \
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Scope CurrentUser -Force | Out-Null; \
Install-Module -Name Microsoft.WinGet.Client -Scope CurrentUser -Repository PSGallery -Force";
logged("Modulinstallation", run_powershell(script, Duration::from_secs(300)).await)?;
Ok(registry.detect_all().await)
}
/// Registriert bzw. installiert den „App-Installer“ (enthält WinGet).
#[tauri::command]
pub async fn install_app_installer(registry: State<'_, Registry>) -> AppResult<Vec<ManagerInfo>> {
let script = "$ProgressPreference='SilentlyContinue'; $ErrorActionPreference='Stop'; \
Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe";
logged("Installation des App-Installers", run_powershell(script, Duration::from_secs(300)).await)?;
Ok(registry.detect_all().await)
}