fix: 10 пунктов ревью — /run (кортеж store.add), валидация limit/offset в панели, close() соединений SQLite, троттлинг под локом, read-only бот без OMNI_BOT_OWNERS, eviction JOBS, push_new отдаёт свежие записи, ai.py не спит после последней попытки, дедуп реестра, подключён abuse-реестр (+191 источник); tests/test_regress.py 16 проверок + CI py3.10-3.12
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
source_flags (name, enabled, status, items, note, checked)
|
||||
source_custom (name, category, kind, url, adapter, tags, limit, detail, added)
|
||||
"""
|
||||
import contextlib
|
||||
import json
|
||||
import sqlite3
|
||||
import time
|
||||
@@ -34,9 +35,24 @@ def conn():
|
||||
return c
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def db():
|
||||
"""Соединение с гарантированным close(): `with conn()` коммитит, но не закрывает,
|
||||
и хендлы копятся (замер: 200 вызовов == +76 handles)."""
|
||||
c = conn()
|
||||
try:
|
||||
yield c
|
||||
c.commit()
|
||||
except Exception:
|
||||
c.rollback()
|
||||
raise
|
||||
finally:
|
||||
c.close()
|
||||
|
||||
|
||||
def flags():
|
||||
"""{name: {enabled, status, items, note, checked}}"""
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
rows = c.execute("SELECT name, enabled, status, items, note, checked FROM source_flags").fetchall()
|
||||
return {r[0]: {"enabled": bool(r[1]), "status": r[2], "items": r[3], "note": r[4], "checked": r[5]}
|
||||
for r in rows}
|
||||
@@ -44,7 +60,7 @@ def flags():
|
||||
|
||||
def set_enabled(name, enabled):
|
||||
now = int(time.time())
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
c.execute("INSERT INTO source_flags(name, enabled, checked) VALUES(?,?,?) "
|
||||
"ON CONFLICT(name) DO UPDATE SET enabled=excluded.enabled",
|
||||
(name, 1 if enabled else 0, now))
|
||||
@@ -53,7 +69,7 @@ def set_enabled(name, enabled):
|
||||
|
||||
def record_check(name, status, items, note=""):
|
||||
now = int(time.time())
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
c.execute("INSERT INTO source_flags(name, enabled, status, items, note, checked) VALUES(?,1,?,?,?,?) "
|
||||
"ON CONFLICT(name) DO UPDATE SET status=excluded.status, items=excluded.items, "
|
||||
"note=excluded.note, checked=excluded.checked",
|
||||
@@ -62,7 +78,7 @@ def record_check(name, status, items, note=""):
|
||||
|
||||
|
||||
def custom():
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
rows = c.execute("SELECT name, category, kind, url, adapter, tags, lim, detail, added "
|
||||
"FROM source_custom ORDER BY added DESC").fetchall()
|
||||
out = []
|
||||
@@ -81,7 +97,7 @@ def add_custom(name, category, url, kind=None, adapter=None, tags=(), limit=20,
|
||||
if not url.startswith("http"):
|
||||
raise ValueError("url должен начинаться с http")
|
||||
kind, adapter = kind or guess_kind(url), adapter or guess_adapter(url, kind)
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
c.execute("INSERT OR REPLACE INTO source_custom(name, category, kind, url, adapter, tags, lim, detail, added) "
|
||||
"VALUES(?,?,?,?,?,?,?,?,?)",
|
||||
(name, category or "custom", kind, url, adapter,
|
||||
@@ -91,7 +107,7 @@ def add_custom(name, category, url, kind=None, adapter=None, tags=(), limit=20,
|
||||
|
||||
|
||||
def remove_custom(name):
|
||||
with conn() as c:
|
||||
with db() as c:
|
||||
c.execute("DELETE FROM source_custom WHERE name=?", (name,))
|
||||
c.execute("DELETE FROM source_flags WHERE name=?", (name,))
|
||||
return {"removed": name}
|
||||
|
||||
Reference in New Issue
Block a user