Skip to content

Commit 9919400

Browse files
committed
Introduced Karma rate limit
modified: README.md modified: bot_core/irc_bot.py new file: karma/karma_rate.py
1 parent 8556f2f commit 9919400

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
pyircbot
22
========
33

4-
A simple python-twisted IRC bot with greetings and karma functionalities
4+
A simple python-twisted IRC bot with greetings and karma functionalities
5+
6+
# Usage
7+
8+
`$ python pyircbot.py --help`

bot_core/irc_bot.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from message_logger import MessageLogger
77
from karma.karma_manager import KarmaManager
8+
from karma.karma_rate import KarmaRateLimiter
89

910
class IRCBot(irc.IRCClient):
1011
"""Python Twisted IRC BOT. irc.IRCClient specialization."""
@@ -25,13 +26,11 @@ def connectionMade(self):
2526
time.asctime(time.localtime(time.time()))
2627
)
2728
self.karma_manager = KarmaManager(self.factory.data_folder)
29+
self.karmrator = KarmaRateLimiter()
2830

2931
def connectionLost(self, reason):
3032
irc.IRCClient.connectionLost(self, reason)
31-
self.logger.log(
32-
"[disconnected at %s]" %
33-
time.asctime(time.localtime(time.time()))
34-
)
33+
self.logger.log("[disconnected at %s]" % self.get_current_timestamp() )
3534
self.logger.close()
3635

3736
# TODO (sentenza) ConfigManager password
@@ -79,7 +78,6 @@ def privmsg(self, user, channel, msg):
7978
def evaluate_command(self, user, channel, msg):
8079
# check for commands starting with bang!
8180
if msg.startswith('!karma'):
82-
print("<%s> send a karma command: %s" % (user,msg))
8381
msg_splits = msg.split()
8482
if len(msg_splits) == 1:
8583
fetch_user = user
@@ -89,14 +87,22 @@ def evaluate_command(self, user, channel, msg):
8987
self.msg(channel, self.karma_manager.fetch_karma(fetch_user))
9088

9189
def karma_update(self, user, channel, msg):
92-
nickname = msg[:-2]
93-
print "karma command: %s. user affected: %s" % (msg, nickname)
94-
if nickname == user:
95-
self.msg(channel, "%s: you can't alter your own karma!" % user)
96-
return
97-
if msg.endswith('++'):
98-
self.karma_manager.update_karma(nickname, plus=True)
99-
if msg.endswith('--'):
100-
self.karma_manager.update_karma(nickname, plus=False)
101-
90+
"""Try to modify the Karma for a given nickname"""
91+
receiver_nickname = msg[:-2]
92+
# TODO (sentenza) Check if the given nick is present on DB or if is on chan with /WHO command
93+
if receiver_nickname == user:
94+
self.msg(channel, "%s: you can't alter your own karma!" % user)
95+
return
96+
if self.karmrator.is_rate_limited(user):
97+
waiting_minutes = self.karmrator.user_timeout(user) / 60
98+
self.msg(channel, "%s: you have to wait %s min for your next karmic request!" % (user, waiting_minutes))
99+
return
100+
if msg.endswith('++'):
101+
self.karma_manager.update_karma(receiver_nickname, plus=True)
102+
if msg.endswith('--'):
103+
self.karma_manager.update_karma(receiver_nickname, plus=False)
104+
self.msg(channel, self.karma_manager.fetch_karma(receiver_nickname))
105+
self.logger.log("%s modified Karma: %s" % (user, receiver_nickname))
102106

107+
def get_current_timestamp(self):
108+
return time.asctime(time.localtime(time.time()))

karma/karma_rate.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import time
2+
from collections import defaultdict
3+
4+
class KarmaRateLimiter(object):
5+
6+
def __init__(self, timeout=3600):
7+
"""timeout in seconds - default 1 h"""
8+
self.timeout = timeout
9+
# http://goo.gl/ZFmFX
10+
# http://stackoverflow.com/a/5900628
11+
self.user_last_request = defaultdict(int)
12+
13+
def is_rate_limited(self, nick):
14+
now = int(time.time())
15+
if nick not in self.user_last_request:
16+
self.user_last_request[nick] = now
17+
return False
18+
elif (now - self.user_last_request[nick]) < self.timeout:
19+
return True
20+
else:
21+
self.user_last_request[nick] = now
22+
return False
23+
24+
def user_timeout(self, nick):
25+
"""Return the user specific timeout"""
26+
if nick not in self.user_last_request:
27+
return 0
28+
else:
29+
wait_time = self.timeout - (int(time.time()) - self.user_last_request[nick])
30+
return wait_time

0 commit comments

Comments
 (0)