From be513622ac04bee46be89d1817e23b04f37f5acd Mon Sep 17 00:00:00 2001
From: Wim <wim@42.be>
Date: Tue, 1 Nov 2016 22:52:28 +0100
Subject: Add anti-flooding settings (irc). See #40

---
 bridge/config/config.go |  2 ++
 bridge/irc/irc.go       | 31 ++++++++++++++++++++++++++++---
 2 files changed, 30 insertions(+), 3 deletions(-)

(limited to 'bridge')

diff --git a/bridge/config/config.go b/bridge/config/config.go
index aa881a79..89222894 100644
--- a/bridge/config/config.go
+++ b/bridge/config/config.go
@@ -34,6 +34,8 @@ type Protocol struct {
 	Password               string // IRC,mattermost,XMPP
 	PrefixMessagesWithNick bool   // mattemost, slack
 	Protocol               string //all protocols
+	MessageQueue           int    // IRC, size of message queue for flood control
+	MessageDelay           int    // IRC, time in millisecond to wait between messages
 	RemoteNickFormat       string // all protocols
 	Server                 string // IRC,mattermost,XMPP,discord
 	ShowJoinPart           bool   // all protocols
diff --git a/bridge/irc/irc.go b/bridge/irc/irc.go
index e5b6858c..30f27724 100644
--- a/bridge/irc/irc.go
+++ b/bridge/irc/irc.go
@@ -23,6 +23,7 @@ type Birc struct {
 	protocol  string
 	Remote    chan config.Message
 	connected chan struct{}
+	Local     chan config.Message // local queue for flood control
 }
 
 var flog *log.Entry
@@ -32,15 +33,22 @@ func init() {
 	flog = log.WithFields(log.Fields{"module": protocol})
 }
 
-func New(config config.Protocol, origin string, c chan config.Message) *Birc {
+func New(cfg config.Protocol, origin string, c chan config.Message) *Birc {
 	b := &Birc{}
-	b.Config = &config
+	b.Config = &cfg
 	b.Nick = b.Config.Nick
 	b.Remote = c
 	b.names = make(map[string][]string)
 	b.origin = origin
 	b.protocol = protocol
 	b.connected = make(chan struct{})
+	if b.Config.MessageDelay == 0 {
+		b.Config.MessageDelay = 1300
+	}
+	if b.Config.MessageQueue == 0 {
+		b.Config.MessageQueue = 30
+	}
+	b.Local = make(chan config.Message, b.Config.MessageQueue+10)
 	return b
 }
 
@@ -81,6 +89,7 @@ func (b *Birc) Connect() error {
 		return fmt.Errorf("connection timed out")
 	}
 	i.Debug = false
+	go b.doSend()
 	return nil
 }
 
@@ -115,11 +124,27 @@ func (b *Birc) Send(msg config.Message) error {
 		return nil
 	}
 	for _, text := range strings.Split(msg.Text, "\n") {
-		b.i.Privmsg(msg.Channel, msg.Username+text)
+		if len(b.Local) < b.Config.MessageQueue {
+			if len(b.Local) == b.Config.MessageQueue-1 {
+				text = text + " <message clipped>"
+			}
+			b.Local <- config.Message{Text: text, Username: msg.Username, Channel: msg.Channel}
+		} else {
+			flog.Debugf("flooding, dropping message (queue at %d)", len(b.Local))
+		}
 	}
 	return nil
 }
 
+func (b *Birc) doSend() {
+	rate := time.Millisecond * time.Duration(b.Config.MessageDelay)
+	throttle := time.Tick(rate)
+	for msg := range b.Local {
+		<-throttle
+		b.i.Privmsg(msg.Channel, msg.Username+msg.Text)
+	}
+}
+
 func (b *Birc) endNames(event *irc.Event) {
 	channel := event.Arguments[1]
 	sort.Strings(b.names[channel])
-- 
cgit v1.2.3