Host-side identifier (systemd unit name and /var/lib/left4me dirs) is now
str(server.id), centralized in services/server_identity.server_unit_name.
Server.name becomes a free-form display label, required and unique per
user (was [a-z0-9_-]{1,64} and globally unique).
Migration 0006 swaps the old global UNIQUE(name) for UNIQUE(user_id, name).
Web routes already keyed on id; templates only used name for display.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
37 lines
1.1 KiB
Python
37 lines
1.1 KiB
Python
from flask import Blueprint, Response
|
|
from sqlalchemy import select
|
|
|
|
from l4d2web.auth import current_user, require_login
|
|
from l4d2web.db import session_scope
|
|
from l4d2web.models import Server
|
|
from l4d2web.services import l4d2_facade as facade
|
|
from l4d2web.services.server_identity import server_unit_name
|
|
|
|
|
|
bp = Blueprint("logs", __name__)
|
|
|
|
|
|
def load_authorized_server(server_id: int) -> Server | None:
|
|
user = current_user()
|
|
if user is None:
|
|
return None
|
|
with session_scope() as db:
|
|
server = db.scalar(select(Server).where(Server.id == server_id, Server.user_id == user.id))
|
|
return server
|
|
|
|
|
|
@bp.get("/servers/<int:server_id>/logs/stream")
|
|
@require_login
|
|
def stream_server_logs(server_id: int) -> Response:
|
|
server = load_authorized_server(server_id)
|
|
if server is None:
|
|
return Response(status=404)
|
|
|
|
def generate():
|
|
for line in facade.stream_server_logs(server_unit_name(server.id), lines=200, follow=True):
|
|
if line == "":
|
|
yield ": keepalive\n\n"
|
|
else:
|
|
yield f"data: {line}\n\n"
|
|
|
|
return Response(generate(), mimetype="text/event-stream")
|