Implement rate limiting
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
|
import asyncio
|
||||||
|
import random
|
||||||
from synapse.module_api import ModuleApi, errors
|
from synapse.module_api import ModuleApi, errors
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -6,7 +8,6 @@ logger = logging.getLogger(__name__)
|
|||||||
class AutoInviteBotModule:
|
class AutoInviteBotModule:
|
||||||
def __init__(self, config, api: ModuleApi):
|
def __init__(self, config, api: ModuleApi):
|
||||||
self.api = api
|
self.api = api
|
||||||
# Fetch the bot user ID from the config file
|
|
||||||
self.auto_invite_user_id = config.get("auto_invite_user_id")
|
self.auto_invite_user_id = config.get("auto_invite_user_id")
|
||||||
if not self.auto_invite_user_id:
|
if not self.auto_invite_user_id:
|
||||||
raise ValueError("auto_invite_user_id must be configured")
|
raise ValueError("auto_invite_user_id must be configured")
|
||||||
@@ -16,7 +17,6 @@ class AutoInviteBotModule:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_config(config):
|
def parse_config(config):
|
||||||
# Validate that the auto_invite_user_id is in the config
|
|
||||||
if "auto_invite_user_id" not in config:
|
if "auto_invite_user_id" not in config:
|
||||||
logger.error("auto_invite_user_id not provided in config")
|
logger.error("auto_invite_user_id not provided in config")
|
||||||
raise Exception("auto_invite_user_id must be provided in config")
|
raise Exception("auto_invite_user_id must be provided in config")
|
||||||
@@ -28,24 +28,32 @@ class AutoInviteBotModule:
|
|||||||
inviter = event['sender']
|
inviter = event['sender']
|
||||||
invitee = event['state_key']
|
invitee = event['state_key']
|
||||||
|
|
||||||
# Check if the bot is already in the room
|
try:
|
||||||
|
await self.retry_invite(self.auto_invite_user_id, room_id, inviter)
|
||||||
|
logger.info(f"Invited bot to room {room_id} as {invitee} was invited by {inviter}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to invite bot to room {room_id}: {str(e)}")
|
||||||
|
|
||||||
|
async def retry_invite(self, bot_user_id, room_id, inviter, retries=5, base_delay=1):
|
||||||
|
for attempt in range(retries):
|
||||||
try:
|
try:
|
||||||
state = await self.api.get_room_state(room_id)
|
state = await self.api.get_room_state(room_id)
|
||||||
bot_membership = state.get(("m.room.member", self.auto_invite_user_id), {}).get("content", {}).get("membership")
|
bot_membership = state.get(("m.room.member", bot_user_id), {}).get("content", {}).get("membership")
|
||||||
|
|
||||||
if bot_membership != "join":
|
if bot_membership != "join":
|
||||||
await self.api.update_room_membership(
|
await self.api.update_room_membership(
|
||||||
sender=inviter,
|
sender=inviter,
|
||||||
target=self.auto_invite_user_id,
|
target=bot_user_id,
|
||||||
room_id=room_id,
|
room_id=room_id,
|
||||||
new_membership="invite"
|
new_membership="invite"
|
||||||
)
|
)
|
||||||
logger.info(f"Invited bot to room {room_id} as {invitee} was invited by {inviter}")
|
return # If invite is successful, return immediately
|
||||||
|
|
||||||
except errors.SynapseError as e:
|
except errors.SynapseError as e:
|
||||||
logger.error(f"Failed to invite bot to room {room_id}: {str(e)}")
|
if e.errcode == 'M_LIMIT_EXCEEDED' and attempt < retries - 1:
|
||||||
|
wait_time = base_delay * 2 ** attempt + random.uniform(0, 1) * base_delay
|
||||||
|
await asyncio.sleep(wait_time)
|
||||||
|
else:
|
||||||
|
raise # Raise the error if it's not a rate limit or we've exhausted retries
|
||||||
|
|
||||||
def setup(config, api):
|
def setup(config, api):
|
||||||
# Parse and validate config when setting up the module
|
|
||||||
module_config = AutoInviteBotModule.parse_config(config)
|
module_config = AutoInviteBotModule.parse_config(config)
|
||||||
return AutoInviteBotModule(module_config, api)
|
return AutoInviteBotModule(module_config, api)
|
||||||
|
Reference in New Issue
Block a user