summaryrefslogtreecommitdiff
path: root/irc
diff options
context:
space:
mode:
authordelthas <delthas@dille.cc>2021-07-12 11:43:22 +0200
committerHubert Hirtz <hubert@hirtz.pm>2021-07-13 13:40:57 +0200
commit01c27150b773b578a24096caf5fa618ae3b19aa6 (patch)
tree58da8b4371b3c4e528c7e338d73d022a383a4f09 /irc
parentSort channel members by name (diff)
Ratelimit +typing and send +typing=done once only
Fixes: #8 Fixes: #41
Diffstat (limited to 'irc')
-rw-r--r--irc/session.go37
-rw-r--r--irc/typing.go8
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
+}