Skip to content
/ girc Public
forked from lrstanley/girc

Commit

Permalink
better checks before ratelimiting; drop events if disconnected (closes
Browse files Browse the repository at this point in the history
  • Loading branch information
lrstanley authored and nmeum committed Apr 22, 2020
1 parent 8b4f823 commit 312322c
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
22 changes: 22 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -754,3 +754,25 @@ func (c *Client) panicIfNotTracking() {

panic(fmt.Sprintf("%s used when tracking is disabled (caller %s:%d)", fn.Name(), file, line))
}

func (c *Client) debugLogEvent(e *Event, dropped bool) {
var prefix string

if dropped {
prefix = "dropping event (disconnected):"
} else {
prefix = ">"
}

if e.Sensitive {
c.debug.Printf(prefix, " %s ***redacted***", e.Command)
} else {
c.debug.Print(prefix, " ", StripRaw(e.String()))
}

if c.Config.Out != nil {
if pretty, ok := e.Pretty(); ok {
fmt.Fprintln(c.Config.Out, StripRaw(pretty))
}
}
}
44 changes: 28 additions & 16 deletions conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,16 +430,42 @@ func (c *Client) readLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
// Send sends an event to the server. Use Client.RunHandlers() if you are
// simply looking to trigger handlers with an event.
func (c *Client) Send(event *Event) {
var delay time.Duration

if !c.Config.AllowFlood {
<-time.After(c.conn.rate(event.Len()))
c.mu.RLock()

// Drop the event early as we're disconnected, this way we don't have to wait
// the (potentially long) rate limit delay before dropping.
if c.conn == nil {
c.debugLogEvent(event, true)
c.mu.RUnlock()
return
}

c.conn.mu.Lock()
delay = c.conn.rate(event.Len())
c.conn.mu.Unlock()
c.mu.RUnlock()
}

if c.Config.GlobalFormat && len(event.Params) > 0 && event.Params[len(event.Params)-1] != "" &&
(event.Command == PRIVMSG || event.Command == TOPIC || event.Command == NOTICE) {
event.Params[len(event.Params)-1] = Fmt(event.Params[len(event.Params)-1])
}

<-time.After(delay)

// Relock client again as there may be an extended delay.
c.mu.RLock()
if c.conn == nil {
// Drop the event if disconnected.
c.debugLogEvent(event, true)
c.mu.RUnlock()
return
}
c.write(event)
c.mu.RUnlock()
}

// write is the lower level function to write an event. It does not have a
Expand All @@ -453,14 +479,10 @@ func (c *Client) write(event *Event) {
func (c *ircConn) rate(chars int) time.Duration {
_time := time.Second + ((time.Duration(chars) * time.Second) / 100)

c.mu.Lock()
if c.writeDelay += _time - time.Now().Sub(c.lastWrite); c.writeDelay < 0 {
c.writeDelay = 0
}
c.mu.Unlock()

c.mu.RLock()
defer c.mu.RUnlock()
if c.writeDelay > (8 * time.Second) {
return _time
}
Expand Down Expand Up @@ -495,17 +517,7 @@ func (c *Client) sendLoop(ctx context.Context, errs chan error, wg *sync.WaitGro
}
}

// Log the event.
if event.Sensitive {
c.debug.Printf("> %s ***redacted***", event.Command)
} else {
c.debug.Print("> ", StripRaw(event.String()))
}
if c.Config.Out != nil {
if pretty, ok := event.Pretty(); ok {
fmt.Fprintln(c.Config.Out, StripRaw(pretty))
}
}
c.debugLogEvent(event, false)

c.conn.mu.Lock()
c.conn.lastWrite = time.Now()
Expand Down

0 comments on commit 312322c

Please sign in to comment.