From ac578823dc300d3aa62152615d34183fcb3f3d1a Mon Sep 17 00:00:00 2001 From: delthas Date: Mon, 24 Oct 2022 14:56:35 +0200 Subject: [PATCH] Fix clearing webpush targets after any MARKREAD Previously, we would clear webpush targets after any MARKREAD. Consider the following scenario (ignore any typos, this is crafted by hand): <<< @time=2020-01-01T00:00:00Z PRIVMSG #foo :hi mark! <<< @time=2020-01-02T00:00:00Z PRIVMSG #foo :hi again mark! >>> MARKREAD #foo timestamp=2020-01-01T00:00:00Z >>> MARKREAD #foo timestamp=2020-01-02T00:00:00Z The push target was previously cleared on the first MARKREAD, which means that the second MARKREAD was never broadcast to Firebase, and all devices would keep the "hi again mark!" notification indefinitely. This changes the webpush target map so that we store a timestamp of the last highlight we sent. We only clear the push target when sending a MARKREAD that is at or after the last message. --- downstream.go | 4 +++- irc.go | 14 +++++++++++--- upstream.go | 4 +++- user.go | 4 ++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/downstream.go b/downstream.go index 3a452d5..4ba6792 100644 --- a/downstream.go +++ b/downstream.go @@ -2818,7 +2818,9 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc. if broadcast && network.pushTargets.Has(target) { // TODO: only broadcast if draft/read-marker has been negotiated - network.pushTargets.Del(target) + if !r.Timestamp.Before(network.pushTargets.Get(target)) { + network.pushTargets.Del(target) + } go network.broadcastWebPush(&irc.Message{ Command: "MARKREAD", Params: []string{target, timestampStr}, diff --git a/irc.go b/irc.go index d5e0a69..464d9f8 100644 --- a/irc.go +++ b/irc.go @@ -459,10 +459,18 @@ func (cm *monitorCasemapMap) ForEach(f func(name string, online bool)) { } } -type casemapSet struct{ casemapMap } +type pushTargetCasemapMap struct{ casemapMap } -func (cs *casemapSet) Add(name string) { - cs.set(name, nil) +func (cm *pushTargetCasemapMap) Get(name string) (last time.Time) { + if v := cm.get(name); v == nil { + return time.Time{} + } else { + return v.(time.Time) + } +} + +func (cm *pushTargetCasemapMap) Set(name string, last time.Time) { + cm.set(name, last) } func isWordBoundary(r rune) bool { diff --git a/upstream.go b/upstream.go index 032e710..5e47dc7 100644 --- a/upstream.go +++ b/upstream.go @@ -556,7 +556,9 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err if highlight || uc.isOurNick(target) { go uc.network.broadcastWebPush(msg) - uc.network.pushTargets.Add(bufferName) + if timestamp, err := time.Parse(xirc.ServerTimeLayout, string(msg.Tags["time"])); err == nil { + uc.network.pushTargets.Set(bufferName, timestamp) + } } uc.produce(bufferName, msg, downstreamID) diff --git a/user.go b/user.go index ef9433f..8b83c34 100644 --- a/user.go +++ b/user.go @@ -141,7 +141,7 @@ type network struct { conn *upstreamConn channels channelCasemapMap delivered deliveredStore - pushTargets casemapSet + pushTargets pushTargetCasemapMap lastError error casemap casemapping } @@ -162,7 +162,7 @@ func newNetwork(user *user, record *database.Network, channels []database.Channe stopped: make(chan struct{}), channels: m, delivered: newDeliveredStore(), - pushTargets: casemapSet{newCasemapMap()}, + pushTargets: pushTargetCasemapMap{newCasemapMap()}, casemap: casemapRFC1459, } }