162 lines
4.7 KiB
Go
162 lines
4.7 KiB
Go
package updater
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"runtime"
|
|
"seanime/internal/constants"
|
|
"seanime/internal/database/models"
|
|
"seanime/internal/events"
|
|
"slices"
|
|
|
|
"github.com/Masterminds/semver/v3"
|
|
"github.com/goccy/go-json"
|
|
)
|
|
|
|
type AnnouncementType string
|
|
|
|
const (
|
|
AnnouncementTypeToast AnnouncementType = "toast"
|
|
AnnouncementTypeDialog AnnouncementType = "dialog"
|
|
AnnouncementTypeBanner AnnouncementType = "banner"
|
|
)
|
|
|
|
type AnnouncementSeverity string
|
|
|
|
const (
|
|
AnnouncementSeverityInfo AnnouncementSeverity = "info"
|
|
AnnouncementSeverityWarning AnnouncementSeverity = "warning"
|
|
AnnouncementSeverityError AnnouncementSeverity = "error"
|
|
AnnouncementSeverityCritical AnnouncementSeverity = "critical"
|
|
)
|
|
|
|
type AnnouncementAction struct {
|
|
Label string `json:"label"`
|
|
URL string `json:"url"`
|
|
Type string `json:"type"`
|
|
}
|
|
|
|
type AnnouncementConditions struct {
|
|
OS []string `json:"os,omitempty"` // ["windows", "darwin", "linux"]
|
|
Platform []string `json:"platform,omitempty"` // ["tauri", "web", "denshi"]
|
|
// FeatureFlags []string `json:"featureFlags,omitempty"` // Required feature flags
|
|
VersionConstraint string `json:"versionConstraint,omitempty"` // e.g. "<= 2.9.0", "2.9.0"
|
|
UserSettingsPath string `json:"userSettingsPath,omitempty"` // JSON path to check in user settings
|
|
UserSettingsValue []string `json:"userSettingsValue,omitempty"` // Expected values at that path
|
|
}
|
|
|
|
type Announcement struct {
|
|
ID string `json:"id"` // Unique identifier for tracking
|
|
Title string `json:"title,omitempty"` // Title for dialogs/banners
|
|
Message string `json:"message"` // The message to display
|
|
Type AnnouncementType `json:"type"` // The type of announcement
|
|
Severity AnnouncementSeverity `json:"severity"` // Severity level
|
|
Date interface{} `json:"date"` // Date of the announcement
|
|
|
|
NotDismissible bool `json:"notDismissible"` // Can user dismiss it
|
|
|
|
Conditions *AnnouncementConditions `json:"conditions,omitempty"` // Advanced targeting
|
|
|
|
Actions []AnnouncementAction `json:"actions,omitempty"` // Action buttons
|
|
|
|
Priority int `json:"priority"`
|
|
}
|
|
|
|
func (u *Updater) GetAnnouncements(version string, platform string, settings *models.Settings) []Announcement {
|
|
var filteredAnnouncements []Announcement
|
|
if !u.checkForUpdate {
|
|
return filteredAnnouncements
|
|
}
|
|
// filter out
|
|
for _, announcement := range u.announcements {
|
|
if announcement.Conditions == nil {
|
|
filteredAnnouncements = append(filteredAnnouncements, announcement)
|
|
continue
|
|
}
|
|
|
|
conditions := announcement.Conditions
|
|
|
|
if len(conditions.OS) > 0 && !slices.Contains(conditions.OS, runtime.GOOS) {
|
|
continue
|
|
}
|
|
|
|
if conditions.Platform != nil && !slices.Contains(conditions.Platform, platform) {
|
|
continue
|
|
}
|
|
|
|
if conditions.VersionConstraint != "" {
|
|
versionConstraint, err := semver.NewConstraint(conditions.VersionConstraint)
|
|
if err != nil {
|
|
u.logger.Error().Err(err).Msgf("updater: Failed to parse version constraint")
|
|
continue
|
|
}
|
|
|
|
currVersion, err := semver.NewVersion(version)
|
|
if err != nil {
|
|
u.logger.Error().Err(err).Msgf("updater: Failed to parse current version")
|
|
continue
|
|
}
|
|
|
|
if !versionConstraint.Check(currVersion) {
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
filteredAnnouncements = append(filteredAnnouncements, announcement)
|
|
}
|
|
|
|
u.announcements = filteredAnnouncements
|
|
|
|
return u.announcements
|
|
}
|
|
|
|
func (u *Updater) FetchAnnouncements() []Announcement {
|
|
var announcements []Announcement
|
|
|
|
response, err := http.Get(constants.AnnouncementURL)
|
|
if err != nil {
|
|
u.logger.Error().Err(err).Msgf("updater: Failed to get announcements")
|
|
return announcements
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
u.logger.Error().Err(err).Msgf("updater: Failed to read announcements")
|
|
return announcements
|
|
}
|
|
|
|
err = json.Unmarshal(body, &announcements)
|
|
if err != nil {
|
|
u.logger.Error().Err(err).Msgf("updater: Failed to unmarshal announcements")
|
|
return announcements
|
|
}
|
|
|
|
// Filter out announcements
|
|
var filteredAnnouncements []Announcement
|
|
for _, announcement := range announcements {
|
|
if announcement.Conditions == nil {
|
|
filteredAnnouncements = append(filteredAnnouncements, announcement)
|
|
continue
|
|
}
|
|
|
|
conditions := announcement.Conditions
|
|
|
|
if len(conditions.OS) > 0 && !slices.Contains(conditions.OS, runtime.GOOS) {
|
|
continue
|
|
}
|
|
|
|
filteredAnnouncements = append(filteredAnnouncements, announcement)
|
|
}
|
|
|
|
u.announcements = announcements
|
|
|
|
if u.wsEventManager.IsPresent() {
|
|
// Tell the client to send a request to fetch the latest announcements
|
|
u.wsEventManager.MustGet().SendEvent(events.CheckForAnnouncements, nil)
|
|
}
|
|
|
|
return announcements
|
|
}
|