Merge pull request #13 from prosolis/claude/add-presence-heartbeat-WckxL
Add presence heartbeat to keep bot shown as online
This commit is contained in:
@@ -47,6 +47,9 @@ class DealsBot:
|
|||||||
else:
|
else:
|
||||||
self._first_run_done = True
|
self._first_run_done = True
|
||||||
|
|
||||||
|
# Start presence heartbeat so the bot shows as "online"
|
||||||
|
await self.matrix.start_presence_heartbeat()
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
"""Clean shutdown."""
|
"""Clean shutdown."""
|
||||||
await self._http.aclose()
|
await self._http.aclose()
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
"""Matrix client wrapper for sending deal messages."""
|
"""Matrix client wrapper for sending deal messages."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from nio import AsyncClient, RoomSendError
|
from nio import AsyncClient, PresenceSetError, RoomSendError
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
PRESENCE_HEARTBEAT_INTERVAL = 60 # seconds
|
||||||
|
|
||||||
|
|
||||||
class MatrixDealsClient:
|
class MatrixDealsClient:
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -19,6 +22,7 @@ class MatrixDealsClient:
|
|||||||
self._client = AsyncClient(homeserver_url, user_id)
|
self._client = AsyncClient(homeserver_url, user_id)
|
||||||
self._client.access_token = access_token
|
self._client.access_token = access_token
|
||||||
self._client.user_id = user_id
|
self._client.user_id = user_id
|
||||||
|
self._heartbeat_task: asyncio.Task | None = None
|
||||||
|
|
||||||
async def send_deal(self, plain_text: str, html: str) -> bool:
|
async def send_deal(self, plain_text: str, html: str) -> bool:
|
||||||
"""Send a deal message to the configured room.
|
"""Send a deal message to the configured room.
|
||||||
@@ -68,5 +72,49 @@ class MatrixDealsClient:
|
|||||||
logger.error("Matrix send error: %s", exc)
|
logger.error("Matrix send error: %s", exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
async def set_presence(self, presence: str) -> bool:
|
||||||
|
"""Set the bot's presence status on the homeserver.
|
||||||
|
|
||||||
|
Returns True on success, False on failure.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
resp = await self._client.set_presence(presence)
|
||||||
|
if isinstance(resp, PresenceSetError):
|
||||||
|
logger.error("Failed to set presence to %s: %s", presence, resp.message)
|
||||||
|
return False
|
||||||
|
logger.debug("Presence set to %s", presence)
|
||||||
|
return True
|
||||||
|
except Exception as exc:
|
||||||
|
logger.error("Presence set error: %s", exc)
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def start_presence_heartbeat(self):
|
||||||
|
"""Set presence to online and spawn a background task to keep it alive."""
|
||||||
|
await self.set_presence("online")
|
||||||
|
self._heartbeat_task = asyncio.create_task(self._presence_heartbeat_loop())
|
||||||
|
logger.info("Presence heartbeat started (every %ds)", PRESENCE_HEARTBEAT_INTERVAL)
|
||||||
|
|
||||||
|
async def _presence_heartbeat_loop(self):
|
||||||
|
"""Re-send 'online' presence every PRESENCE_HEARTBEAT_INTERVAL seconds."""
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(PRESENCE_HEARTBEAT_INTERVAL)
|
||||||
|
await self.set_presence("online")
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def stop_presence_heartbeat(self):
|
||||||
|
"""Cancel the heartbeat task and set presence to offline."""
|
||||||
|
if self._heartbeat_task is not None:
|
||||||
|
self._heartbeat_task.cancel()
|
||||||
|
try:
|
||||||
|
await self._heartbeat_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
self._heartbeat_task = None
|
||||||
|
await self.set_presence("offline")
|
||||||
|
logger.info("Presence heartbeat stopped, set to offline")
|
||||||
|
|
||||||
async def close(self):
|
async def close(self):
|
||||||
|
await self.stop_presence_heartbeat()
|
||||||
await self._client.close()
|
await self._client.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user