63 lines
2.0 KiB
Python
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)
|