mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-23 11:12:44 +01:00
Merge pull request #1993 from slingamn/fakelag_budget.3
exempt a configurable number of MARKREAD commands from fakelag
This commit is contained in:
commit
0e8f447326
@ -849,6 +849,14 @@ fakelag:
|
||||
# sending any commands:
|
||||
cooldown: 2s
|
||||
|
||||
# exempt a certain number of command invocations per session from fakelag;
|
||||
# this is to speed up "resynchronization" of client state during reattach
|
||||
command-budgets:
|
||||
"CHATHISTORY": 16
|
||||
"MARKREAD": 16
|
||||
"MONITOR": 1
|
||||
"WHO": 4
|
||||
|
||||
# the roleplay commands are semi-standardized extensions to IRC that allow
|
||||
# sending and receiving messages from pseudo-nicknames. this can be used either
|
||||
# for actual roleplaying, or for bridging IRC with other protocols.
|
||||
|
@ -668,12 +668,21 @@ func (client *Client) run(session *Session) {
|
||||
}
|
||||
}
|
||||
|
||||
msg, err := ircmsg.ParseLineStrict(line, true, MaxLineLen)
|
||||
// XXX defer processing of command error parsing until after fakelag
|
||||
|
||||
if client.registered {
|
||||
touches := session.deferredFakelagCount + 1
|
||||
session.deferredFakelagCount = 0
|
||||
for i := 0; i < touches; i++ {
|
||||
session.fakelag.Touch()
|
||||
// apply deferred fakelag
|
||||
for i := 0; i < session.deferredFakelagCount; i++ {
|
||||
session.fakelag.Touch("")
|
||||
}
|
||||
session.deferredFakelagCount = 0
|
||||
// touch for the current command
|
||||
var command string
|
||||
if err == nil {
|
||||
command = msg.Command
|
||||
}
|
||||
session.fakelag.Touch(command)
|
||||
} else {
|
||||
// DoS hardening, #505
|
||||
session.registrationMessages++
|
||||
@ -683,7 +692,6 @@ func (client *Client) run(session *Session) {
|
||||
}
|
||||
}
|
||||
|
||||
msg, err := ircmsg.ParseLineStrict(line, true, MaxLineLen)
|
||||
if err == ircmsg.ErrorLineIsEmpty {
|
||||
continue
|
||||
} else if err == ircmsg.ErrorTagsTooLong {
|
||||
|
@ -524,6 +524,7 @@ type FakelagConfig struct {
|
||||
BurstLimit uint `yaml:"burst-limit"`
|
||||
MessagesPerWindow uint `yaml:"messages-per-window"`
|
||||
Cooldown time.Duration
|
||||
CommandBudgets map[string]int `yaml:"command-budgets"`
|
||||
}
|
||||
|
||||
type TorListenersConfig struct {
|
||||
@ -1428,6 +1429,17 @@ func LoadConfig(filename string) (config *Config, err error) {
|
||||
}
|
||||
config.Server.capValues[caps.Languages] = config.languageManager.CapValue()
|
||||
|
||||
if len(config.Fakelag.CommandBudgets) != 0 {
|
||||
// normalize command names to uppercase:
|
||||
commandBudgets := make(map[string]int, len(config.Fakelag.CommandBudgets))
|
||||
for command, budget := range config.Fakelag.CommandBudgets {
|
||||
commandBudgets[strings.ToUpper(command)] = budget
|
||||
}
|
||||
config.Fakelag.CommandBudgets = commandBudgets
|
||||
} else {
|
||||
config.Fakelag.CommandBudgets = nil
|
||||
}
|
||||
|
||||
if config.Server.Relaymsg.Enabled {
|
||||
for _, char := range protocolBreakingNameCharacters {
|
||||
if strings.ContainsRune(config.Server.Relaymsg.Separators, char) {
|
||||
|
@ -5,6 +5,8 @@ package irc
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ergochat/ergo/irc/utils"
|
||||
)
|
||||
|
||||
// fakelag is a system for artificially delaying commands when a user issues
|
||||
@ -36,6 +38,10 @@ type Fakelag struct {
|
||||
|
||||
func (fl *Fakelag) Initialize(config FakelagConfig) {
|
||||
fl.config = config
|
||||
// XXX don't share mutable member CommandBudgets:
|
||||
if config.CommandBudgets != nil {
|
||||
fl.config.CommandBudgets = utils.CopyMap(config.CommandBudgets)
|
||||
}
|
||||
fl.nowFunc = time.Now
|
||||
fl.sleepFunc = time.Sleep
|
||||
fl.state = FakelagBursting
|
||||
@ -58,11 +64,16 @@ func (fl *Fakelag) Unsuspend() {
|
||||
}
|
||||
|
||||
// register a new command, sleep if necessary to delay it
|
||||
func (fl *Fakelag) Touch() {
|
||||
func (fl *Fakelag) Touch(command string) {
|
||||
if !fl.config.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
if budget, ok := fl.config.CommandBudgets[command]; ok && budget > 0 {
|
||||
fl.config.CommandBudgets[command] = budget - 1
|
||||
return
|
||||
}
|
||||
|
||||
now := fl.nowFunc()
|
||||
// XXX if lastTouch.IsZero(), treat it as "very far in the past", which is fine
|
||||
elapsed := now.Sub(fl.lastTouch)
|
||||
|
@ -60,7 +60,7 @@ func TestFakelag(t *testing.T) {
|
||||
window, _ := time.ParseDuration("1s")
|
||||
fl, mt := newFakelagForTesting(window, 3, 2, window)
|
||||
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
slept, _ := mt.lastSleep()
|
||||
if slept {
|
||||
t.Fatalf("should not have slept")
|
||||
@ -69,7 +69,7 @@ func TestFakelag(t *testing.T) {
|
||||
interval, _ := time.ParseDuration("100ms")
|
||||
for i := 0; i < 2; i++ {
|
||||
mt.pause(interval)
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
slept, _ := mt.lastSleep()
|
||||
if slept {
|
||||
t.Fatalf("should not have slept")
|
||||
@ -77,7 +77,7 @@ func TestFakelag(t *testing.T) {
|
||||
}
|
||||
|
||||
mt.pause(interval)
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
if fl.state != FakelagThrottled {
|
||||
t.Fatalf("should be throttled")
|
||||
}
|
||||
@ -91,7 +91,7 @@ func TestFakelag(t *testing.T) {
|
||||
}
|
||||
|
||||
// send another message without a pause; we should have to sleep for 500 msec
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
if fl.state != FakelagThrottled {
|
||||
t.Fatalf("should be throttled")
|
||||
}
|
||||
@ -102,7 +102,7 @@ func TestFakelag(t *testing.T) {
|
||||
}
|
||||
|
||||
mt.pause(interval * 6)
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
if fl.state != FakelagThrottled {
|
||||
t.Fatalf("should still be throttled")
|
||||
}
|
||||
@ -112,7 +112,7 @@ func TestFakelag(t *testing.T) {
|
||||
}
|
||||
|
||||
mt.pause(window * 2)
|
||||
fl.Touch()
|
||||
fl.Touch("")
|
||||
if fl.state != FakelagBursting {
|
||||
t.Fatalf("should be bursting again")
|
||||
}
|
||||
|
@ -821,6 +821,14 @@ fakelag:
|
||||
# sending any commands:
|
||||
cooldown: 2s
|
||||
|
||||
# exempt a certain number of command invocations per session from fakelag;
|
||||
# this is to speed up "resynchronization" of client state during reattach
|
||||
command-budgets:
|
||||
"CHATHISTORY": 16
|
||||
"MARKREAD": 16
|
||||
"MONITOR": 1
|
||||
"WHO": 4
|
||||
|
||||
# the roleplay commands are semi-standardized extensions to IRC that allow
|
||||
# sending and receiving messages from pseudo-nicknames. this can be used either
|
||||
# for actual roleplaying, or for bridging IRC with other protocols.
|
||||
|
Loading…
Reference in New Issue
Block a user