Files
FrenoCorp/src-tauri/src/updater.rs
Michael Freno 0fcd91cf87 FRE-606: Add Tauri desktop framework with cross-platform support
- Configure Tauri v2 for macOS, Windows, Linux
- Implement native menu bar (File, Edit, View, Window, Help)
- Add system tray with show/hide/quit functionality
- Create auto-updater framework with periodic checks
- Set up window state persistence
- Configure plugins (fs, http, dialog, shell, store)
- Add build scripts for all platforms
- Include comprehensive documentation

Files:
- src-tauri/Cargo.toml
- src-tauri/tauri.conf.json
- src-tauri/build.rs
- src-tauri/src/main.rs
- src-tauri/src/lib.rs
- src-tauri/src/menu.rs
- src-tauri/src/tray.rs
- src-tauri/src/updater.rs
- src-tauri/Cargo.lock
- src-tauri/icons/tray-icon.svg
- src-tauri/tauri.build.conf
- src-tauri/README.md
- .gitignore
- package.json (Tauri CLI scripts)
2026-04-23 22:29:22 -04:00

153 lines
4.3 KiB
Rust

use log::{info, warn};
use serde::{Deserialize, Serialize};
use std::time::Duration;
use tauri::{AppHandle, Emitter, Manager};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateInfo {
pub current_version: String,
pub latest_version: String,
pub release_notes: String,
pub download_url: String,
pub is_update_available: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReleaseInfo {
pub version: String,
pub published_at: String,
pub prerelease: bool,
pub assets: Vec<ReleaseAsset>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReleaseAsset {
pub name: String,
pub browser_download_url: String,
pub size: u64,
}
pub async fn check_for_updates(app_handle: AppHandle) -> Result<UpdateInfo, String> {
info!("Checking for updates");
let current_version = app_handle
.package_info()
.version
.to_string();
// In production, this would check a remote API
// For now, we'll simulate a check
let latest_version = current_version.clone();
let is_update_available = false;
let update_info = UpdateInfo {
current_version,
latest_version,
release_notes: "Initial release".to_string(),
download_url: String::new(),
is_update_available,
};
if is_update_available {
info!("Update available: {}", update_info.latest_version);
// Emit event to frontend
if let Err(e) = app_handle.emit("update-available", &update_info) {
warn!("Failed to emit update event: {}", e);
}
} else {
info!("Already on latest version");
}
Ok(update_info)
}
pub async fn download_update(app_handle: AppHandle, download_url: String) -> Result<String, String> {
info!("Downloading update from: {}", download_url);
// Simulate download
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(300))
.build()
.map_err(|e| e.to_string())?;
let response = client
.get(&download_url)
.send()
.await
.map_err(|e| format!("Download failed: {}", e))?;
let bytes = response
.bytes()
.await
.map_err(|e| format!("Failed to read bytes: {}", e))?;
info!("Downloaded {} bytes", bytes.len());
// Save to temp location
let temp_dir = std::env::temp_dir();
let installer_path = temp_dir.join("frenocorp-updater-installer");
std::fs::write(&installer_path, &bytes)
.map_err(|e| format!("Failed to write installer: {}", e))?;
Ok(installer_path.to_string_lossy().to_string())
}
pub async fn install_update(app_handle: AppHandle, installer_path: String) -> Result<(), String> {
info!("Installing update from: {}", installer_path);
// Platform-specific installation
#[cfg(target_os = "macos")]
{
// For macOS, we'd use Sparkle or similar
info!("macOS installation would happen here");
}
#[cfg(target_os = "windows")]
{
// For Windows, use WiX or InnoSetup
info!("Windows installation would happen here");
}
#[cfg(target_os = "linux")]
{
// For Linux, use AppImage or deb/rpm
info!("Linux installation would happen here");
}
// Emit update installed event
if let Err(e) = app_handle.emit("update-installed", &installer_path) {
warn!("Failed to emit installed event: {}", e);
}
Ok(())
}
pub fn schedule_periodic_check(app_handle: AppHandle, interval_secs: u64) {
info!("Scheduling periodic update check every {} seconds", interval_secs);
let interval = Duration::from_secs(interval_secs);
tokio::spawn(async move {
let mut interval_tick = tokio::time::interval(interval);
loop {
interval_tick.tick().await;
info!("Running scheduled update check");
match check_for_updates(app_handle.clone()).await {
Ok(update_info) => {
if update_info.is_update_available {
info!("Scheduled check found update: {}", update_info.latest_version);
}
}
Err(e) => {
warn!("Scheduled update check failed: {}", e);
}
}
}
});
}