package main import ( "fmt" "runtime" "spitfire-installer/spm" ) // Installer manages the download, decompression, and installation processes. type Installer struct { // Progress info from SPM Progress int Task string // Internal states IsDownloading bool IsInstalling bool DoneDownload bool DoneInstall bool LastError error PendingInstall bool } // NewInstaller creates a new Installer with initial state. func NewInstaller() *Installer { return &Installer{} } // StartDownloadDecompress starts the download and decompression in a background goroutine. func (inst *Installer) StartDownloadDecompress() { inst.IsDownloading = true go func() { defer func() { inst.IsDownloading = false // Signal that download phase is complete. inst.DoneDownload = (inst.LastError == nil) // If a final install was requested, go ahead. if inst.PendingInstall && inst.DoneDownload && !inst.IsInstalling && !inst.DoneInstall { inst.doFinalInstall() } }() spm.UpdateProgress(0, "Preparing to download...") // Define the package specifications. specs := []spm.AppIndexEntry{ { Name: "spitfire-luncher", Release: "nightly", OS: runtime.GOOS, Arch: runtime.GOARCH, Type: "luncher", }, { Name: "spitfire-browser", Release: "nightly", OS: runtime.GOOS, Arch: runtime.GOARCH, Type: "browser", }, } spm.UpdateProgress(0, "Downloading specified packages...") if err := spm.AutoDownloadSpecified(specs); err != nil { fmt.Println("AutoDownloadSpecifiedPackages failed:", err) inst.LastError = err return } spm.UpdateProgress(0, "Download and decompression complete!") // Here, update your installer state so FinalInstall() can proceed. inst.DoneDownload = true }() } // FinalInstall is called by the UI to request installation. // If download is done, it runs immediately, otherwise sets PendingInstall=true. func (inst *Installer) FinalInstall() { // Already installed or installing => ignore repeated calls. if inst.IsInstalling || inst.DoneInstall { return } // If not done downloading, mark that we want to install once finished. if !inst.DoneDownload { fmt.Println("Cannot install now: download and decompression not complete -> pending install.") inst.PendingInstall = true return } // Otherwise, go ahead and install now. inst.doFinalInstall() } // doFinalInstall does the actual installation by invoking AutoInstallUpdates. func (inst *Installer) doFinalInstall() { inst.IsInstalling = true inst.PendingInstall = false // we are fulfilling the install now go func() { defer func() { inst.IsInstalling = false inst.DoneInstall = (inst.LastError == nil) }() spm.UpdateProgress(0, "Installing updates...") if err := spm.AutoInstallUpdates(); err != nil { inst.LastError = err return } spm.UpdateProgress(100, "Installation complete!") }() } // PollProgress fetches the latest progress and task from SPM. func (inst *Installer) PollProgress() { p, t := spm.GetProgress() inst.Progress, inst.Task = p, t }