/* * Copyright (c) 2026 Kaiy Ragur * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package notify import ( "log" "sync" ) type EventType int const ( EventMailNew EventType = iota EventMailUpdate EventMailPurge EventFlagsUpdate EventHeartbit // ... ) const AllUsers = "*" type Event interface { GetType() EventType GetAccountPK() string } type HeartbitEvent struct { Type EventType AccountPK string } func (e *HeartbitEvent) GetAccountPK() string { return e.AccountPK } func (e *HeartbitEvent) GetType() EventType { return EventHeartbit } type EmailEvent struct { Type EventType MessageId, Count int64 AccountPK, MailBox string done chan struct{} } func NewEmailEvent(pk, mailbox string, id, count int64) *EmailEvent { return &EmailEvent{ AccountPK: pk, MailBox: mailbox, MessageId: id, Count: count, done: make(chan struct{}), } } func (e *EmailEvent) GetAccountPK() string { return e.AccountPK } func (e *EmailEvent) GetType() EventType { return e.Type } // imap/backend/update interface func (e *EmailEvent) Username() string { return e.AccountPK } func (e *EmailEvent) Mailbox() string { return e.MailBox } func (e *EmailEvent) Done() chan struct{} { return e.done } type FlagsEvent struct { AccountPK string Mailbox string MessageID int64 Seen bool Answered bool Flagged bool Deleted bool } func (e *FlagsEvent) GetAccountPK() string { return e.AccountPK } func (e *FlagsEvent) GetType() EventType { return EventFlagsUpdate } type Notify struct { log *log.Logger mu sync.Mutex listeners map[string]map[chan Event]struct{} } func NewNotifyBus(log *log.Logger) *Notify { return &Notify{ log: log, } } // Subscribe for any methods func (n *Notify) Subscribe(pk string) chan Event { n.mu.Lock() defer n.mu.Unlock() if n.listeners == nil { n.listeners = make(map[string]map[chan Event]struct{}) } if n.listeners[pk] == nil { n.listeners[pk] = make(map[chan Event]struct{}) } ch := make(chan Event, 10) n.listeners[pk][ch] = struct{}{} return ch } func (n *Notify) Unsubscribe(pk string, ch chan Event) { n.mu.Lock() defer n.mu.Unlock() if subs, ok := n.listeners[pk]; ok { delete(subs, ch) if len(subs) == 0 { delete(n.listeners, pk) } } } // Do Notification for clients func (n *Notify) NotifyNew(pk string, event Event) error { n.mu.Lock() defer n.mu.Unlock() go func() { if subs, ok := n.listeners[pk]; ok { for ch := range subs { ch <- event } } if subs, ok := n.listeners[AllUsers]; ok { for ch := range subs { ch <- event } } }() return nil }