release / govulncheck (push) Successful in 18s
release / web (push) Successful in 1m22s
release / go (push) Successful in 1m43s
release / integration (push) Successful in 4m56s
release / android (push) Successful in 5m16s
release / Build signed APK (releases and dev) (push) Successful in 5m27s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 15s
release / Verify release artifacts (tag releases only) (push) Skipped
- A failed scan run sends scan_failed. Each failure adds to the count and the notice shows the latest error. A scan cut short by shutdown says nothing. - Marking tracks missing sends tracks_missing with a running count. - A duplicate sweep that proposes a group it had not proposed before sends duplicates_found, counting everything awaiting review. A sweep that only re-finds known groups stays quiet, so a read notice isn't repeated every sweep (CountDuplicateGroupsDetectedSince). - A playback-error report sends playback_errors, counting the unresolved errors (CountUnresolvedPlaybackErrors). The library package gets its notifier as a package-level SetNotifier beside SetEventBus, for the same reason the bus is package-level. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
45 lines
1.4 KiB
Go
45 lines
1.4 KiB
Go
package library
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
|
|
"github.com/jackc/pgx/v5/pgtype"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/notifications"
|
|
)
|
|
|
|
// Package-level notifier for library-health notices to admins (M489): a
|
|
// scan that failed, tracks gone missing, new duplicates. Set once at startup
|
|
// beside SetEventBus, for the same reason the bus is package-level. Nil, as in
|
|
// tests that never set it, means nobody is told.
|
|
var (
|
|
notifierMu sync.RWMutex
|
|
notifier *notifications.Notifier
|
|
)
|
|
|
|
// SetNotifier wires the notifications inbox into the library package.
|
|
func SetNotifier(n *notifications.Notifier) {
|
|
notifierMu.Lock()
|
|
defer notifierMu.Unlock()
|
|
notifier = n
|
|
}
|
|
|
|
// notifyAdmins tells every admin about a library-health event. These kinds
|
|
// coalesce, so a burst is one unread notice with a running count.
|
|
func notifyAdmins(ctx context.Context, kind notifications.Kind, p notifications.Payload) {
|
|
notifierMu.RLock()
|
|
n := notifier
|
|
notifierMu.RUnlock()
|
|
n.NotifyLogged(ctx, kind, notifications.ToAdmins(pgtype.UUID{}), p.Map())
|
|
}
|
|
|
|
// notifyScanFinished tells admins a scan run ended in error. A scan cut short
|
|
// by shutdown is not a failure anyone needs telling about.
|
|
func notifyScanFinished(ctx context.Context, errMsg string) {
|
|
if errMsg == "" || ctx.Err() != nil {
|
|
return
|
|
}
|
|
notifyAdmins(ctx, notifications.KindScanFailed, notifications.Payload{Count: 1, Detail: errMsg})
|
|
}
|