mirror of
https://github.com/rommapp/romm.git
synced 2026-10-12 02:21:58 +00:00
feat(streaming): open a container's desktop by its name
This commit is contained in:
@@ -230,6 +230,8 @@ class ContainerSessionSchema(BaseModel):
|
||||
|
||||
class AdminContainerSchema(BaseModel):
|
||||
container: str
|
||||
name: str = ""
|
||||
"""What URLs call this container: its own label when unique, else the key."""
|
||||
label: str | None = None
|
||||
host: str
|
||||
platforms: list[str]
|
||||
|
||||
@@ -69,6 +69,7 @@ from handler.streaming.config import (
|
||||
ResolvedContainer,
|
||||
configured_emulator,
|
||||
container_for_session,
|
||||
container_names,
|
||||
containers_by_key,
|
||||
containers_for_platform,
|
||||
emulator_labels,
|
||||
@@ -165,7 +166,7 @@ class LoadStateRequest(BaseModel):
|
||||
|
||||
|
||||
class DesktopStreamingSessionRequest(BaseModel):
|
||||
# The container to open, named by the key GET /streaming/containers
|
||||
# The container to open, by the name or key GET /streaming/containers
|
||||
# reports. Named rather than pooled: an admin configuring a container
|
||||
# needs that one, not whichever is free.
|
||||
container: Annotated[str, Field(min_length=1, max_length=300)]
|
||||
@@ -1374,6 +1375,7 @@ async def list_containers(request: Request) -> AdminContainersResponse:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
containers: list[dict[str, Any]] = []
|
||||
names = container_names()
|
||||
for container_key, entries in containers_by_key().items():
|
||||
first = entries[0]
|
||||
held = await get_session(container_key) if container_key else None
|
||||
@@ -1386,6 +1388,7 @@ async def list_containers(request: Request) -> AdminContainersResponse:
|
||||
containers.append(
|
||||
{
|
||||
"container": container_key,
|
||||
"name": names.get(container_key, ""),
|
||||
"label": first.container_label or first.label,
|
||||
"host": first.host,
|
||||
"platforms": [e.platform for e in entries],
|
||||
@@ -1429,7 +1432,7 @@ async def claim_desktop_session(
|
||||
if request.user.role != Role.ADMIN:
|
||||
raise HTTPException(status_code=403, detail="Forbidden")
|
||||
|
||||
container, platform = access.container_by_key(req.container)
|
||||
container, platform = access.container_by_name(req.container)
|
||||
if not container.protocol.supports_desktop:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
|
||||
@@ -11,6 +11,7 @@ from handler.streaming.config import (
|
||||
containers_by_key,
|
||||
containers_for_platform,
|
||||
entry_for_platform,
|
||||
key_for_name,
|
||||
)
|
||||
from handler.streaming.session_store import (
|
||||
get_live_session,
|
||||
@@ -306,17 +307,16 @@ async def require_claim(
|
||||
return target
|
||||
|
||||
|
||||
def container_by_key(container_key: str) -> tuple[ResolvedContainer, str]:
|
||||
"""A configured container named by its key, plus the platform to file its
|
||||
sessions under.
|
||||
def container_by_name(name: str) -> tuple[ResolvedContainer, str]:
|
||||
"""A configured container named by its name or key, plus the platform to
|
||||
file its sessions under.
|
||||
|
||||
The session routes are platform-keyed, so a container serving several gets
|
||||
the first, which `container_for_session` resolves back to this entry.
|
||||
Raises 404 when the key names no container.
|
||||
Raises 404 when the name matches no container.
|
||||
"""
|
||||
entries = containers_by_key().get(container_key) if container_key else None
|
||||
key = key_for_name(name) if name else None
|
||||
entries = containers_by_key().get(key) if key else None
|
||||
if not entries:
|
||||
raise HTTPException(
|
||||
status_code=404, detail=f"No streaming container '{container_key}'"
|
||||
)
|
||||
raise HTTPException(status_code=404, detail=f"No streaming container '{name}'")
|
||||
return entries[0], entries[0].platform
|
||||
|
||||
@@ -2284,6 +2284,43 @@ def test_containers_shows_what_is_running(client, access_token):
|
||||
assert session["username"] == "test_admin"
|
||||
|
||||
|
||||
def test_containers_reports_each_containers_name(client, access_token):
|
||||
labelled = _webstation(label="WEBSTATION-DEV")
|
||||
unlabelled = _webstation(
|
||||
label=None,
|
||||
host="http://192.168.1.11:3000",
|
||||
broker_host="http://192.168.1.11:8000",
|
||||
)
|
||||
with _streaming(labelled, unlabelled):
|
||||
rows = _containers(client, access_token).json()["containers"]
|
||||
assert [row["name"] for row in rows] == ["WEBSTATION-DEV", _key_of(unlabelled)]
|
||||
assert rows[0]["container"] == _key_of(labelled)
|
||||
|
||||
|
||||
def test_desktop_opens_by_label(client, access_token):
|
||||
container = _webstation(label="Emulation station")
|
||||
with _streaming(container):
|
||||
response, activate = _desktop(client, access_token, "emulation station")
|
||||
assert response.status_code == 200
|
||||
assert response.json()["container"] == _key_of(container)
|
||||
activate.assert_called_once()
|
||||
|
||||
|
||||
def test_desktop_still_opens_by_key(client, access_token):
|
||||
container = _webstation(label="WEBSTATION-DEV")
|
||||
with _streaming(container):
|
||||
response, _ = _desktop(client, access_token, _key_of(container))
|
||||
assert response.status_code == 200
|
||||
assert response.json()["container"] == _key_of(container)
|
||||
|
||||
|
||||
def test_desktop_refuses_an_unknown_name(client, access_token):
|
||||
with _streaming(_webstation(label="WEBSTATION-DEV")):
|
||||
response, activate = _desktop(client, access_token, "WEBSTATION-OTHER")
|
||||
assert response.status_code == 404
|
||||
activate.assert_not_called()
|
||||
|
||||
|
||||
def test_containers_is_admin_only(client, viewer_access_token):
|
||||
with _streaming(_webstation()):
|
||||
assert _containers(client, viewer_access_token).status_code == 403
|
||||
|
||||
Reference in New Issue
Block a user