Files
dc-nogi/bot/backlog.py
2026-08-01 15:09:47 +02:00

63 lines
2.0 KiB
Python

import asyncio
import datetime
import logging
from typing import Awaitable, Callable
import discord
from bot.discovery import Target
from bot.storage import Storage
log = logging.getLogger(__name__)
ReactFn = Callable[[discord.Message, Target], Awaitable[bool]]
async def scan_channel_backlog(
storage: Storage,
channel: discord.abc.Messageable,
target: Target,
friend_id: int,
cutoff: datetime.datetime,
react_fn: ReactFn,
) -> None:
"""Scan a channel's history once, resumably.
First run: walk forward from `cutoff` (now - days_back) to the present.
Subsequent runs: only diff forward from the newest message already seen,
since the days_back window only ever moves forward in time.
"""
channel_id = getattr(channel, "id", None)
if channel_id is None:
return
state = await asyncio.to_thread(storage.get_scan_state, channel_id)
newest_id_seen = int(state["newest_id_seen"]) if state and state.get("newest_id_seen") else None
after = discord.Object(id=newest_id_seen) if newest_id_seen else cutoff
checkpoint_every = 25
seen_since_checkpoint = 0
try:
async for message in channel.history(after=after, oldest_first=True, limit=None):
if newest_id_seen is None or message.id > newest_id_seen:
newest_id_seen = message.id
await react_fn(message, target)
seen_since_checkpoint += 1
if seen_since_checkpoint >= checkpoint_every:
seen_since_checkpoint = 0
await asyncio.to_thread(
storage.set_scan_state, channel_id, target.target_id, newest_id_seen, False
)
await asyncio.to_thread(
storage.set_scan_state, channel_id, target.target_id, newest_id_seen, True
)
except discord.Forbidden:
log.warning("No access to channel %s (%s), skipping", channel_id, getattr(channel, "name", ""))
except discord.HTTPException:
log.exception("HTTP error scanning channel %s", channel_id)