feat: notify on direct messages; store DMs under sender nick; respect quiet hours and rate limit for DMs

This commit is contained in:
Thomas Cravey 2025-08-16 12:36:01 -05:00
parent 00ddd9e460
commit 26ae405e9b

View file

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@ -136,8 +137,15 @@ func main() {
} }
alert := func(channel, author, text, msgid string, at time.Time) { alert := func(channel, author, text, msgid string, at time.Time) {
logger.Debug("ingest", "ts", at.UTC(), "channel", channel, "author", author, "body", text, "msgid", msgid) logger.Debug("ingest", "ts", at.UTC(), "channel", channel, "author", author, "body", text, "msgid", msgid)
// Determine storage channel: for DMs to me, store under sender nick
storeChan := channel
isChannel := strings.HasPrefix(channel, "#") || strings.HasPrefix(channel, "&")
isDMToMe := !isChannel && strings.EqualFold(channel, cfg.Nick)
if isDMToMe {
storeChan = author
}
if err := st.InsertMessage(ctx, store.Message{ if err := st.InsertMessage(ctx, store.Message{
Channel: channel, Channel: storeChan,
Author: author, Author: author,
Body: text, Body: text,
Time: at.UTC(), Time: at.UTC(),
@ -147,26 +155,52 @@ func main() {
} else { } else {
atomic.AddInt64(&metrics.MessagesIngested, 1) atomic.AddInt64(&metrics.MessagesIngested, 1)
} }
if mentionChecker(text) && allowedChannel(channel) { // Notify on direct messages to me (bypass channel allow/deny; respect quiet hours)
if isDMToMe && !strings.EqualFold(author, cfg.Nick) {
if nt != nil { if nt != nil {
if !cfg.NotifyBackfill && time.Since(at) > 5*time.Minute { if !cfg.NotifyBackfill && time.Since(at) > 5*time.Minute {
logger.Debug("mention suppressed", "reason", "backfill", "channel", channel, "author", author) logger.Debug("dm suppressed", "reason", "backfill", "from", author)
return return
} }
if config.WithinQuietHours(at, cfg.QuietHours) && !isUrgent(text) { if config.WithinQuietHours(at, cfg.QuietHours) && !isUrgent(text) {
logger.Debug("mention suppressed", "reason", "quiet_hours", "channel", channel, "author", author) logger.Debug("dm suppressed", "reason", "quiet_hours", "from", author)
return return
} }
key := channel + "|" + cfg.Nick key := "dm|" + author
if !rl.allow(key, cfg.MentionMinInterval) { if !rl.allow(key, cfg.MentionMinInterval) {
logger.Debug("mention suppressed", "reason", "rate_limit", "channel", channel, "author", author) logger.Debug("dm suppressed", "reason", "rate_limit", "from", author)
return return
} }
if err := nt.Notify(ctx, "IRC mention in "+channel, author+": "+text); err != nil { if err := nt.Notify(ctx, "Direct message from "+author, text); err != nil {
logger.Error("dm notify", "err", err)
} else {
atomic.AddInt64(&metrics.NotificationsSent, 1)
logger.Debug("dm notified", "from", author)
}
}
return
}
// Mentions in channels
if mentionChecker(text) && allowedChannel(storeChan) {
if nt != nil {
if !cfg.NotifyBackfill && time.Since(at) > 5*time.Minute {
logger.Debug("mention suppressed", "reason", "backfill", "channel", storeChan, "author", author)
return
}
if config.WithinQuietHours(at, cfg.QuietHours) && !isUrgent(text) {
logger.Debug("mention suppressed", "reason", "quiet_hours", "channel", storeChan, "author", author)
return
}
key := storeChan + "|" + cfg.Nick
if !rl.allow(key, cfg.MentionMinInterval) {
logger.Debug("mention suppressed", "reason", "rate_limit", "channel", storeChan, "author", author)
return
}
if err := nt.Notify(ctx, "IRC mention in "+storeChan, author+": "+text); err != nil {
logger.Error("mention notify", "err", err) logger.Error("mention notify", "err", err)
} else { } else {
atomic.AddInt64(&metrics.NotificationsSent, 1) atomic.AddInt64(&metrics.NotificationsSent, 1)
logger.Debug("mention notified", "channel", channel, "author", author) logger.Debug("mention notified", "channel", storeChan, "author", author)
} }
} }
} }