From 234a9a382a7585d4ead9a3544364066c073ca8a9 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Jan 2022 11:47:59 +0100 Subject: [PATCH] Improved module, event and settings loading --- src/gismo/application.py | 13 +++- src/gismo/config | 2 +- src/gismo/gismo.json | 4 +- src/gismo_core/abc/module_service_abc.py | 3 + src/gismo_core/service/bot_service.py | 17 ++---- src/gismo_core/service/module_service.py | 61 ++++++++++--------- .../abc/user_joined_voice_channel_abc.py | 3 + .../user_joined_voice_channel_service.py | 20 +++++- src/modules/database/database.py | 25 ++++---- src/modules/database/database_extension.py | 4 ++ 10 files changed, 91 insertions(+), 61 deletions(-) diff --git a/src/gismo/application.py b/src/gismo/application.py index 849c55e..1562d7b 100644 --- a/src/gismo/application.py +++ b/src/gismo/application.py @@ -5,6 +5,9 @@ from cpl_core.dependency_injection import ServiceProviderABC from cpl_core.logging import LoggerABC from gismo_core.abc.bot_service_abc import BotServiceABC +from gismo_core.abc.module_service_abc import ModuleServiceABC +from gismo_core.configuration.bot_settings import BotSettings +from gismo_core.configuration.server_settings import ServerSettings from gismo_core.service.bot_service import BotService from gismo_data.service.migration_service import MigrationService @@ -16,14 +19,18 @@ class Gismo(ApplicationABC): self._bot: BotService = services.get_service(BotServiceABC) self._logger: LoggerABC = services.get_service(LoggerABC) - self._migrations: MigrationService = services.get_service(MigrationService) + self._bot_settings: BotSettings = config.get_configuration(BotSettings) async def configure(self): - pass + self._logger.debug(__name__, 'Try to load discord server configs') + for server in self._bot_settings.servers: + server: ServerSettings = server + self._logger.trace(__name__, f'Try to load config for server: {server.id}') + self._configuration.add_configuration(f'DSERVER_{server.id}', server) + self._logger.trace(__name__, f'Loaded config for server: {server.id}') async def main(self): try: - self._migrations.migrate() self._logger.trace(__name__, f'Try to start {BotService}') await self._bot.start_async() except Exception as e: diff --git a/src/gismo/config b/src/gismo/config index 3d4e93d..ed5887b 160000 --- a/src/gismo/config +++ b/src/gismo/config @@ -1 +1 @@ -Subproject commit 3d4e93d4d658e1c6c571756f99a3297efb8a7d64 +Subproject commit ed5887b6d068d33e686347081630b18d896ece4c diff --git a/src/gismo/gismo.json b/src/gismo/gismo.json index a133aca..98a00c2 100644 --- a/src/gismo/gismo.json +++ b/src/gismo/gismo.json @@ -17,8 +17,8 @@ "LicenseDescription": "MIT, see LICENSE for more details.", "Dependencies": [ "sh_cpl-core>=2021.11.0.post3", - "sh_cpl-query>=2021.11.0.post2", - "discord.py==1.7.3" + "discord.py==1.7.3", + "sh_cpl-query==2021.11.0.post3" ], "PythonVersion": ">=3.9.2", "PythonPath": { diff --git a/src/gismo_core/abc/module_service_abc.py b/src/gismo_core/abc/module_service_abc.py index 407868a..6c2fa9a 100644 --- a/src/gismo_core/abc/module_service_abc.py +++ b/src/gismo_core/abc/module_service_abc.py @@ -9,6 +9,9 @@ class ModuleServiceABC(ABC): @abstractmethod def __init__(self): pass + + @abstractmethod + def load_modules(self): pass @abstractmethod async def on_connect(self): pass diff --git a/src/gismo_core/service/bot_service.py b/src/gismo_core/service/bot_service.py index b7c124a..8f4ba1c 100644 --- a/src/gismo_core/service/bot_service.py +++ b/src/gismo_core/service/bot_service.py @@ -25,7 +25,6 @@ class BotService(BotServiceABC, commands.Bot): logging_st: LoggingSettings, ): # services - self._config = config self._logger = logger self._modules = modules self._env = env @@ -33,7 +32,6 @@ class BotService(BotServiceABC, commands.Bot): # settings self._discord_settings = discord_settings - self._bot_settings: BotSettings = bot_settings # setup super commands.Bot.__init__(self, command_prefix=bot_settings.prefix, help_command=None, intents=discord.Intents().all()) @@ -41,8 +39,8 @@ class BotService(BotServiceABC, commands.Bot): async def start_async(self): self._logger.trace(__name__, 'Try to connect to discord') - self.add_cog(self._modules) - + self._modules.load_modules() + await self.start(self._discord_settings.token) # continue at on_ready @@ -56,16 +54,11 @@ class BotService(BotServiceABC, commands.Bot): async def on_ready(self): self._logger.info(__name__, 'Connected to discord') - - self._logger.debug(__name__, 'Try to load discord server configs') - for server in self._bot_settings.servers: - server: ServerSettings = server - self._logger.trace(__name__, f'Try to load config for server: {server.id}') - self._config.add_configuration(f'DSERVER_{server.id}', server) - self._logger.trace(__name__, f'Loaded config for server: {server.id}') self._logger.header(f'{self.user.name}:') if self._logging_st.console.value >= LoggingLevelEnum.INFO.value: Console.banner(self._env.application_name if self._env.application_name != '' else 'Gismo') - + + self.add_cog(self._modules) + await self._modules.on_ready() diff --git a/src/gismo_core/service/module_service.py b/src/gismo_core/service/module_service.py index 20049ba..0a4397c 100644 --- a/src/gismo_core/service/module_service.py +++ b/src/gismo_core/service/module_service.py @@ -1,7 +1,7 @@ from abc import ABC, ABCMeta from datetime import datetime import json -from typing import Optional, Sequence, Union +from typing import Optional, Sequence, Union, Type import discord from cpl_core.configuration import ConfigurationModelABC, ConfigurationABC @@ -69,37 +69,14 @@ class ModuleService(ModuleServiceABC, commands.Cog, metaclass=CommandsMeta): self._config = config self._services = services self._env = env - self._modules: List[ModuleABC] = List() - self._modules.extend(ModuleABC.__subclasses__()) - - def _get_modules(self, t: type) -> OrderedIterableABC: - module_types = self._modules.where(lambda m: issubclass(m, t)) - modules = List(t) - for module_type in module_types: - module: ModuleABC = self._services.get_service(module_type) - if module is None: - self._logger.warn(__name__, f'Module {module_type} not found in services!') - break - - if len(module.settings_types) > 0: - for settings_type in module.settings_types: - settings_name = settings_type.__name__.split('Settings')[0] - - with open(f'config/{String.convert_to_snake_case(settings_name).lower()}.json', encoding='utf-8') as cfg: - json_cfg = json.load(cfg) - for index in json_cfg: - settings: ConfigurationModelABC = settings_type() - settings.from_dict(json_cfg[index]) - self._config.add_configuration(f'{type(module).__name__}_{index}', settings) - self._logger.debug(__name__, f'Added config: {type(module).__name__}_{index}') - - modules.append(module) - - return modules.order_by(lambda m: m.get_priority(t)) + self._modules_types: List[Type[ModuleABC]] = List() + self._modules_types.extend(ModuleABC.__subclasses__()) + self._modules: List[ModuleABC] = List(ModuleABC) async def _handle_event(self, event: type, *args): self._logger.debug(__name__, f'Start {event} modules') - modules = self._get_modules(event) + # modules = self._get_modules(event) + modules = self._modules.where(lambda m: isinstance(m, event)).order_by(lambda m: m.get_priority(event)) if modules.count() < 1: self._logger.debug(__name__, f'Stopped {event} modules') @@ -118,6 +95,32 @@ class ModuleService(ModuleServiceABC, commands.Cog, metaclass=CommandsMeta): self._logger.error(__name__, f'Start {event} modules failed', e) self._logger.debug(__name__, f'Stopped {event} modules') + + def load_modules(self): + self._logger.debug(__name__, f'Start loading modules') + for module_type in self._modules_types: + module: ModuleABC = self._services.get_service(module_type) + if module is None: + self._logger.warn(__name__, f'Module {module_type} not found in services!') + break + + loaded_settings: list[str] = [] + for settings_type in module.settings_types: + settings_name = settings_type.__name__.split('Settings')[0] + if settings_name in loaded_settings: + continue + + with open(f'config/{String.convert_to_snake_case(settings_name).lower()}.json', encoding='utf-8') as cfg: + json_cfg = json.load(cfg) + for index in json_cfg: + settings: ConfigurationModelABC = settings_type() + settings.from_dict(json_cfg[index]) + self._config.add_configuration(f'{type(module).__name__}_{index}', settings) + self._logger.debug(__name__, f'Added config: {type(module).__name__}_{index}') + + loaded_settings.append(settings_name) + + self._modules.append(module) @commands.Cog.listener() async def on_connect(self): diff --git a/src/gismo_data/abc/user_joined_voice_channel_abc.py b/src/gismo_data/abc/user_joined_voice_channel_abc.py index 57ad410..04ecf7d 100644 --- a/src/gismo_data/abc/user_joined_voice_channel_abc.py +++ b/src/gismo_data/abc/user_joined_voice_channel_abc.py @@ -23,6 +23,9 @@ class UserJoinedVoiceChannelRepositoryABC(ABC): @abstractmethod def find_active_user_joined_voice_channel_by_user_id(self, user_id: int) -> Optional[UserJoinedVoiceChannel]: pass + + @abstractmethod + def find_active_user_joined_voice_channels_by_user_id(self, user_id: int) -> List[Optional[UserJoinedVoiceChannel]]: pass @abstractmethod def add_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel): pass diff --git a/src/gismo_data/service/user_joined_voice_channel_service.py b/src/gismo_data/service/user_joined_voice_channel_service.py index 35f999d..05e7e1f 100644 --- a/src/gismo_data/service/user_joined_voice_channel_service.py +++ b/src/gismo_data/service/user_joined_voice_channel_service.py @@ -2,9 +2,8 @@ from typing import Optional from cpl_core.database.context import DatabaseContextABC from cpl_core.logging import LoggerABC -from cpl_query.extension import List +from cpl_query.extension import List, IterableABC from gismo_data.abc.user_repository_abc import UserRepositoryABC -from gismo_data.model.user import User from gismo_data.model.user_joined_voice_channel import UserJoinedVoiceChannel from gismo_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC @@ -93,6 +92,23 @@ class UserJoinedVoiceChannelRepositoryService(UserJoinedVoiceChannelRepositoryAB result[5], id=result[0] ) + + def find_active_user_joined_voice_channels_by_user_id(self, user_id: int) -> List[Optional[UserJoinedVoiceChannel]]: + self._logger.trace(__name__, f'Send SQL command: {UserJoinedVoiceChannel.get_select_by_user_id_string(user_id)}') + result = List(UserJoinedVoiceChannel) + db_results = self._context.select(UserJoinedVoiceChannel.get_select_active_by_user_id_string(user_id)) + + for db_result in db_results: + result.append(UserJoinedVoiceChannel( + self._users.get_user_by_id(db_result[1]), + db_result[2], + db_result[3], + db_result[4], + db_result[5], + id=db_result[0] + )) + + return result def add_user_joined_voice_channel(self, user_joined_voice_channel: UserJoinedVoiceChannel): self._logger.trace(__name__, f'Send SQL command: {user_joined_voice_channel.insert_string}') diff --git a/src/modules/database/database.py b/src/modules/database/database.py index b3427dd..9cb77dc 100644 --- a/src/modules/database/database.py +++ b/src/modules/database/database.py @@ -1,5 +1,5 @@ from ctypes import Union -from datetime import datetime +from datetime import datetime, timedelta import discord from cpl_core.configuration import ConfigurationABC @@ -268,20 +268,21 @@ class Database(ModuleABC, OnReadyABC): if user is None: self._logger.fatal(__name__, f'User not found in database: {member.id}') - join = self._user_joins_vc.find_active_user_joined_voice_channel_by_user_id(user.user_id) - if join is None: + joins = self._user_joins_vc.find_active_user_joined_voice_channels_by_user_id(user.user_id) + if joins is None or len(joins) == 0: continue - self._logger.warn(__name__, f'Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}') - join.leaved_on = datetime.now() - settings: BaseSettings = self._config.get_configuration(f'base_{guild.id}') - - if ((join.leaved_on - join.joined_on).total_seconds()/60/60) > settings.max_voice_state_hours: - join.leaved_on = join.joined_on + datetime.timedelta(hours=settings.max_voice_state_hours) + for join in joins: + self._logger.warn(__name__, f'Active UserJoinedVoiceChannel found in database: {guild.id}:{member.id}@{join.joined_on}') + join.leaved_on = datetime.now() + settings: BaseSettings = self._config.get_configuration(f'Base_{guild.id}') - self._user_joins_vc.update_user_joined_voice_channel(join) - # todo: maybe add XP - self._db_context.save_changes() + if ((join.leaved_on - join.joined_on).total_seconds()/60/60) > settings.max_voice_state_hours: + join.leaved_on = join.joined_on + timedelta(hours=settings.max_voice_state_hours) + + self._user_joins_vc.update_user_joined_voice_channel(join) + # todo: maybe add XP + self._db_context.save_changes() for member in guild.members: if member.bot: diff --git a/src/modules/database/database_extension.py b/src/modules/database/database_extension.py index 613c9cb..d7a7d4c 100644 --- a/src/modules/database/database_extension.py +++ b/src/modules/database/database_extension.py @@ -5,6 +5,8 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.dependency_injection import ServiceProviderABC from cpl_core.logging import LoggerABC +from gismo_data.service.migration_service import MigrationService + class DatabaseExtension(ApplicationExtensionABC): @@ -15,3 +17,5 @@ class DatabaseExtension(ApplicationExtensionABC): logger: LoggerABC = services.get_service(LoggerABC) logger.debug(__name__, 'Database extension started') config.add_configuration('Database_StartTime', str(datetime.now())) + migrations = services.get_service(MigrationService) + migrations.migrate()