diff --git a/app.go b/app.go index 10214b0..0b88a4a 100644 --- a/app.go +++ b/app.go @@ -773,11 +773,13 @@ func (a *App) startup(ctx context.Context) { // LoTW user-activity list (who's a LoTW user + last upload). Loads the cached // CSV if present, and auto-downloads in the background when it's missing or - // older than a week (the ARRL list changes daily). Manual refresh is in - // Settings → LoTW. + // older than a DAY — the list carries each station's last-upload date, so a + // stale cache would misreport recency (a station that uploaded 2 days ago must + // show as recent, which only works if we refresh roughly daily). Manual + // refresh is in Settings → LoTW. a.lotwUsers = lotwusers.NewManager(dataDir) go func() { - if a.lotwUsers.Count() == 0 || time.Since(a.lotwUsers.Updated()) > 7*24*time.Hour { + if a.lotwUsers.Count() == 0 || time.Since(a.lotwUsers.Updated()) > 24*time.Hour { if n, err := a.lotwUsers.Download(context.Background()); err == nil { applog.Printf("lotwusers: auto-downloaded %d LoTW users", n) if a.ctx != nil { @@ -789,7 +791,17 @@ func (a *App) startup(ctx context.Context) { } }() go func() { - if err := a.clublog.EnsureLoaded(); err == nil { + _ = a.clublog.EnsureLoaded() + // Auto-refresh a missing/stale country file (ClubLog adds date-ranged + // exceptions constantly — e.g. event calls like IR0WWA get new SARDINIA + // periods). Without this a stale cache resolves recent event QSOs to the + // base country. Best-effort; the on-disk copy still serves if it fails. + if a.clublog.NeedsRefresh(3 * 24 * time.Hour) { + if err := a.clublog.Download(context.Background()); err != nil { + applog.Printf("clublog: auto-refresh failed: %v", err) + } + } + if a.clublog.Loaded() { d, n := a.clublog.Info() fmt.Printf("OpsLog: clublog cty.xml loaded — %d exceptions (%s)\n", n, d) } diff --git a/internal/clublog/manager.go b/internal/clublog/manager.go index 7bbdcc5..5143aab 100644 --- a/internal/clublog/manager.go +++ b/internal/clublog/manager.go @@ -50,6 +50,17 @@ func (m *Manager) Info() (date string, count int) { return m.db.Date(), m.db.Count() } +// NeedsRefresh reports whether the cached country file is missing or older than +// maxAge — so the caller re-downloads it to pick up newly-added date-ranged +// exceptions (e.g. an event call's fresh SARDINIA period). +func (m *Manager) NeedsRefresh(maxAge time.Duration) bool { + fi, err := os.Stat(m.Path()) + if err != nil { + return true // missing + } + return time.Since(fi.ModTime()) > maxAge +} + // EnsureLoaded loads the cached file into memory if present. Does NOT download. func (m *Manager) EnsureLoaded() error { if m.Loaded() {