From ac238b360a2e3b62346bbb4db99fa0dd6e3237b4 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 2 Oct 2022 02:34:27 +0200 Subject: [PATCH] Added feature-flags --- src/bot/config/appsettings.development.json | 8 +++ .../config/appsettings.edrafts-pc-ubuntu.json | 8 +++ src/bot/config/appsettings.production.json | 8 +++ src/bot/config/appsettings.staging.json | 8 +++ src/bot/startup.py | 9 ++- src/bot/startup_discord_extension.py | 53 +++++++++------ .../configuration/feature_flags_settings.py | 65 +++++++++++++++++++ 7 files changed, 138 insertions(+), 21 deletions(-) create mode 100644 src/bot_core/configuration/feature_flags_settings.py diff --git a/src/bot/config/appsettings.development.json b/src/bot/config/appsettings.development.json index 53ed5d70..d75fdfea 100644 --- a/src/bot/config/appsettings.development.json +++ b/src/bot/config/appsettings.development.json @@ -17,6 +17,14 @@ "de" ] }, + "FeatureFlag": { + "AdminModule": true, + "BaseModule": true, + "BootLogModule": true, + "DatabaseModule": true, + "ModeratorModule": true, + "PermissionModule": true + }, "DiscordBot": { "Token": "OTk4MTU5NjczODkzMDYwNzM4.GN3QyA.yvWO6L7Eu36gXQ7ARDs0Jg2J1VqIDnHLou5lT4", "Prefix": "!kd " diff --git a/src/bot/config/appsettings.edrafts-pc-ubuntu.json b/src/bot/config/appsettings.edrafts-pc-ubuntu.json index 8c26c3ea..6523b2d9 100644 --- a/src/bot/config/appsettings.edrafts-pc-ubuntu.json +++ b/src/bot/config/appsettings.edrafts-pc-ubuntu.json @@ -19,6 +19,14 @@ "Token": "OTk4MTYwNDI3Njg5MTgxMjM3.GI7h67.BqD6Lu1Tz0MuG8iktYrcLnHi1pNozyMiWFGTKI", "Prefix": "!ke " }, + "FeatureFlag": { + "AdminModule": true, + "BaseModule": true, + "BootLogModule": true, + "DatabaseModule": true, + "ModeratorModule": true, + "PermissionModule": true + }, "Bot": { "910199451145076828": { "MessageDeleteTimer": 2 diff --git a/src/bot/config/appsettings.production.json b/src/bot/config/appsettings.production.json index 91872272..1f2dd507 100644 --- a/src/bot/config/appsettings.production.json +++ b/src/bot/config/appsettings.production.json @@ -28,6 +28,14 @@ "Buffered": "true", "AuthPlugin": "mysql_native_password" }, + "FeatureFlag": { + "AdminModule": true, + "BaseModule": true, + "BootLogModule": true, + "DatabaseModule": true, + "ModeratorModule": true, + "PermissionModule": true + }, "Bot": { "650366049023295514": { "MessageDeleteTimer": 2 diff --git a/src/bot/config/appsettings.staging.json b/src/bot/config/appsettings.staging.json index b69da3dd..3ddd1c3f 100644 --- a/src/bot/config/appsettings.staging.json +++ b/src/bot/config/appsettings.staging.json @@ -17,6 +17,14 @@ "de" ] }, + "FeatureFlag": { + "AdminModule": true, + "BaseModule": true, + "BootLogModule": true, + "DatabaseModule": true, + "ModeratorModule": true, + "PermissionModule": true + }, "Bot": { "910199451145076828": { "MessageDeleteTimer": 4 diff --git a/src/bot/startup.py b/src/bot/startup.py index db5fd508..4f936340 100644 --- a/src/bot/startup.py +++ b/src/bot/startup.py @@ -10,6 +10,7 @@ from cpl_core.environment import ApplicationEnvironment from bot_core.abc.client_utils_service_abc import ClientUtilsServiceABC from bot_core.abc.message_service_abc import MessageServiceABC +from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from bot_core.pipes.date_time_offset_pipe import DateTimeOffsetPipe from bot_core.service.client_utils_service import ClientUtilsService from bot_core.service.message_service import MessageService @@ -39,6 +40,7 @@ class Startup(StartupABC): self._start_time = datetime.now() self._config: Optional[ConfigurationABC] = None + self._feature_flags: Optional[FeatureFlagsSettings] = None def configure_configuration(self, configuration: ConfigurationABC, environment: ApplicationEnvironment) -> ConfigurationABC: environment.set_working_directory(os.path.dirname(os.path.realpath(__file__))) @@ -52,6 +54,7 @@ class Startup(StartupABC): configuration.add_configuration('Startup_StartTime', str(self._start_time)) self._config = configuration + self._feature_flags = configuration.get_configuration(FeatureFlagsSettings) return configuration def configure_services(self, services: ServiceCollectionABC, environment: ApplicationEnvironment) -> ServiceProviderABC: @@ -61,7 +64,8 @@ class Startup(StartupABC): services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings)) # general services - services.add_transient(BaseHelperABC, BaseHelperService) + if self._feature_flags.base_module: + services.add_transient(BaseHelperABC, BaseHelperService) services.add_transient(MessageServiceABC, MessageService) services.add_transient(ClientUtilsServiceABC, ClientUtilsService) @@ -69,7 +73,8 @@ class Startup(StartupABC): services.add_transient(DateTimeOffsetPipe) # module services - services.add_singleton(PermissionServiceABC, PermissionService) + if self._feature_flags.permission_module: + services.add_singleton(PermissionServiceABC, PermissionService) # data services services.add_transient(ServerRepositoryABC, ServerRepositoryService) diff --git a/src/bot/startup_discord_extension.py b/src/bot/startup_discord_extension.py index 4d20e684..8e7b93ec 100644 --- a/src/bot/startup_discord_extension.py +++ b/src/bot/startup_discord_extension.py @@ -1,3 +1,5 @@ +from typing import Optional + from cpl_core.application import StartupExtensionABC from cpl_core.configuration import ConfigurationABC from cpl_core.dependency_injection import ServiceCollectionABC @@ -5,6 +7,7 @@ from cpl_core.environment import ApplicationEnvironmentABC from cpl_discord import get_discord_collection from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum +from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings from modules.admin.command.restart_command import RestartCommand from modules.admin.command.shutdown_command import ShutdownCommand from modules.base.command.afk_command import AFKCommand @@ -27,40 +30,52 @@ from modules.permission.events.permission_on_ready_event import PermissionOnRead class StartupDiscordExtension(StartupExtensionABC): def __init__(self): - pass + self._feature_flags: Optional[FeatureFlagsSettings] = None def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): - pass + self._feature_flags = config.get_configuration(FeatureFlagsSettings) def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): services.add_discord() dc = get_discord_collection(services) """ commands """ # admin - dc.add_command(RestartCommand) - dc.add_command(ShutdownCommand) + if self._feature_flags.admin_module: + dc.add_command(RestartCommand) + dc.add_command(ShutdownCommand) # moderator - dc.add_command(PurgeCommand) + if self._feature_flags.moderator_module: + dc.add_command(PurgeCommand) # simple - dc.add_command(AFKCommand) - dc.add_command(HelpCommand) - dc.add_command(InfoCommand) - dc.add_command(PingCommand) - dc.add_command(UserInfoCommand) + if self._feature_flags.base_module: + dc.add_command(AFKCommand) + dc.add_command(HelpCommand) + dc.add_command(InfoCommand) + dc.add_command(PingCommand) + dc.add_command(UserInfoCommand) """ events """ # on_command_error - dc.add_event(DiscordEventTypesEnum.on_command_error.value, BaseOnCommandErrorEvent) + if self._feature_flags.base_module: + dc.add_event(DiscordEventTypesEnum.on_command_error.value, BaseOnCommandErrorEvent) # on_member_join - dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberJoinEvent) + if self._feature_flags.base_module: + dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberJoinEvent) # on_member_remove - dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberRemoveEvent) + if self._feature_flags.base_module: + dc.add_event(DiscordEventTypesEnum.on_member_join.value, BaseOnMemberRemoveEvent) # on_member_update - dc.add_event(DiscordEventTypesEnum.on_member_update.value, PermissionOnMemberUpdateEvent) + if self._feature_flags.permission_module: + dc.add_event(DiscordEventTypesEnum.on_member_update.value, PermissionOnMemberUpdateEvent) # on_message - dc.add_event(DiscordEventTypesEnum.on_message.value, BaseOnMessageEvent) + if self._feature_flags.base_module: + dc.add_event(DiscordEventTypesEnum.on_message.value, BaseOnMessageEvent) # on_voice_state_update - dc.add_event(DiscordEventTypesEnum.on_voice_state_update.value, BaseOnVoiceStateUpdateEvent) + if self._feature_flags.base_module: + dc.add_event(DiscordEventTypesEnum.on_voice_state_update.value, BaseOnVoiceStateUpdateEvent) # on_ready - dc.add_event(DiscordEventTypesEnum.on_ready.value, DatabaseOnReadyEvent) - dc.add_event(DiscordEventTypesEnum.on_ready.value, PermissionOnReadyEvent) - dc.add_event(DiscordEventTypesEnum.on_ready.value, BootLogOnReadyEvent) # has to be last + if self._feature_flags.database_module: + dc.add_event(DiscordEventTypesEnum.on_ready.value, DatabaseOnReadyEvent) + if self._feature_flags.permission_module: + dc.add_event(DiscordEventTypesEnum.on_ready.value, PermissionOnReadyEvent) + if self._feature_flags.boot_log_module: + dc.add_event(DiscordEventTypesEnum.on_ready.value, BootLogOnReadyEvent) # has to be last diff --git a/src/bot_core/configuration/feature_flags_settings.py b/src/bot_core/configuration/feature_flags_settings.py new file mode 100644 index 00000000..8d280744 --- /dev/null +++ b/src/bot_core/configuration/feature_flags_settings.py @@ -0,0 +1,65 @@ +import traceback +from typing import Optional + +from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC +from cpl_core.console import Console + + +class FeatureFlagsSettings(ConfigurationModelABC): + + def __init__(self): + ConfigurationModelABC.__init__(self) + + self._admin_module = False # 02.10.2022 #48 + self._base_module = True # 02.10.2022 #48 + self._boot_log_module = True # 02.10.2022 #48 + self._database_module = True # 02.10.2022 #48 + self._moderator_module = False # 02.10.2022 #48 + self._permission_module = True # 02.10.2022 #48 + + @property + def admin_module(self) -> bool: + return self._admin_module + + @property + def base_module(self) -> bool: + return self._base_module + + @property + def boot_log_module(self) -> bool: + return self._boot_log_module + + @property + def database_module(self) -> bool: + return self._database_module + + @property + def moderator_module(self) -> bool: + return self._moderator_module + + @property + def permission_module(self) -> bool: + return self._permission_module + + def from_dict(self, settings: dict): + try: + if 'AdminModule' in settings: + self._admin_module = settings['AdminModule'] + + if 'BaseModule' in settings: + self._base_module = settings['BaseModule'] + + if 'BootLogModule' in settings: + self._boot_log_module = settings['BootLogModule'] + + if 'DatabaseModule' in settings: + self._database_module = settings['DatabaseModule'] + + if 'ModeratorModule' in settings: + self._moderator_module = settings['ModeratorModule'] + + if 'PermissionModule' in settings: + self._permission_module = settings['PermissionModule'] + except Exception as e: + Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') + Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}')