Michael H d3f406a34a [V3 Travis] Update travis to not skip pipfile lock... (#1678)
* Update travis to not sip pipfile lock

update pipfile dependencies

additional black formatting pass to conform to black 18.5b

* .

* pin async timeout until further discussion of 3.5 support

* .
2018-05-18 17:48:22 -08:00

60 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()
]