diff options
author | delthas <delthas@dille.cc> | 2021-07-12 11:43:22 +0200 |
---|---|---|
committer | Hubert Hirtz <hubert@hirtz.pm> | 2021-07-13 13:40:57 +0200 |
commit | 01c27150b773b578a24096caf5fa618ae3b19aa6 (patch) | |
tree | 58da8b4371b3c4e528c7e338d73d022a383a4f09 /irc | |
parent | Sort channel members by name (diff) |
Ratelimit +typing and send +typing=done once only
Diffstat (limited to 'irc')
-rw-r--r-- | irc/session.go | 37 | ||||
-rw-r--r-- | irc/typing.go | 8 |
2 files changed, 40 insertions, 5 deletions
diff --git a/irc/session.go b/irc/session.go index dabec03..376015f 100644 --- a/irc/session.go +++ b/irc/session.go @@ -11,6 +11,8 @@ import ( "time" "unicode" "unicode/utf8" + + "golang.org/x/time/rate" ) type SASLClient interface { @@ -102,8 +104,8 @@ type Session struct { out chan<- Message closed bool registered bool - typings *Typings // incoming typing notifications. - typingStamps map[string]time.Time // user typing instants. + typings *Typings // incoming typing notifications. + typingStamps map[string]typingStamp // user typing instants. nick string nickCf string // casemapped nickname. @@ -134,7 +136,7 @@ func NewSession(out chan<- Message, params SessionParams) *Session { s := &Session{ out: out, typings: NewTypings(), - typingStamps: map[string]time.Time{}, + typingStamps: map[string]typingStamp{}, nick: params.Nickname, nickCf: CasemapASCII(params.Nickname), user: params.Username, @@ -342,10 +344,19 @@ func (s *Session) Typing(target string) { } targetCf := s.casemap(target) now := time.Now() - if t, ok := s.typingStamps[targetCf]; ok && now.Sub(t).Seconds() < 3.0 { + t, ok := s.typingStamps[targetCf] + if ok && ((t.Type == TypingActive && now.Sub(t.Last).Seconds() < 3.0) || !t.Limit.Allow()) { return } - s.typingStamps[targetCf] = now + if !ok { + t.Limit = rate.NewLimiter(rate.Limit(1.0/3.0), 5) + t.Limit.Reserve() // will always be OK + } + s.typingStamps[targetCf] = typingStamp{ + Last: now, + Type: TypingActive, + Limit: t.Limit, + } s.out <- NewMessage("TAGMSG", target).WithTag("+typing", "active") } @@ -353,6 +364,22 @@ func (s *Session) TypingStop(target string) { if !s.HasCapability("message-tags") { return } + targetCf := s.casemap(target) + now := time.Now() + t, ok := s.typingStamps[targetCf] + if ok && (t.Type == TypingDone || !t.Limit.Allow()) { + // don't send a +typing=done again if the last typing we sent was a +typing=done + return + } + if !ok { + t.Limit = rate.NewLimiter(rate.Limit(1), 5) + t.Limit.Reserve() // will always be OK + } + s.typingStamps[targetCf] = typingStamp{ + Last: now, + Type: TypingDone, + Limit: t.Limit, + } s.out <- NewMessage("TAGMSG", target).WithTag("+typing", "done") } diff --git a/irc/typing.go b/irc/typing.go index 5f028e4..5a3073c 100644 --- a/irc/typing.go +++ b/irc/typing.go @@ -3,6 +3,8 @@ package irc import ( "sync" "time" + + "golang.org/x/time/rate" ) // Typing is an event of Name actively typing in Target. @@ -86,3 +88,9 @@ func (ts *Typings) List(target string) []string { } return res } + +type typingStamp struct { + Last time.Time + Type int + Limit *rate.Limiter +} |