diff --git a/internal/app/app.go b/internal/app/app.go index 45a8a54ceb5b7cc5c192b2e0a721bf67096abf8c..4e4c7572111059352994af53611b8ca7f8dd3c53 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -348,26 +348,16 @@ func (app *App) Shutdown() { } } -// checkForUpdates checks for available updates in the background. +// checkForUpdates checks for available updates. func (app *App) checkForUpdates(ctx context.Context) { - // Use a timeout to avoid hanging indefinitely. - checkCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + checkCtx, cancel := context.WithTimeout(ctx, 30*time.Second) defer cancel() - - // Check for updates asynchronously. - updateCh := update.CheckForUpdateAsync(checkCtx, app.config.Options.DataDirectory) - - select { - case info := <-updateCh: - if info != nil && info.Available { - // Send update notification through the event system. - app.events <- pubsub.UpdateAvailableMsg{ - CurrentVersion: info.CurrentVersion, - LatestVersion: info.LatestVersion, - } - } - case <-checkCtx.Done(): - // Timeout or context cancelled. + info, err := update.Check(checkCtx) + if err != nil || info == nil || !info.Available { return } + app.events <- pubsub.UpdateAvailableMsg{ + CurrentVersion: info.CurrentVersion, + LatestVersion: info.LatestVersion, + } } diff --git a/internal/update/update.go b/internal/update/update.go index 065af136ca34dc2a3f0c600ca6c72d5dff3455af..d48ff6db266c9b4a24f86551eba7077cec01b8ab 100644 --- a/internal/update/update.go +++ b/internal/update/update.go @@ -6,7 +6,6 @@ import ( "fmt" "io" "net/http" - "os" "strings" "time" @@ -19,23 +18,17 @@ const ( userAgent = "crush/1.0" ) -// Release represents a GitHub release. -type Release struct { - TagName string `json:"tag_name"` - HTMLURL string `json:"html_url"` -} - -// UpdateInfo contains information about an available update. -type UpdateInfo struct { +// Info contains information about an available update. +type Info struct { CurrentVersion string LatestVersion string ReleaseURL string Available bool } -// CheckForUpdate checks if a new version is available. -func CheckForUpdate(ctx context.Context) (*UpdateInfo, error) { - info := &UpdateInfo{ +// Check checks if a new version is available. +func Check(ctx context.Context) (*Info, error) { + info := &Info{ CurrentVersion: version.Version, } @@ -62,8 +55,14 @@ func CheckForUpdate(ctx context.Context) (*UpdateInfo, error) { return info, nil } +// githubRelease represents a GitHub release. +type githubRelease struct { + TagName string `json:"tag_name"` + HTMLURL string `json:"html_url"` +} + // fetchLatestRelease fetches the latest release information from GitHub. -func fetchLatestRelease(ctx context.Context) (*Release, error) { +func fetchLatestRelease(ctx context.Context) (*githubRelease, error) { client := &http.Client{ Timeout: 30 * time.Second, } @@ -86,35 +85,10 @@ func fetchLatestRelease(ctx context.Context) (*Release, error) { return nil, fmt.Errorf("GitHub API returned status %d: %s", resp.StatusCode, string(body)) } - var release Release + var release githubRelease if err := json.NewDecoder(resp.Body).Decode(&release); err != nil { return nil, err } return &release, nil } - -// CheckForUpdateAsync performs an update check in the background and returns immediately. -// If an update is available, it returns the update info through the channel. -func CheckForUpdateAsync(ctx context.Context, dataDir string) <-chan *UpdateInfo { - ch := make(chan *UpdateInfo, 1) - - go func() { - defer close(ch) - - // Perform the check. - info, err := CheckForUpdate(ctx) - if err != nil { - // Log error but don't fail. - fmt.Fprintf(os.Stderr, "Failed to check for updates: %v\n", err) - return - } - - // Send update info if available. - if info.Available { - ch <- info - } - }() - - return ch -} diff --git a/internal/update/update_test.go b/internal/update/update_test.go index 8edd9fddaf06d257192ef07673eeb774e624ebda..5b387c5b89b160eb3e8455ab9c507d5a2c64b1ee 100644 --- a/internal/update/update_test.go +++ b/internal/update/update_test.go @@ -8,65 +8,6 @@ import ( "github.com/stretchr/testify/require" ) -func TestCompareVersions(t *testing.T) { - tests := []struct { - name string - v1 string - v2 string - expected int - }{ - { - name: "equal versions", - v1: "1.0.0", - v2: "1.0.0", - expected: 0, - }, - { - name: "v1 less than v2 - patch", - v1: "1.0.0", - v2: "1.0.1", - expected: -1, - }, - { - name: "v1 less than v2 - minor", - v1: "1.0.0", - v2: "1.1.0", - expected: -1, - }, - { - name: "v1 less than v2 - major", - v1: "1.0.0", - v2: "2.0.0", - expected: -1, - }, - { - name: "v1 greater than v2", - v1: "2.0.0", - v2: "1.9.9", - expected: 1, - }, - { - name: "with v prefix", - v1: "v1.0.0", - v2: "v1.0.1", - expected: -1, - }, - { - name: "different lengths", - v1: "1.0", - v2: "1.0.0", - expected: -1, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := compareVersions(tt.v1, tt.v2) - require.Equal(t, tt.expected, result) - }) - } -} - func TestCheckForUpdate_DevelopmentVersion(t *testing.T) { // Test that development versions don't trigger updates. ctx := context.Background() @@ -78,7 +19,7 @@ func TestCheckForUpdate_DevelopmentVersion(t *testing.T) { version.Version = originalVersion }() - info, err := CheckForUpdate(ctx) + info, err := Check(ctx) require.NoError(t, err) require.NotNil(t, info) require.False(t, info.Available)