diff --git a/base-config.yaml b/base-config.yaml index 7f77244..42c30ed 100644 --- a/base-config.yaml +++ b/base-config.yaml @@ -14,7 +14,6 @@ rooms_per_message: 50 # Voorkomt dat een enorme (gefedereerde) space-boom leidt tot duizenden berichten. max_rooms: 300 -# Hoe lang (minuten) de opgehaalde lijst wordt gecached in de plugin-database. -# Binnen deze periode gebruikt !rooms de cache i.p.v. de hele boom opnieuw op te -# halen (minder traffic naar de homeserver en federatie). 0 = caching uit. -cache_ttl_minutes: 15 \ No newline at end of file +# Hoe vaak (minuten) de bot de ruimte-hierarchy opnieuw indexeert op de +# achtergrond. !rooms toont altijd het laatste geindexeerde resultaat. +refresh_interval_minutes: 15 \ No newline at end of file diff --git a/maubot.yaml b/maubot.yaml index 15a4b0c..4c0c7d0 100644 --- a/maubot.yaml +++ b/maubot.yaml @@ -1,6 +1,6 @@ maubot: 0.1.0 id: nl.roomsoverview -version: 1.0.7 +version: 1.0.8 license: MIT modules: - roomsoverview diff --git a/roomsoverview.mbp b/roomsoverview.mbp index 96b3341..9900091 100644 Binary files a/roomsoverview.mbp and b/roomsoverview.mbp differ diff --git a/roomsoverview.py b/roomsoverview.py index 3dad5df..8d7c217 100644 --- a/roomsoverview.py +++ b/roomsoverview.py @@ -1,6 +1,7 @@ import asyncio import json import time +from functools import partial from typing import Any, Dict, List, Optional, Tuple from urllib.parse import quote @@ -58,12 +59,36 @@ class Config(BaseProxyConfig): helper.copy("max_depth") helper.copy("rooms_per_message") helper.copy("max_rooms") - helper.copy("cache_ttl_minutes") + helper.copy("refresh_interval_minutes") class RoomsOverviewPlugin(Plugin): async def start(self) -> None: self.config.load_and_update() + space_id = str(self.config.get("space_id", "") or "") + interval_minutes = max(1, int(self.config.get("refresh_interval_minutes", 15) or 15)) + if not space_id or space_id.startswith("!vervang-mij"): + return + self._refresh_lock = asyncio.Lock() + self._scheduled_tasks = [] + # Direct eenmalig indexeren (prewarm), daarna periodiek. + self._scheduled_tasks.append( + self.sched.run_later(2, self._refresh_cache(space_id)) + ) + self._scheduled_tasks.append( + self.sched.run_periodically( + interval_minutes * 60, + partial(self._refresh_cache, space_id), + run_task_in_background=True, + ) + ) + self.log.info( + f"start: indexering gepland elke {interval_minutes} minuten" + ) + + async def stop(self) -> None: + for task in getattr(self, "_scheduled_tasks", []): + task.cancel() @classmethod def get_config_class(cls): @@ -155,6 +180,19 @@ class RoomsOverviewPlugin(Plugin): break return rooms, True + async def _refresh_cache(self, space_id: str) -> None: + """Live ophalen en in de cache opslaan (gedeeld via lock, ook achtergrond).""" + async with self._refresh_lock: + entries, complete = await self._fetch_hierarchy(space_id) + rooms = [ + r + for r in entries + if r.get("room_id") != space_id + and (r.get("room_type") or "") != "m.space" + ] + await self._store_cache(space_id, rooms, complete) + self.log.info(f"indexering voltooid ({len(rooms)} rooms)") + async def _load_cache( self, space_id: str ) -> Optional[Tuple[List[Dict[str, Any]], bool, int]]: @@ -191,35 +229,19 @@ class RoomsOverviewPlugin(Plugin): await evt.mark_read() - ttl_minutes = max(0, int(self.config.get("cache_ttl_minutes", 15) or 15)) cached = await self._load_cache(space_id) - now = int(time.time()) - if cached and ttl_minutes > 0 and now - cached[2] < ttl_minutes * 60: - rooms, complete = cached[0], cached[1] - self.log.info( - f"rooms: cache hit voor {space_id} (age {now - cached[2]}s)" - ) - else: - entries, complete = await self._fetch_hierarchy(space_id) - rooms = [ - r - for r in entries - if r.get("room_id") != space_id - and (r.get("room_type") or "") != "m.space" - ] - await self._store_cache(space_id, rooms, complete) + if cached is None: + # Nog nooit geïndexeerd: vraag een indexering aan en wacht erop + # (lock deelt met de achtergrondtaak, dus geen dubbele fetches). + await self._refresh_cache(space_id) + cached = await self._load_cache(space_id) + rooms, complete = cached[0], cached[1] if cached else ([], True) if not rooms: - if not complete: - await evt.reply( - "De ruimte-hierarchy kon niet worden opgehaald. Controleer de " - "space_id en of de bot lid is van (of toegang heeft tot) de space." - ) - else: - await evt.reply( - "Geen rooms gevonden. Controleer of de space_id klopt en of de bot " - "lid is van (of toegang heeft tot) de space." - ) + await evt.reply( + "Er zijn (nog) geen rooms gevonden. Controleer de space_id en of de bot " + "lid is van (of toegang heeft tot) de space." + ) return def sort_key(r: Dict[str, Any]) -> str: @@ -248,5 +270,5 @@ class RoomsOverviewPlugin(Plugin): for idx, chunk in enumerate(chunks, start=1): header = f"**Rooms overzicht ({total} rooms getoond, deel {idx}/{len(chunks)}):**\n\n" if idx == 1 and not complete: - header += "*De lijst is mogelijk onvolledig: de ruimte-hierarchy kon niet volledig worden opgehaald.*\n\n" + header += "*De lijst is mogelijk onvolledig: de laatste indexering was niet compleet.*\n\n" await evt.respond(header + "\n".join(chunk), markdown=True) \ No newline at end of file