Michael H b88b5a2601 [V3] Update code standards (black code format pass) (#1650)
* ran black: code formatter against `redbot/` with `-l 99`

* badge
2018-05-14 15:33:24 -04:00

59 lines
1.9 KiB
Python

from datetime import datetime, timedelta
from typing import Tuple, List
from collections import namedtuple
Interval = Tuple[timedelta, int]
AntiSpamInterval = namedtuple("AntiSpamInterval", ["period", "frequency"])
class AntiSpam:
"""
Custom class which is more flexible than using discord.py's
`commands.cooldown()`
Can be intialized with a custom set of intervals
These should be provided as a list of tuples in the form
(timedelta, quantity)
Where quantity represents the maximum amount of times
something should be allowed in an interval.
"""
# TODO : Decorator interface for command check using `spammy`
# with insertion of the antispam element into context
# for manual stamping on succesful command completion
default_intervals = [
(timedelta(seconds=5), 3),
(timedelta(minutes=1), 5),
(timedelta(hours=1), 10),
(timedelta(days=1), 24),
]
def __init__(self, intervals: List[Interval]):
self.__event_timestamps = []
_itvs = intervals if intervals else self.default_intervals
self.__intervals = [AntiSpamInterval(*x) for x in _itvs]
self.__discard_after = max([x.period for x in self.__intervals])
def __interval_check(self, interval: AntiSpamInterval):
return len(
[t for t in self.__event_timestamps if (t + interval.period) > datetime.utcnow()]
) >= interval.frequency
@property
def spammy(self):
"""
use this to check if any interval criteria are met
"""
return any(self.__interval_check(x) for x in self.__intervals)
def stamp(self):
"""
Use this to mark an event that counts against the intervals
as happening now
"""
self.__event_timestamps.append(datetime.utcnow())
self.__event_timestamps = [
t for t in self.__event_timestamps if t + self.__discard_after > datetime.utcnow()
]