Initial commit
This commit is contained in:
62
bot/backlog.py
Normal file
62
bot/backlog.py
Normal file
@@ -0,0 +1,62 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user