Sicherheits-Härtung und Bugfixes
This commit is contained in:
+56
-8
@@ -1,9 +1,25 @@
|
||||
import datetime
|
||||
from sqlalchemy import create_engine, Column, Integer, String, Boolean, DateTime, Text, text
|
||||
import logging
|
||||
|
||||
from sqlalchemy import create_engine, event, Column, Integer, String, Boolean, DateTime, Text, text
|
||||
from sqlalchemy.orm import declarative_base, sessionmaker
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
logger = logging.getLogger("models")
|
||||
|
||||
|
||||
def utcnow() -> datetime.datetime:
|
||||
return datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
||||
|
||||
|
||||
def iso_utc(dt: datetime.datetime | None) -> str | None:
|
||||
if dt is None:
|
||||
return None
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.replace(tzinfo=datetime.timezone.utc)
|
||||
return dt.astimezone(datetime.timezone.utc).isoformat()
|
||||
|
||||
|
||||
class Job(Base):
|
||||
__tablename__ = "jobs"
|
||||
@@ -37,8 +53,8 @@ class Job(Base):
|
||||
|
||||
station_id = Column(Integer, nullable=True)
|
||||
|
||||
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
created_at = Column(DateTime, default=utcnow)
|
||||
updated_at = Column(DateTime, default=utcnow, onupdate=utcnow)
|
||||
|
||||
|
||||
class Station(Base):
|
||||
@@ -49,8 +65,8 @@ class Station(Base):
|
||||
stream_url = Column(String(1000), nullable=False)
|
||||
stream_type = Column(String(20), default="auto")
|
||||
description = Column(Text, default="")
|
||||
created_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.datetime.utcnow, onupdate=datetime.datetime.utcnow)
|
||||
created_at = Column(DateTime, default=utcnow)
|
||||
updated_at = Column(DateTime, default=utcnow, onupdate=utcnow)
|
||||
|
||||
|
||||
class Recording(Base):
|
||||
@@ -65,7 +81,7 @@ class Recording(Base):
|
||||
output_file = Column(String(500), default="")
|
||||
pid = Column(Integer, nullable=True)
|
||||
status = Column(String(20), default="running") # running, stopped, completed, error
|
||||
started_at = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
started_at = Column(DateTime, default=utcnow)
|
||||
stopped_at = Column(DateTime, nullable=True)
|
||||
scheduled_stop = Column(DateTime, nullable=True)
|
||||
segment_mode = Column(Boolean, default=False)
|
||||
@@ -79,7 +95,7 @@ class LogEntry(Base):
|
||||
__tablename__ = "logs"
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
timestamp = Column(DateTime, default=datetime.datetime.utcnow)
|
||||
timestamp = Column(DateTime, default=utcnow)
|
||||
level = Column(String(10), default="INFO")
|
||||
message = Column(Text, nullable=False)
|
||||
job_name = Column(String(200), nullable=True)
|
||||
@@ -91,7 +107,20 @@ _SessionLocal = None
|
||||
|
||||
def init_db(db_path: str):
|
||||
global _engine, _SessionLocal
|
||||
_engine = create_engine(f"sqlite:///{db_path}", connect_args={"check_same_thread": False})
|
||||
_engine = create_engine(
|
||||
f"sqlite:///{db_path}",
|
||||
connect_args={"check_same_thread": False, "timeout": 30},
|
||||
)
|
||||
|
||||
@event.listens_for(_engine, "connect")
|
||||
def _set_sqlite_pragmas(dbapi_conn, _record):
|
||||
cur = dbapi_conn.cursor()
|
||||
try:
|
||||
cur.execute("PRAGMA journal_mode=WAL")
|
||||
cur.execute("PRAGMA busy_timeout=5000")
|
||||
finally:
|
||||
cur.close()
|
||||
|
||||
Base.metadata.create_all(_engine)
|
||||
_SessionLocal = sessionmaker(bind=_engine)
|
||||
_migrate(_engine)
|
||||
@@ -115,3 +144,22 @@ def _migrate(engine):
|
||||
|
||||
def get_session():
|
||||
return _SessionLocal()
|
||||
|
||||
|
||||
def prune_logs(days: int) -> int:
|
||||
if days <= 0:
|
||||
return 0
|
||||
cutoff = utcnow() - datetime.timedelta(days=days)
|
||||
session = get_session()
|
||||
try:
|
||||
count = session.query(LogEntry).filter(LogEntry.timestamp < cutoff).delete(synchronize_session=False)
|
||||
session.commit()
|
||||
if count:
|
||||
logger.info("%d alte Log-Einträge gelöscht (älter als %d Tage)", count, days)
|
||||
return count
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
logger.error("Log-Bereinigung fehlgeschlagen: %s", e)
|
||||
return 0
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
Reference in New Issue
Block a user