119 lines
3.7 KiB
Python
119 lines
3.7 KiB
Python
"""
|
|
Session and lobby management for voicebot.
|
|
|
|
This module handles session creation and lobby management functionality.
|
|
"""
|
|
|
|
import json
|
|
import ssl
|
|
import urllib.request
|
|
import urllib.error
|
|
import urllib.parse
|
|
import sys
|
|
import os
|
|
from pydantic import ValidationError
|
|
|
|
# Add the parent directory to sys.path to allow absolute imports
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
# Import shared models
|
|
from shared.models import SessionModel, LobbyCreateResponse
|
|
|
|
from voicebot.utils import http_base_url
|
|
|
|
|
|
def create_or_get_session(
|
|
server_url: str, session_id: str | None = None, insecure: bool = False
|
|
) -> str:
|
|
"""Call GET /api/session to obtain a session_id (unless one was provided).
|
|
|
|
Uses urllib so no extra runtime deps are required.
|
|
"""
|
|
if session_id:
|
|
return session_id
|
|
|
|
http_base = http_base_url(server_url)
|
|
url = f"{http_base}/api/session"
|
|
req = urllib.request.Request(url, method="GET")
|
|
# Prepare SSL context if requested (accept self-signed certs)
|
|
ssl_ctx = None
|
|
if insecure:
|
|
ssl_ctx = ssl.create_default_context()
|
|
ssl_ctx.check_hostname = False
|
|
ssl_ctx.verify_mode = ssl.CERT_NONE
|
|
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10, context=ssl_ctx) as resp:
|
|
body = resp.read()
|
|
data = json.loads(body)
|
|
|
|
# Validate response shape using Pydantic
|
|
try:
|
|
session = SessionModel.model_validate(data)
|
|
except ValidationError as e:
|
|
raise RuntimeError(f"Invalid session response from {url}: {e}")
|
|
|
|
sid = session.id
|
|
if not sid:
|
|
raise RuntimeError(f"No session id returned from {url}: {data}")
|
|
return sid
|
|
except urllib.error.HTTPError as e:
|
|
raise RuntimeError(f"HTTP error getting session: {e}")
|
|
except Exception as e:
|
|
raise RuntimeError(f"Error getting session: {e}")
|
|
|
|
|
|
def create_or_get_lobby(
|
|
server_url: str,
|
|
session_id: str,
|
|
lobby_name: str,
|
|
private: bool = False,
|
|
insecure: bool = False,
|
|
) -> str:
|
|
"""Call POST /api/lobby/{session_id} to create or lookup a lobby by name.
|
|
|
|
Returns the lobby id.
|
|
"""
|
|
http_base = http_base_url(server_url)
|
|
url = f"{http_base}/api/lobby/{urllib.parse.quote(session_id)}"
|
|
payload = json.dumps(
|
|
{
|
|
"type": "lobby_create",
|
|
"data": {"name": lobby_name, "private": private},
|
|
}
|
|
).encode("utf-8")
|
|
req = urllib.request.Request(
|
|
url, data=payload, headers={"Content-Type": "application/json"}, method="POST"
|
|
)
|
|
# Prepare SSL context if requested (accept self-signed certs)
|
|
ssl_ctx = None
|
|
if insecure:
|
|
ssl_ctx = ssl.create_default_context()
|
|
ssl_ctx.check_hostname = False
|
|
ssl_ctx.verify_mode = ssl.CERT_NONE
|
|
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=10, context=ssl_ctx) as resp:
|
|
body = resp.read()
|
|
data = json.loads(body)
|
|
# Expect shape: { "type": "lobby_created", "data": {"id":..., ...}}
|
|
try:
|
|
lobby_resp = LobbyCreateResponse.model_validate(data)
|
|
except ValidationError as e:
|
|
raise RuntimeError(f"Invalid lobby response from {url}: {e}")
|
|
|
|
lobby_id = lobby_resp.data.id
|
|
if not lobby_id:
|
|
raise RuntimeError(f"No lobby id returned from {url}: {data}")
|
|
return lobby_id
|
|
except urllib.error.HTTPError as e:
|
|
# Try to include response body for debugging
|
|
try:
|
|
body = e.read()
|
|
msg = body.decode("utf-8", errors="ignore")
|
|
except Exception:
|
|
msg = str(e)
|
|
raise RuntimeError(f"HTTP error creating lobby: {msg}")
|
|
except Exception as e:
|
|
raise RuntimeError(f"Error creating lobby: {e}")
|