From b9806626aae93bd714bc155febf65dd62b226764 Mon Sep 17 00:00:00 2001 From: aticie Date: Tue, 5 Jul 2022 17:56:32 +0200 Subject: [PATCH] Reduce max user size per instance Add new setting to database for cooldowns Change TwitchBot.PER_REQUEST_COOLDOWN with channel_cooldown --- ronnia/bots/bot_manager.py | 5 +++-- ronnia/bots/twitch_bot.py | 30 +++++++----------------------- ronnia/helpers/database_helper.py | 18 ++++++++++++++---- 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/ronnia/bots/bot_manager.py b/ronnia/bots/bot_manager.py index 261fe9d..a619df8 100644 --- a/ronnia/bots/bot_manager.py +++ b/ronnia/bots/bot_manager.py @@ -85,8 +85,9 @@ def __init__(self, ): self.twitch_client = TwitchAPI(os.getenv('TWITCH_CLIENT_ID'), os.getenv('TWITCH_CLIENT_SECRET')) self._loop = asyncio.get_event_loop() - self.user_per_instance = 150 - self.sleep_after_instance = (self.user_per_instance // 20 + 1) * 11 + self.user_per_instance = 60 + self.channel_join_cooldown = 11 + self.sleep_after_instance = (self.user_per_instance // 20 + 1) * self.channel_join_cooldown self.servicebus_connection_string = os.getenv('SERVICE_BUS_CONNECTION_STR') self.servicebus_webserver_queue_name = 'webserver-signups' diff --git a/ronnia/bots/twitch_bot.py b/ronnia/bots/twitch_bot.py index 254d898..92180a0 100644 --- a/ronnia/bots/twitch_bot.py +++ b/ronnia/bots/twitch_bot.py @@ -9,7 +9,6 @@ from multiprocessing import Lock from typing import AnyStr, Tuple, Union, List -import aiohttp from azure.servicebus import ServiceBusMessage from azure.servicebus.aio import ServiceBusClient from azure.servicebus.exceptions import ServiceBusError @@ -25,7 +24,6 @@ class TwitchBot(commands.Bot, ABC): - PER_REQUEST_COOLDOWN = 30 # each request has 30 seconds cooldown def __init__(self, initial_channel_names: List[str], join_lock: Lock, max_users: int): self.users_db = UserDatabase() @@ -124,21 +122,6 @@ async def receive_and_parse_message(self, message): def run(self): super().run() - @staticmethod - async def _get_access_token(): - client_id = os.getenv('TWITCH_CLIENT_ID'), - client_secret = os.getenv('TWITCH_CLIENT_SECRET') - grant_type = 'client_credentials' - scope = 'chat:read chat:edit' - payload = {'client_id': client_id, - 'client_secret': client_secret, - 'grant_type': grant_type, - 'scope': scope} - async with aiohttp.ClientSession() as session: - async with session.post('https://id.twitch.tv/oauth2/token', data=payload) as resp: - response_json = await resp.json() - return response_json['access_token'] - async def event_message(self, message: Message): if message.author is None: logger.info(f"{message.channel.name}: {message.content}") @@ -276,25 +259,26 @@ async def _check_user_cooldown(self, author: Chatter): """ Check if user is on cooldown, raise an exception if the user is on request cooldown. :param author: Twitch user object - :return: Exception if user has requested a beatmap before TwitchBot.PER_REQUEST_COOLDOWN seconds passed. + :return: Exception if user has requested a beatmap before channel_cooldown seconds passed. """ author_id = author.id time_right_now = datetime.datetime.now() - await self._prune_cooldowns(time_right_now) + channel_cooldown = await self.users_db.get_setting("cooldown", author_id) + await self._prune_cooldowns(time_right_now, channel_cooldown) if author_id not in self.user_last_request: self.user_last_request[author_id] = time_right_now else: last_message_time = self.user_last_request[author_id] seconds_since_last_request = (time_right_now - last_message_time).total_seconds() - assert seconds_since_last_request >= TwitchBot.PER_REQUEST_COOLDOWN, \ + assert seconds_since_last_request >= channel_cooldown, \ f'{author.name} is on cooldown.' self.user_last_request[author_id] = time_right_now return - async def _prune_cooldowns(self, time_right_now: datetime.datetime): + async def _prune_cooldowns(self, time_right_now: datetime.datetime, channel_cooldown: int): """ Prunes users on that are on cooldown list so it doesn't get too cluttered. :param time_right_now: @@ -303,7 +287,7 @@ async def _prune_cooldowns(self, time_right_now: datetime.datetime): pop_list = [] for user_id, last_message_time in self.user_last_request.items(): seconds_since_last_request = (time_right_now - last_message_time).total_seconds() - if seconds_since_last_request >= TwitchBot.PER_REQUEST_COOLDOWN: + if seconds_since_last_request >= channel_cooldown: pop_list.append(user_id) for user in pop_list: @@ -463,7 +447,7 @@ async def update_user_db_info(self, user: sqlite3.Row, osu_info: dict, twitch_in twitch_id = twitch_info.id await self.users_db.update_user(new_twitch_username=twitch_name, new_osu_username=osu_username, osu_user_id=osu_user_id, twitch_id=twitch_id) - logger.info( + logger.debug( f'Updated user information for {user["twitch_username"]}: ' f'{osu_username} | {twitch_name} | {twitch_id} | {osu_user_id}') diff --git a/ronnia/helpers/database_helper.py b/ronnia/helpers/database_helper.py index f792a51..36c1e6d 100644 --- a/ronnia/helpers/database_helper.py +++ b/ronnia/helpers/database_helper.py @@ -36,6 +36,11 @@ def __init__(self, db_path=None): f"INNER JOIN users ON users.user_id=user_settings.user_id " \ f"WHERE user_settings.key=? AND users.twitch_username=?" + self.sql_string_get_setting_by_id = f"SELECT value FROM user_settings " \ + f"INNER JOIN settings ON user_settings.key=settings.key " \ + f"INNER JOIN users ON users.user_id=user_settings.user_id " \ + f"WHERE user_settings.key=? AND users.twitch_id=?" + self.sql_string_get_range_setting = f"SELECT range_start, range_end FROM user_range_settings " \ f"INNER JOIN range_settings ON user_range_settings.key=range_settings.key " \ f"INNER JOIN users ON users.user_id=user_range_settings.user_id " \ @@ -105,6 +110,7 @@ async def initialize(self): await self.define_setting('sub-only', 0, 'Subscribers only request mode.') await self.define_setting('cp-only', 0, 'Channel Points only request mode.') await self.define_setting('test', 0, 'Enables test mode.') + await self.define_setting('cooldown', 30, 'Cooldown for requests.') await self.define_range_setting('sr', -1, -1, 'Star rating limit for requests.') async def set_channel_updated(self, twitch_username: str): @@ -180,7 +186,7 @@ async def get_multiple_users_by_ids(self, twitch_ids: List[int]) -> List[sqlite3 async def get_multiple_users_by_username(self, twitch_names: List[str]) -> List[sqlite3.Row]: """ Gets multiple users from database - :param twitch_ids: List of twitch ids + :param twitch_names: List of twitch names :return: List of users """ query = f"SELECT * FROM users WHERE twitch_username IN ({','.join('?' for i in twitch_names)})" @@ -315,7 +321,7 @@ async def handle_none_type_setting(self, value: str, setting_key: str): if value is None: r = await self.c.execute(f"SELECT default_value FROM settings WHERE key=?", (setting_key,)) value = await r.fetchone() - return bool(value[0]) + return value[0] async def handle_none_type_range_setting(self, value: Optional[sqlite3.Row], setting_key: str): """ @@ -331,14 +337,18 @@ async def handle_none_type_range_setting(self, value: Optional[sqlite3.Row], set return value['default_low'], value['default_high'] return value['range_start'], value['range_end'] - async def get_setting(self, setting_key: str, twitch_username: str): + async def get_setting(self, setting_key: str, twitch_username_or_id: Union[str, int]): """ Get the setting's current value for user :param setting_key: Key of the setting :param twitch_username: Twitch username :return: """ - result = await self.c.execute(self.sql_string_get_setting, (setting_key, twitch_username)) + if isinstance(twitch_username_or_id, str): + result = await self.c.execute(self.sql_string_get_setting, (setting_key, twitch_username_or_id)) + else: + result = await self.c.execute(self.sql_string_get_setting_by_id, (setting_key, twitch_username_or_id)) + value = await result.fetchone() return await self.handle_none_type_setting(value, setting_key)