From 940fb77c3d15c688373084b060ef9f0bd5f98371 Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 14 Dec 2024 14:22:33 +0000 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8=20Add=20cache=20configuration=20p?= =?UTF-8?q?arameters=20to=20Bot=20class?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/custom/__init__.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/custom/__init__.py b/src/custom/__init__.py index dbf8023..1e88933 100644 --- a/src/custom/__init__.py +++ b/src/custom/__init__.py @@ -51,9 +51,29 @@ def load_translations(self) -> None: class Bot(bridge.Bot): - def __init__(self, *args: Any, **options: Any) -> None: + def __init__( + self, + *args: Any, + cache_type: str = "memory", + cache_config: dict[str, Any] | None = None, + **options: Any + ) -> None: self.translations: list[ExtensionTranslation] = options.pop("translations", []) - self.cache: aiocache.SimpleMemoryCache | aiocache.RedisCache = aiocache.SimpleMemoryCache() + + # Initialize cache based on type and config + if cache_type == "redis" and cache_config: + self.cache = aiocache.RedisCache( + endpoint=cache_config.get("host", "localhost"), + port=cache_config.get("port", 6379), + db=cache_config.get("db", 0), + password=cache_config.get("password"), + username=cache_config.get("username"), + ssl=cache_config.get("ssl", False), + namespace="botkit" + ) + else: + self.cache = aiocache.SimpleMemoryCache(namespace="botkit") + super().__init__(*args, **options) @self.listen(name="on_ready", once=True) From f5a5dbd637957589a33ba45edef37c88059d1cab Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 14 Dec 2024 14:27:51 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=8E=A8=20Improve=20cache=20initializa?= =?UTF-8?q?tion=20with=20warning=20for=20missing=20Redis=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/custom/__init__.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/custom/__init__.py b/src/custom/__init__.py index 1e88933..e09ba68 100644 --- a/src/custom/__init__.py +++ b/src/custom/__init__.py @@ -61,16 +61,20 @@ def __init__( self.translations: list[ExtensionTranslation] = options.pop("translations", []) # Initialize cache based on type and config - if cache_type == "redis" and cache_config: - self.cache = aiocache.RedisCache( - endpoint=cache_config.get("host", "localhost"), - port=cache_config.get("port", 6379), - db=cache_config.get("db", 0), - password=cache_config.get("password"), - username=cache_config.get("username"), - ssl=cache_config.get("ssl", False), - namespace="botkit" - ) + if cache_type == "redis": + if cache_config: + self.cache = aiocache.RedisCache( + endpoint=cache_config.get("host", "localhost"), + port=cache_config.get("port", 6379), + db=cache_config.get("db", 0), + password=cache_config.get("password"), + username=cache_config.get("username"), + ssl=cache_config.get("ssl", False), + namespace="botkit" + ) + else: + logger.warning("Redis cache type specified but no configuration provided. Falling back to memory cache.") + self.cache = aiocache.SimpleMemoryCache(namespace="botkit") else: self.cache = aiocache.SimpleMemoryCache(namespace="botkit") From c46808613d56203d8e2dca16e1f590f0c1663627 Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 14 Dec 2024 14:29:18 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=E2=9C=A8=20Pass=20cache=20configuration=20?= =?UTF-8?q?to=20Bot=20initialization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/start.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/start.py b/src/start.py index 6c69e2c..68214bf 100644 --- a/src/start.py +++ b/src/start.py @@ -133,10 +133,14 @@ async def setup_and_start_bot( intents = discord.Intents.default() if config.get("prefix"): intents.message_content = True + # Get cache configuration + cache_config = config.get("cache", {}) bot = custom.Bot( intents=intents, help_command=None, command_prefix=(config.get("prefix", {}).get("prefix") or commands.when_mentioned), + cache_type=cache_config.get("type", "memory"), + cache_config=cache_config.get("redis"), ) for function, its_config in bot_functions: setup_func(function, bot=bot, config=its_config) From 14d7d3d7fc4c0720b6a6558fb253f16747bd009a Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 14 Dec 2024 14:33:14 +0000 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=93=9D=20Add=20cache=20configuration?= =?UTF-8?q?=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config.example.yaml | 11 +++++++++-- readme.md | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/config.example.yaml b/config.example.yaml index 115e952..7a6d611 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -41,5 +41,12 @@ logging: use: bot: true # Whether to run the bot backend: false # Whether to run the backend - - +cache: + type: "memory" # Cache type. Possible values: "memory" or "redis" + redis: # Redis configuration (only used if type is "redis") + host: "localhost" # Redis server host + port: 6379 # Redis server port + db: 0 # Redis database number + password: null # Redis password (optional) + username: null # Redis username (optional) + ssl: false # Whether to use SSL for Redis connection diff --git a/readme.md b/readme.md index 2952ec4..e9e788e 100644 --- a/readme.md +++ b/readme.md @@ -114,8 +114,33 @@ BOTKIT__extensions__listings__enabled=false BOTKIT__extensions__listings__topgg_token=your_top.gg_token BOTKIT__extensions__ping__enabled=true BOTKIT__logging__level=INFO +BOTKIT__cache__type=redis +BOTKIT__cache__redis__host=redis.example.com +BOTKIT__cache__redis__port=6379 ``` +### Cache Configuration + +Botkit supports two types of caching: +- **Memory Cache**: Simple in-memory cache (default) +- **Redis Cache**: Distributed cache using Redis + +To configure the cache, use the `cache` section in your config: + +```yaml +cache: + type: "redis" # Use "memory" for in-memory cache + redis: # Redis configuration (only needed when type is "redis") + host: "localhost" + port: 6379 + db: 0 + password: "optional" # Optional Redis password + username: "optional" # Optional Redis username + ssl: false # Whether to use SSL +``` + +If Redis cache is requested but no configuration is provided, Botkit will fall back to memory cache with a warning. + ## Creating Extensions Extensions are in truth just python located in the `src/extensions` directory. When From 422e5844bb6de61a6e1cc9e5dcd782a2004d59cc Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 14 Dec 2024 14:39:54 +0000 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=8E=A8=20Format=20code=20with=20ruff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/custom/__init__.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/custom/__init__.py b/src/custom/__init__.py index e09ba68..b1b3a7f 100644 --- a/src/custom/__init__.py +++ b/src/custom/__init__.py @@ -52,14 +52,10 @@ def load_translations(self) -> None: class Bot(bridge.Bot): def __init__( - self, - *args: Any, - cache_type: str = "memory", - cache_config: dict[str, Any] | None = None, - **options: Any + self, *args: Any, cache_type: str = "memory", cache_config: dict[str, Any] | None = None, **options: Any ) -> None: self.translations: list[ExtensionTranslation] = options.pop("translations", []) - + # Initialize cache based on type and config if cache_type == "redis": if cache_config: @@ -70,14 +66,16 @@ def __init__( password=cache_config.get("password"), username=cache_config.get("username"), ssl=cache_config.get("ssl", False), - namespace="botkit" + namespace="botkit", ) else: - logger.warning("Redis cache type specified but no configuration provided. Falling back to memory cache.") + logger.warning( + "Redis cache type specified but no configuration provided. Falling back to memory cache." + ) self.cache = aiocache.SimpleMemoryCache(namespace="botkit") else: self.cache = aiocache.SimpleMemoryCache(namespace="botkit") - + super().__init__(*args, **options) @self.listen(name="on_ready", once=True) From 353fd22f2b83cf0ed1792e992b322542e7844f00 Mon Sep 17 00:00:00 2001 From: Paillat Date: Sun, 22 Dec 2024 22:08:12 +0100 Subject: [PATCH 6/6] :sparkles: Improve caching --- compose.yaml | 9 +++++++++ config.example.yaml | 17 ++++++++--------- readme.md | 24 +++++++++++++----------- src/custom/__init__.py | 10 ++++++---- src/utils/cooldown.py | 2 +- 5 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 compose.yaml diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..0977c21 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,9 @@ +# Copyright (c) NiceBots +# SPDX-License-Identifier: MIT + +services: + redis: + image: redis:alpine + ports: + - "6379:6379" + command: --loglevel debug \ No newline at end of file diff --git a/config.example.yaml b/config.example.yaml index 7a6d611..97db981 100644 --- a/config.example.yaml +++ b/config.example.yaml @@ -36,17 +36,16 @@ extensions: every: 300 # 300 seconds = 5 minutes bot: token: "bot token here" # Your bot token + cache: + type: "memory" # Cache type. Possible values: "memory" or "redis" + redis: # Redis configuration (only used if type is "redis") + host: "localhost" # Redis server host + port: 6379 # Redis server port + db: 0 # Redis database number + password: null # Redis password (optional) + ssl: false # Whether to use SSL for Redis connection logging: level: "INFO" # The logging level. Possible values: DEBUG, INFO, WARNING, ERROR, CRITICAL use: bot: true # Whether to run the bot backend: false # Whether to run the backend -cache: - type: "memory" # Cache type. Possible values: "memory" or "redis" - redis: # Redis configuration (only used if type is "redis") - host: "localhost" # Redis server host - port: 6379 # Redis server port - db: 0 # Redis database number - password: null # Redis password (optional) - username: null # Redis username (optional) - ssl: false # Whether to use SSL for Redis connection diff --git a/readme.md b/readme.md index e9e788e..2512ee7 100644 --- a/readme.md +++ b/readme.md @@ -122,24 +122,26 @@ BOTKIT__cache__redis__port=6379 ### Cache Configuration Botkit supports two types of caching: + - **Memory Cache**: Simple in-memory cache (default) - **Redis Cache**: Distributed cache using Redis -To configure the cache, use the `cache` section in your config: +To configure the cache, use the `cache` section under the `bot` in your config: ```yaml -cache: - type: "redis" # Use "memory" for in-memory cache - redis: # Redis configuration (only needed when type is "redis") - host: "localhost" - port: 6379 - db: 0 - password: "optional" # Optional Redis password - username: "optional" # Optional Redis username - ssl: false # Whether to use SSL +bot: + cache: + type: "redis" # Use "memory" for in-memory cache + redis: # Redis configuration (only needed when type is "redis") + host: "localhost" + port: 6379 + db: 0 + password: "optional" # Optional Redis password + ssl: false # Whether to use SSL ``` -If Redis cache is requested but no configuration is provided, Botkit will fall back to memory cache with a warning. +If Redis cache is requested but no configuration is provided, Botkit will fall back to +memory cache with a warning. ## Creating Extensions diff --git a/src/custom/__init__.py b/src/custom/__init__.py index b1b3a7f..ca750d4 100644 --- a/src/custom/__init__.py +++ b/src/custom/__init__.py @@ -56,15 +56,16 @@ def __init__( ) -> None: self.translations: list[ExtensionTranslation] = options.pop("translations", []) + self.botkit_cache: aiocache.BaseCache # Initialize cache based on type and config if cache_type == "redis": if cache_config: - self.cache = aiocache.RedisCache( + logger.info("Using Redis cache") + self.botkit_cache = aiocache.RedisCache( endpoint=cache_config.get("host", "localhost"), port=cache_config.get("port", 6379), db=cache_config.get("db", 0), password=cache_config.get("password"), - username=cache_config.get("username"), ssl=cache_config.get("ssl", False), namespace="botkit", ) @@ -72,9 +73,10 @@ def __init__( logger.warning( "Redis cache type specified but no configuration provided. Falling back to memory cache." ) - self.cache = aiocache.SimpleMemoryCache(namespace="botkit") + self.botkit_cache = aiocache.SimpleMemoryCache(namespace="botkit") else: - self.cache = aiocache.SimpleMemoryCache(namespace="botkit") + logger.info("Using memory cache") + self.botkit_cache = aiocache.SimpleMemoryCache(namespace="botkit") super().__init__(*args, **options) diff --git a/src/utils/cooldown.py b/src/utils/cooldown.py index 474c4dc..93f841d 100644 --- a/src/utils/cooldown.py +++ b/src/utils/cooldown.py @@ -92,7 +92,7 @@ def cooldown[C: commands.Cog, **P]( # noqa: PLR0913 def inner(func: CogCommandFunction[C, P]) -> CogCommandFunction[C, P]: @wraps(func) async def wrapper(self: C, ctx: custom.ApplicationContext, *args: P.args, **kwargs: P.kwargs) -> None: - cache = ctx.bot.cache + cache = ctx.bot.botkit_cache key_value: str = await parse_reactive_setting(key, ctx.bot, ctx) limit_value: int = await parse_reactive_setting(limit, ctx.bot, ctx) per_value: int = await parse_reactive_setting(per, ctx.bot, ctx)