package main import ( "fmt" "strings" "sync" "time" "github.com/safing/portbase/api/client" "github.com/safing/portbase/formats/dsd" "github.com/safing/portbase/log" pbnotify "github.com/safing/portbase/notifications" ) const ( dbNotifBasePath = "notifications:all/" ) var ( notifications = make(map[string]*Notification) notificationsLock sync.Mutex ) func notifClient() { notifOp := apiClient.Qsub(fmt.Sprintf("query %s where ShowOnSystem is true", dbNotifBasePath), handleNotification) notifOp.EnableResuscitation() // start the action listener and block // until it's closed. actionListener() } func handleNotification(m *client.Message) { notificationsLock.Lock() defer notificationsLock.Unlock() log.Tracef("received %s msg: %s", m.Type, m.Key) switch m.Type { case client.MsgError: case client.MsgDone: case client.MsgSuccess: case client.MsgOk, client.MsgUpdate, client.MsgNew: n := &Notification{} _, err := dsd.Load(m.RawValue, &n.Notification) if err != nil { log.Warningf("notify: failed to parse new notification: %s", err) return } // copy existing system values existing, ok := notifications[n.EventID] if ok { existing.Lock() n.systemID = existing.systemID existing.Unlock() } // save notifications[n.EventID] = n // Handle notification. switch { case existing != nil: // Cancel existing notification if not active, else ignore. if n.State != pbnotify.Active { existing.Cancel() } return case n.State == pbnotify.Active: // Show new notifications that are active. n.Show() default: // Ignore new notifications that are not active. } case client.MsgDelete: n, ok := notifications[strings.TrimPrefix(m.Key, dbNotifBasePath)] if ok { n.Cancel() delete(notifications, n.EventID) } case client.MsgWarning: case client.MsgOffline: } } func clearNotifications() { notificationsLock.Lock() defer notificationsLock.Unlock() for _, n := range notifications { n.Cancel() } // Wait for goroutines that cancel notifications. // TODO: Revamp to use a waitgroup. time.Sleep(1 * time.Second) }