git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/selfupdate/updater.go (about)

     1  package selfupdate
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"sync"
     7  
     8  	"git.sr.ht/~pingoo/stdx/httpx"
     9  	"git.sr.ht/~pingoo/stdx/semver"
    10  )
    11  
    12  type Config struct {
    13  	ZingPublicKey string
    14  	// BaseURL is the URL of the folder containing the manifest
    15  	// e.g. https://downloads.example.com/myapp
    16  	BaseURL        string
    17  	CurrentVersion string
    18  	ReleaseChannel string
    19  
    20  	// Default: 300 seconds
    21  	AutoupdateInterval int64
    22  	// Verbose logs actions with the INFO level
    23  	Verbose    bool
    24  	UserAgent  *string
    25  	HttpClient *http.Client
    26  }
    27  
    28  type Updater struct {
    29  	httpClient             *http.Client
    30  	baseUrl                string
    31  	zingPublicKey          string
    32  	currentVersion         string
    33  	userAgent              string
    34  	releaseChannel         string
    35  	updateInProgress       sync.Mutex
    36  	latestVersionAvailable string
    37  	latestVersionInstalled string
    38  	autoupdateInterval     int64
    39  	verbose                bool
    40  
    41  	Updated chan struct{}
    42  }
    43  
    44  func NewUpdater(config Config) (updater *Updater, err error) {
    45  	if config.HttpClient == nil {
    46  		config.HttpClient = httpx.DefaultClient()
    47  	}
    48  
    49  	if config.BaseURL == "" {
    50  		err = errors.New("selfupdate: BaseURL is empty")
    51  		return
    52  	}
    53  
    54  	if config.ZingPublicKey == "" {
    55  		err = errors.New("selfupdate: ZingPublicKey is empty")
    56  		return
    57  	}
    58  
    59  	if config.CurrentVersion == "" {
    60  		err = errors.New("selfupdate: CurrentVersion is empty")
    61  		return
    62  	}
    63  
    64  	if config.AutoupdateInterval == 0 {
    65  		config.AutoupdateInterval = 300
    66  	}
    67  
    68  	userAgent := DefaultUserAgent
    69  	if config.UserAgent != nil {
    70  		userAgent = *config.UserAgent
    71  	}
    72  
    73  	updater = &Updater{
    74  		httpClient:             config.HttpClient,
    75  		baseUrl:                config.BaseURL,
    76  		zingPublicKey:          config.ZingPublicKey,
    77  		currentVersion:         config.CurrentVersion,
    78  		userAgent:              userAgent,
    79  		releaseChannel:         config.ReleaseChannel,
    80  		updateInProgress:       sync.Mutex{},
    81  		latestVersionAvailable: config.CurrentVersion,
    82  		latestVersionInstalled: config.CurrentVersion,
    83  		autoupdateInterval:     config.AutoupdateInterval,
    84  		verbose:                config.Verbose,
    85  		Updated:                make(chan struct{}),
    86  	}
    87  	return
    88  }
    89  
    90  func (updater *Updater) RestartRequired() bool {
    91  	return updater.latestVersionInstalled != updater.currentVersion
    92  }
    93  
    94  // UpdateAvailable returns true if the latest avaiable version is > to the latest install version
    95  func (updater *Updater) UpdateAvailable() bool {
    96  	return semver.Compare(updater.latestVersionAvailable, updater.latestVersionInstalled) > 0
    97  }