36 lines
1.4 KiB
Python
36 lines
1.4 KiB
Python
import asyncio,json,os
|
|
from pathlib import Path
|
|
from core.threads import run_blocking
|
|
def _read(p):
|
|
if not p.exists():p.write_text("[]")
|
|
return p.stat().st_mtime_ns,frozenset(int(x) for x in json.loads(p.read_text()))
|
|
def _write(p,ids):
|
|
t=p.with_suffix(".tmp");t.write_text(json.dumps(sorted(ids),indent=2));os.replace(t,p);return p.stat().st_mtime_ns
|
|
class Whitelist:
|
|
def __init__(s,path,hook):
|
|
s.path=Path(path);s.hook=hook;s.ids=frozenset();s.m=None;s.lock=asyncio.Lock();s.task=None
|
|
def __contains__(s,i):return i in s.ids
|
|
async def load(s):
|
|
try:m,ids=await run_blocking(_read,s.path)
|
|
except Exception as e:
|
|
s.hook.put(f"whitelist unreadable: {e!r}, keeping previous list")
|
|
try:s.m=(await run_blocking(s.path.stat)).st_mtime_ns
|
|
except OSError:pass
|
|
return
|
|
if s.m is not None and ids!=s.ids:s.hook.put(f"whitelist reloaded ({len(ids)} ids)")
|
|
s.ids=ids;s.m=m
|
|
async def watch(s):
|
|
while True:
|
|
await asyncio.sleep(1)
|
|
try:m=(await run_blocking(s.path.stat)).st_mtime_ns
|
|
except OSError:m=None
|
|
if m!=s.m:await s.load()
|
|
async def start(s):
|
|
await s.load();s.task=asyncio.create_task(s.watch())
|
|
async def mutate(s,i,add):
|
|
async with s.lock:
|
|
n=set(s.ids)
|
|
if add:n.add(i)
|
|
else:n.discard(i)
|
|
s.m=await run_blocking(_write,s.path,n);s.ids=frozenset(n)
|