|
|
|
@@ -45,6 +45,7 @@ async def terminal_websocket(
|
|
|
|
|
"""
|
|
|
|
|
logger.info("Terminal WebSocket connection attempt for instance %s", instance_id)
|
|
|
|
|
await websocket.accept()
|
|
|
|
|
logger.info("Terminal WebSocket accepted for instance %s", instance_id)
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
# Parse instance_id
|
|
|
|
@@ -78,6 +79,8 @@ async def terminal_websocket(
|
|
|
|
|
await websocket.close(code=4004, reason="Instance not running")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
logger.info("Terminal auth passed for instance %s, user %s", instance_id, user_id)
|
|
|
|
|
|
|
|
|
|
# Get or create terminal session
|
|
|
|
|
try:
|
|
|
|
|
session = await terminal_manager.get_or_create_session(
|
|
|
|
@@ -92,6 +95,7 @@ async def terminal_websocket(
|
|
|
|
|
|
|
|
|
|
# Send connected status
|
|
|
|
|
await websocket.send_json({"type": "status", "status": "connected"})
|
|
|
|
|
logger.info("Sent connected status for instance %s", instance_id)
|
|
|
|
|
|
|
|
|
|
# Use mutable session reference so loops can survive reset
|
|
|
|
|
session_ref = SessionRef(session)
|
|
|
|
@@ -100,6 +104,7 @@ async def terminal_websocket(
|
|
|
|
|
read_task = asyncio.create_task(_read_loop(session_ref, websocket))
|
|
|
|
|
write_task = asyncio.create_task(_write_loop(session_ref, websocket, instance_id))
|
|
|
|
|
heartbeat_task = asyncio.create_task(_heartbeat_loop(websocket))
|
|
|
|
|
logger.info("Started terminal loops for instance %s", instance_id)
|
|
|
|
|
|
|
|
|
|
# Wait for either task to complete (indicating disconnect or error)
|
|
|
|
|
done, pending = await asyncio.wait(
|
|
|
|
@@ -107,6 +112,8 @@ async def terminal_websocket(
|
|
|
|
|
return_when=asyncio.FIRST_COMPLETED,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
logger.info("Terminal loop completed for instance %s, done=%s", instance_id, len(done))
|
|
|
|
|
|
|
|
|
|
# Cancel remaining tasks
|
|
|
|
|
for task in pending:
|
|
|
|
|
task.cancel()
|
|
|
|
|