aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar klea2026-05-01 14:56:53 +0000
committerGravatar klea2026-05-01 14:56:53 +0000
commita0ce214430138ddd93dc36c56e4bec533c92d195 (patch)
tree11dd3ee1bcb724f7f473bab61f334d2ba2ab9963
parentAllow having certain irc config changes without reconnect (diff)
signature
Allow setting a global message ratelimit
This allows configuring a http2irc instance to have a higher global message sending rate limit different from the default hard-coded rate of 1 message / second, whilst keeping backwards compatibility by keeping default value being the hard-coded one. In addition if the rate limit is set to 0, which can be done live, the bot will stop sending queued messages whilst keeping the IRC connection alive.
-rw-r--r--config.example.toml2
-rw-r--r--http2irc.py18
2 files changed, 16 insertions, 4 deletions
diff --git a/config.example.toml b/config.example.toml
index 59a9f09..3c0c6a0 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -11,6 +11,8 @@
#family =
#nick = 'h2ibot'
#real = 'I am an http2irc bot.'
+ #sendratelimit = 1
+ # Set to the number of lines per second you want the bot to be able to send globally.
# Certificate and key for SASL EXTERNAL authentication with NickServ; certfile is a string containing the path to a .pem file which has the certificate and the key, certkeyfile similarly for one containing only the key; default values are empty (None in Python) to disable authentication; the connection is terminated if authentication fails
#certfile =
#certkeyfile =
diff --git a/http2irc.py b/http2irc.py
index a73f23d..57c66ac 100644
--- a/http2irc.py
+++ b/http2irc.py
@@ -104,7 +104,7 @@ class Config(dict):
except (ValueError, AssertionError) as e:
raise InvalidConfig('Invalid log format: parsing failed') from e
if 'irc' in obj:
- if any(x not in ('host', 'port', 'ssl', 'family', 'nick', 'real', 'certfile', 'certkeyfile') for x in obj['irc']):
+ if any(x not in ('host', 'port', 'ssl', 'family', 'nick', 'real', 'certfile', 'certkeyfile', 'sendratelimit') for x in obj['irc']):
raise InvalidConfig('Unknown key found in irc section')
if 'host' in obj['irc'] and not isinstance(obj['irc']['host'], str): #TODO: Check whether it's a valid hostname
raise InvalidConfig('Invalid IRC host')
@@ -124,6 +124,11 @@ class Config(dict):
raise InvalidConfig('Invalid IRC nick: contains illegal characters')
if len(IRCClientProtocol.nick_command(obj['irc']['nick'])) > 510:
raise InvalidConfig('Invalid IRC nick: NICK command too long')
+ if 'sendratelimit' in obj['irc']:
+ if not type(obj['irc']['sendratelimit']) in [float, int]:
+ raise InvalidConfig('Invalid ratelimit, must be a float or a integer')
+ if obj['irc']['sendratelimit'] < 0:
+ raise InvalidConfig('Ratelimit must be positive')
if 'real' in obj['irc'] and not isinstance(obj['irc']['real'], str):
raise InvalidConfig('Invalid IRC realname')
if len(IRCClientProtocol.user_command(obj['irc']['nick'], obj['irc']['real'])) > 510:
@@ -225,7 +230,7 @@ class Config(dict):
# Default values
finalObj = {
'logging': {'level': 'INFO', 'format': '{asctime} {levelname} {name} {message}'},
- 'irc': {'host': 'irc.hackint.org', 'port': 6697, 'ssl': 'yes', 'family': 0, 'nick': 'h2ibot', 'real': 'I am an http2irc bot.', 'certfile': None, 'certkeyfile': None},
+ 'irc': {'host': 'irc.hackint.org', 'port': 6697, 'ssl': 'yes', 'family': 0, 'nick': 'h2ibot', 'real': 'I am an http2irc bot.', 'certfile': None, 'certkeyfile': None, 'sendratelimit': 1 },
'web': {'host': '127.0.0.1', 'port': 8080, 'maxrequestsize': 1048576},
'maps': {}
}
@@ -484,11 +489,16 @@ class IRCClientProtocol(asyncio.Protocol):
data = t.result()
self.logger.debug(f'Got {data!r} from send queue')
now = time.time()
- if self.lastSentTime is not None and now - self.lastSentTime < 1:
- self.logger.debug(f'Rate limited')
+ if self.config['irc']['sendratelimit'] == 0:
+ self.logger.debug(f'Rate limited, not sending messages for now.')
await wait_cancel_pending({asyncio.create_task(self.connectionClosedEvent.wait())}, timeout = self.lastSentTime + 1 - now)
if self.connectionClosedEvent.is_set():
break
+ if (self.lastSentTime is not None and now - self.lastSentTime < 1/self.config['irc']['sendratelimit']) or self.config['irc']['sendratelimit'] == 0:
+ self.logger.debug(f'Rate limited')
+ await wait_cancel_pending({asyncio.create_task(self.connectionClosedEvent.wait())}, timeout = self.lastSentTime + 1/self.config['irc']['sendratelimit'] - now)
+ if self.connectionClosedEvent.is_set():
+ break
time_ = self._direct_send(data)
if self.lastSentTime is not None:
self.lastSentTime = time_