Installer/installer.go

128 lines
3.2 KiB
Go
Raw Normal View History

2024-12-25 10:58:31 +01:00
package main
import (
"fmt"
2025-02-04 17:14:00 +01:00
"runtime"
2024-12-25 10:58:31 +01:00
"spitfire-installer/spm"
)
// Installer manages the download, decompression, and installation processes.
type Installer struct {
// Progress info from SPM
Progress int
Task string
// Internal states
2024-12-25 19:06:39 +01:00
IsDownloading bool
IsInstalling bool
DoneDownload bool
DoneInstall bool
LastError error
PendingInstall bool
2024-12-25 10:58:31 +01:00
}
// 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
2025-02-04 17:14:00 +01:00
// Signal that download phase is complete.
2024-12-25 10:58:31 +01:00
inst.DoneDownload = (inst.LastError == nil)
2025-02-04 17:14:00 +01:00
// If a final install was requested, go ahead.
2024-12-25 19:06:39 +01:00
if inst.PendingInstall && inst.DoneDownload && !inst.IsInstalling && !inst.DoneInstall {
inst.doFinalInstall()
}
2024-12-25 10:58:31 +01:00
}()
spm.UpdateProgress(0, "Preparing to download...")
2025-02-04 17:14:00 +01:00
// 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",
},
2024-12-25 10:58:31 +01:00
}
2025-02-04 17:14:00 +01:00
spm.UpdateProgress(0, "Downloading specified packages...")
if err := spm.AutoDownloadSpecified(specs); err != nil {
fmt.Println("AutoDownloadSpecifiedPackages failed:", err)
2024-12-25 10:58:31 +01:00
inst.LastError = err
return
}
2025-02-04 17:14:00 +01:00
spm.UpdateProgress(0, "Download and decompression complete!")
// Here, update your installer state so FinalInstall() can proceed.
inst.DoneDownload = true
2024-12-25 10:58:31 +01:00
}()
}
2024-12-25 19:06:39 +01:00
// FinalInstall is called by the UI to request installation.
// If download is done, it runs immediately, otherwise sets PendingInstall=true.
2024-12-25 10:58:31 +01:00
func (inst *Installer) FinalInstall() {
2025-02-04 17:14:00 +01:00
// Already installed or installing => ignore repeated calls.
2024-12-25 19:06:39 +01:00
if inst.IsInstalling || inst.DoneInstall {
return
}
2025-02-04 17:14:00 +01:00
// If not done downloading, mark that we want to install once finished.
2024-12-25 10:58:31 +01:00
if !inst.DoneDownload {
2024-12-25 19:06:39 +01:00
fmt.Println("Cannot install now: download and decompression not complete -> pending install.")
inst.PendingInstall = true
2024-12-25 10:58:31 +01:00
return
}
2025-02-04 17:14:00 +01:00
// Otherwise, go ahead and install now.
2024-12-25 19:06:39 +01:00
inst.doFinalInstall()
}
2025-02-04 17:14:00 +01:00
// doFinalInstall does the actual installation by invoking AutoInstallUpdates.
2024-12-25 19:06:39 +01:00
func (inst *Installer) doFinalInstall() {
2024-12-25 10:58:31 +01:00
inst.IsInstalling = true
2024-12-25 19:06:39 +01:00
inst.PendingInstall = false // we are fulfilling the install now
2024-12-25 10:58:31 +01:00
go func() {
defer func() {
inst.IsInstalling = false
inst.DoneInstall = (inst.LastError == nil)
}()
2025-02-04 17:14:00 +01:00
spm.UpdateProgress(0, "Installing updates...")
if err := spm.AutoInstallUpdates(); err != nil {
2024-12-25 10:58:31 +01:00
inst.LastError = err
return
}
// Register the app in Windows (i.e. create registry entries)
spm.UpdateProgress(0, "Registering app...")
if err := spm.RegisterApp(); err != nil {
inst.LastError = err
return
}
2024-12-25 10:58:31 +01:00
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
}