// Put adds the given alert to the set. func (a *Alerts) Put(alerts ...*types.Alert) error { a.mtx.Lock() defer a.mtx.Unlock() err := a.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bktAlerts) for _, alert := range alerts { fp := make([]byte, 8) binary.BigEndian.PutUint64(fp, uint64(alert.Fingerprint())) ab := b.Get(fp) // Merge the alert with the existing one. if ab != nil { var old types.Alert if err := json.Unmarshal(ab, &old); err != nil { return fmt.Errorf("decoding alert failed: %s", err) } // Merge alerts if there is an overlap in activity range. if (alert.EndsAt.After(old.StartsAt) && alert.EndsAt.Before(old.EndsAt)) || (alert.StartsAt.After(old.StartsAt) && alert.StartsAt.Before(old.EndsAt)) { alert = old.Merge(alert) } } ab, err := json.Marshal(alert) if err != nil { return fmt.Errorf("encoding alert failed: %s", err) } if err := b.Put(fp, ab); err != nil { return fmt.Errorf("writing alert failed: %s", err) } // Send the update to all subscribers. for _, ch := range a.listeners { ch <- alert } } return nil }) return err }