Bots now join on demand
This commit is contained in:
parent
b916db243b
commit
b5614b9d99
@ -6,28 +6,21 @@
|
||||
node_modules
|
||||
build
|
||||
dist
|
||||
__pycache__
|
||||
**/__pycache__
|
||||
**/.venv
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
*.log
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
.vscode
|
||||
.idea
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
.env
|
||||
.env.*
|
||||
dev-keys
|
||||
*.pem
|
||||
*.key
|
||||
coverage
|
||||
*.bak
|
||||
*.tmp
|
||||
*.local
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
*docker-compose.override.yml
|
||||
|
@ -182,14 +182,10 @@ const BotManager: React.FC<BotManagerProps> = ({ lobbyId, onBotAdded, sx }) => {
|
||||
<Typography variant="body2" component="div">
|
||||
{botInfo.description}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={providerName}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
sx={{ mt: 0.5 }}
|
||||
/>
|
||||
<Chip label={providerName} size="small" variant="outlined" sx={{ mt: 0.5 }} />
|
||||
</Box>
|
||||
}
|
||||
secondaryTypographyProps={{ component: "div" }}
|
||||
/>
|
||||
</ListItem>
|
||||
);
|
||||
@ -220,6 +216,7 @@ const BotManager: React.FC<BotManagerProps> = ({ lobbyId, onBotAdded, sx }) => {
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
secondaryTypographyProps={{ component: "div" }}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
@ -258,15 +255,8 @@ const BotManager: React.FC<BotManagerProps> = ({ lobbyId, onBotAdded, sx }) => {
|
||||
}}
|
||||
onClick={() => setSelectedBot(botName)}
|
||||
>
|
||||
<ListItemText
|
||||
primary={botInfo.name}
|
||||
secondary={botInfo.description}
|
||||
/>
|
||||
<Chip
|
||||
label={getProviderName(providers[botName])}
|
||||
size="small"
|
||||
variant="outlined"
|
||||
/>
|
||||
<ListItemText primary={botInfo.name} secondary={botInfo.description} />
|
||||
<Chip label={getProviderName(providers[botName])} size="small" variant="outlined" />
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
@ -64,15 +64,14 @@ services:
|
||||
- PRODUCTION=${PRODUCTION:-false}
|
||||
- VOICEBOT_MODE=provider
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./cache:/root/.cache:rw
|
||||
- ./shared:/shared:ro
|
||||
- ./voicebot:/voicebot:rw
|
||||
- ./voicebot/.venv:/voicebot/.venv:rw
|
||||
# network_mode: host
|
||||
# networks:
|
||||
# - ai-voicebot-net
|
||||
networks:
|
||||
- ai-voicebot-net
|
||||
|
||||
|
||||
networks:
|
||||
|
@ -1433,13 +1433,17 @@ async def request_bot_join_lobby(
|
||||
# Create a session for the bot
|
||||
bot_session_id = secrets.token_hex(16)
|
||||
|
||||
# Create the Session object for the bot
|
||||
bot_session = Session(bot_session_id)
|
||||
logger.info(f"Created session for bot: {bot_session.getName()}")
|
||||
|
||||
# Determine server URL for the bot to connect back to
|
||||
# Use the server's public URL or construct from request
|
||||
server_base_url = os.getenv("PUBLIC_SERVER_URL", "http://localhost:8000")
|
||||
if server_base_url.endswith("/"):
|
||||
server_base_url = server_base_url[:-1]
|
||||
|
||||
bot_nick = request.nick or f"{bot_name}-bot"
|
||||
bot_nick = request.nick or f"{bot_name}-bot-{bot_session_id[:8]}"
|
||||
|
||||
# Prepare the join request for the bot provider
|
||||
bot_join_payload = BotJoinPayload(
|
||||
@ -1447,7 +1451,7 @@ async def request_bot_join_lobby(
|
||||
session_id=bot_session_id,
|
||||
nick=bot_nick,
|
||||
server_url=f"{server_base_url}{public_url}".rstrip("/"),
|
||||
insecure=False, # Assume secure by default
|
||||
insecure=True, # Accept self-signed certificates in development
|
||||
)
|
||||
|
||||
try:
|
||||
|
@ -11,6 +11,8 @@ import importlib
|
||||
import pkgutil
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Dict, Any
|
||||
|
||||
# Add the parent directory to sys.path to allow absolute imports
|
||||
@ -24,11 +26,47 @@ from voicebot.models import JoinRequest
|
||||
from voicebot.webrtc_signaling import WebRTCSignalingClient
|
||||
|
||||
|
||||
app = FastAPI(title="voicebot-bot-orchestrator")
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Startup
|
||||
logger.info(f"🚀 Voicebot bot orchestrator started successfully at {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
# Log the discovered bots
|
||||
bots = discover_bots()
|
||||
if bots:
|
||||
logger.info(f"📋 Discovered {len(bots)} bots: {list(bots.keys())}")
|
||||
else:
|
||||
logger.info("⚠️ No bots discovered")
|
||||
|
||||
# Check for remote server registration
|
||||
remote_server_url = os.getenv('VOICEBOT_SERVER_URL')
|
||||
if remote_server_url:
|
||||
# Attempt to register with remote server
|
||||
try:
|
||||
host = os.getenv('HOST', '0.0.0.0')
|
||||
port = os.getenv('PORT', '8788')
|
||||
insecure = os.getenv('VOICEBOT_SERVER_INSECURE', 'false').lower() == 'true'
|
||||
|
||||
provider_id = await _perform_server_registration(remote_server_url, host, port, insecure)
|
||||
logger.info(f"🎉 Successfully registered with remote server! Provider ID: {provider_id}")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Failed to register with remote server: {e}")
|
||||
logger.warning("⚠️ Bot orchestrator will continue running without remote registration")
|
||||
else:
|
||||
logger.info("ℹ️ No VOICEBOT_SERVER_URL provided - running in local-only mode")
|
||||
|
||||
yield
|
||||
|
||||
# Shutdown
|
||||
logger.info("🛑 Voicebot bot orchestrator shutting down")
|
||||
|
||||
app = FastAPI(title="voicebot-bot-orchestrator", lifespan=lifespan)
|
||||
|
||||
# Lightweight in-memory registry of running bot clients
|
||||
registry: Dict[str, WebRTCSignalingClient] = {}
|
||||
|
||||
# Log module import for debugging reloads
|
||||
logger.info("📦 Bot orchestrator module imported/reloaded")
|
||||
|
||||
|
||||
def discover_bots() -> Dict[str, Dict[str, Any]]:
|
||||
"""Discover bot modules under the voicebot.bots package that expose bot_info.
|
||||
@ -83,6 +121,8 @@ async def bot_join(bot_name: str, req: JoinRequest):
|
||||
|
||||
create_tracks = bot.get("create_tracks")
|
||||
|
||||
logger.info(f"🤖 Bot {bot_name} joining lobby {req.lobby_id} with nick: '{req.nick}'")
|
||||
|
||||
# Start the WebRTCSignalingClient in a background asyncio task and register it
|
||||
client = WebRTCSignalingClient(
|
||||
server_url=req.server_url,
|
||||
@ -104,8 +144,14 @@ async def bot_join(bot_name: str, req: JoinRequest):
|
||||
finally:
|
||||
registry.pop(run_id, None)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
threading.Thread(target=loop.run_until_complete, args=(run_client(),), daemon=True).start()
|
||||
def run_client_in_thread():
|
||||
"""Run the client in a new event loop in a separate thread."""
|
||||
try:
|
||||
asyncio.run(run_client())
|
||||
except Exception:
|
||||
logger.exception("Bot client thread failed for run %s", run_id)
|
||||
|
||||
threading.Thread(target=run_client_in_thread, daemon=True).start()
|
||||
|
||||
return {"status": "started", "bot": bot_name, "run_id": run_id}
|
||||
|
||||
@ -141,8 +187,46 @@ def start_bot_api(host: str = "0.0.0.0", port: int = 8788):
|
||||
uvicorn.run(app, host=host, port=port)
|
||||
|
||||
|
||||
def _construct_voicebot_url(host: str, port: str) -> str:
|
||||
"""Construct the voicebot URL based on host and port"""
|
||||
if host == "0.0.0.0":
|
||||
import socket
|
||||
try:
|
||||
hostname = socket.gethostname()
|
||||
voicebot_url = f"http://{hostname}:{port}"
|
||||
logger.info(f"🏠 Using hostname-based URL: {voicebot_url}")
|
||||
except Exception:
|
||||
voicebot_url = f"http://localhost:{port}"
|
||||
logger.info(f"🏠 Using localhost URL: {voicebot_url}")
|
||||
else:
|
||||
voicebot_url = f"http://{host}:{port}"
|
||||
logger.info(f"🏠 Using host-based URL: {voicebot_url}")
|
||||
|
||||
return voicebot_url
|
||||
|
||||
|
||||
def _perform_server_registration_sync(server_url: str, host: str, port: str, insecure: bool) -> str:
|
||||
"""Synchronous wrapper for _perform_server_registration"""
|
||||
return asyncio.run(_perform_server_registration(server_url, host, port, insecure))
|
||||
|
||||
|
||||
async def _perform_server_registration(server_url: str, host: str, port: str, insecure: bool) -> str:
|
||||
"""Perform server registration with common logic"""
|
||||
voicebot_url = _construct_voicebot_url(host, port)
|
||||
|
||||
logger.info("⏱️ Waiting 2 seconds before attempting remote registration...")
|
||||
await asyncio.sleep(2) # Give server time to fully start
|
||||
|
||||
provider_id = await register_with_server(server_url, voicebot_url, insecure)
|
||||
logger.info(f"🎉 Successfully registered with remote server! Provider ID: {provider_id}")
|
||||
return provider_id
|
||||
|
||||
|
||||
async def register_with_server(server_url: str, voicebot_url: str, insecure: bool = False) -> str:
|
||||
"""Register this voicebot instance as a bot provider with the main server"""
|
||||
logger.info(f"🔗 Attempting to register with remote server at {server_url}")
|
||||
logger.info(f"📍 Registration details - Voicebot URL: {voicebot_url}, Insecure: {insecure}")
|
||||
|
||||
try:
|
||||
# Import httpx locally to avoid dependency issues
|
||||
import httpx
|
||||
@ -153,6 +237,8 @@ async def register_with_server(server_url: str, voicebot_url: str, insecure: boo
|
||||
"description": "AI voicebot provider with speech recognition and synthetic media capabilities"
|
||||
}
|
||||
|
||||
logger.info(f"📤 Sending registration payload: {payload}")
|
||||
|
||||
# Prepare SSL context if needed
|
||||
verify = not insecure
|
||||
|
||||
@ -166,14 +252,15 @@ async def register_with_server(server_url: str, voicebot_url: str, insecure: boo
|
||||
if response.status_code == 200:
|
||||
result = response.json()
|
||||
provider_id = result.get("provider_id")
|
||||
logger.info(f"Successfully registered with server as provider: {provider_id}")
|
||||
logger.info(f"✅ Successfully registered with server as provider: {provider_id}")
|
||||
logger.info(f"🎯 Remote server can now discover bots at: {voicebot_url}")
|
||||
return provider_id
|
||||
else:
|
||||
logger.error(f"Failed to register with server: HTTP {response.status_code}: {response.text}")
|
||||
logger.error(f"❌ Failed to register with server: HTTP {response.status_code}: {response.text}")
|
||||
raise RuntimeError(f"Registration failed: {response.status_code}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error registering with server: {e}")
|
||||
logger.error(f"💥 Error registering with server: {e}")
|
||||
raise
|
||||
|
||||
|
||||
@ -186,7 +273,6 @@ def start_bot_provider(
|
||||
):
|
||||
"""Start the bot provider API server and optionally register with main server"""
|
||||
import time
|
||||
import socket
|
||||
|
||||
# Start the FastAPI server in a background thread
|
||||
# Add reload functionality for development
|
||||
@ -212,23 +298,19 @@ def start_bot_provider(
|
||||
|
||||
# If server_url is provided, register with the main server
|
||||
if server_url:
|
||||
logger.info(f"🔄 Server URL provided - will attempt registration with: {server_url}")
|
||||
# Give the server a moment to start
|
||||
logger.info("⏱️ Waiting 2 seconds for server to fully start...")
|
||||
time.sleep(2)
|
||||
|
||||
# Construct the voicebot URL
|
||||
voicebot_url = f"http://{host}:{port}"
|
||||
if host == "0.0.0.0":
|
||||
# Try to get a better hostname
|
||||
try:
|
||||
hostname = socket.gethostname()
|
||||
voicebot_url = f"http://{hostname}:{port}"
|
||||
except Exception:
|
||||
voicebot_url = f"http://localhost:{port}"
|
||||
|
||||
try:
|
||||
asyncio.run(register_with_server(server_url, voicebot_url, insecure))
|
||||
provider_id = _perform_server_registration_sync(server_url, host, str(port), insecure)
|
||||
logger.info(f"🎉 Registration completed successfully! Provider ID: {provider_id}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to register with server: {e}")
|
||||
logger.error(f"❌ Failed to register with server: {e}")
|
||||
logger.warning("⚠️ Bot orchestrator will continue running without remote registration")
|
||||
else:
|
||||
logger.info("ℹ️ No remote server URL provided - running in local-only mode")
|
||||
|
||||
# Keep the main thread alive
|
||||
try:
|
||||
|
@ -8,6 +8,7 @@ import asyncio
|
||||
import os
|
||||
import fcntl
|
||||
import sys
|
||||
import time
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Optional
|
||||
|
||||
@ -41,6 +42,9 @@ def create_client_app(args: VoicebotArgs) -> FastAPI:
|
||||
async def lifespan(app: FastAPI):
|
||||
nonlocal client_task, lock_file
|
||||
# Startup
|
||||
logger.info(f"🚀 Voicebot client app started at {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
logger.info(f"📡 Client config - Server: {args.server_url}, Lobby: {args.lobby}, Session: {args.session_name}")
|
||||
|
||||
# Use a file lock to prevent multiple instances from starting
|
||||
lock_file_path = "/tmp/voicebot_client.lock"
|
||||
|
||||
|
@ -27,6 +27,8 @@ if [ "$PRODUCTION" != "true" ]; then
|
||||
if [ "$MODE" = "provider" ]; then
|
||||
echo "Running as bot provider with auto-reload..."
|
||||
export VOICEBOT_MODE=provider
|
||||
export VOICEBOT_SERVER_URL="https://server:8000/ai-voicebot"
|
||||
export VOICEBOT_SERVER_INSECURE="true"
|
||||
exec uv run uvicorn main:uvicorn_app \
|
||||
--host 0.0.0.0 \
|
||||
--port 8788 \
|
||||
@ -37,11 +39,11 @@ if [ "$PRODUCTION" != "true" ]; then
|
||||
else
|
||||
echo "Running as client (connecting to lobby)..."
|
||||
export VOICEBOT_MODE=client
|
||||
export VOICEBOT_SERVER_URL="https://ketrenos.com/ai-voicebot"
|
||||
export VOICEBOT_SERVER_URL="https://server:8000/ai-voicebot"
|
||||
export VOICEBOT_SERVER_INSECURE="true"
|
||||
export VOICEBOT_LOBBY="default"
|
||||
export VOICEBOT_SESSION_NAME="Python Voicebot"
|
||||
export VOICEBOT_PASSWORD="v01c3b0t"
|
||||
export VOICEBOT_INSECURE="true"
|
||||
exec uv run uvicorn main:uvicorn_app \
|
||||
--host 0.0.0.0 \
|
||||
--port 8789 \
|
||||
@ -55,6 +57,8 @@ else
|
||||
if [ "$MODE" = "provider" ]; then
|
||||
echo "Running as bot provider..."
|
||||
export VOICEBOT_MODE=provider
|
||||
export VOICEBOT_SERVER_URL="https://server:8000/ai-voicebot"
|
||||
export VOICEBOT_SERVER_INSECURE="true"
|
||||
exec uv run uvicorn main:uvicorn_app \
|
||||
--host 0.0.0.0 \
|
||||
--port 8788 \
|
||||
@ -62,11 +66,11 @@ else
|
||||
else
|
||||
echo "Running as client (connecting to lobby)..."
|
||||
export VOICEBOT_MODE=client
|
||||
export VOICEBOT_SERVER_URL="https://ai-voicebot.ketrenos.com"
|
||||
export VOICEBOT_SERVER_URL="https://server:8000/ai-voicebot"
|
||||
export VOICEBOT_SERVER_INSECURE="true"
|
||||
export VOICEBOT_LOBBY="default"
|
||||
export VOICEBOT_SESSION_NAME="Python Voicebot"
|
||||
export VOICEBOT_PASSWORD="v01c3b0t"
|
||||
export VOICEBOT_INSECURE="false"
|
||||
exec uv run uvicorn main:uvicorn_app \
|
||||
--host 0.0.0.0 \
|
||||
--port 8789 \
|
||||
|
@ -13,11 +13,17 @@ import os
|
||||
# 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 logger for reload debugging
|
||||
from logger import logger
|
||||
|
||||
from voicebot.models import VoicebotArgs, VoicebotMode
|
||||
from voicebot.client_main import main_with_args, start_client_with_reload
|
||||
from voicebot.bot_orchestrator import start_bot_provider
|
||||
from voicebot.client_app import get_app
|
||||
|
||||
# Log module import for debugging reloads
|
||||
logger.info("📦 Main module imported/reloaded")
|
||||
|
||||
# Create app instance for uvicorn import
|
||||
uvicorn_app = get_app()
|
||||
|
||||
@ -27,7 +33,7 @@ async def main():
|
||||
parser = argparse.ArgumentParser(description="Python WebRTC voicebot client")
|
||||
parser.add_argument(
|
||||
"--server-url",
|
||||
default="http://localhost:8000/ai-voicebot",
|
||||
default="https://server:8000/ai-voicebot",
|
||||
help="AI-Voicebot lobby and signaling server base URL (http:// or https://)",
|
||||
)
|
||||
parser.add_argument(
|
||||
|
@ -58,13 +58,13 @@ class VoicebotArgs(BaseModel):
|
||||
host=os.getenv('VOICEBOT_HOST', '0.0.0.0'),
|
||||
port=int(os.getenv('VOICEBOT_PORT', '8788')),
|
||||
reload=os.getenv('VOICEBOT_RELOAD', 'false').lower() == 'true',
|
||||
server_url=os.getenv('VOICEBOT_SERVER_URL', 'http://localhost:8000/ai-voicebot'),
|
||||
server_url=os.getenv('VOICEBOT_SERVER_URL', 'https://server:8000/ai-voicebot'),
|
||||
lobby=os.getenv('VOICEBOT_LOBBY', 'default'),
|
||||
session_name=os.getenv('VOICEBOT_SESSION_NAME', 'Python Bot'),
|
||||
session_id=os.getenv('VOICEBOT_SESSION_ID', None),
|
||||
password=os.getenv('VOICEBOT_PASSWORD', None),
|
||||
private=os.getenv('VOICEBOT_PRIVATE', 'false').lower() == 'true',
|
||||
insecure=os.getenv('VOICEBOT_INSECURE', 'false').lower() == 'true',
|
||||
insecure=os.getenv('VOICEBOT_SERVER_INSECURE', 'false').lower() == 'true',
|
||||
registration_check_interval=float(os.getenv('VOICEBOT_REGISTRATION_CHECK_INTERVAL', '30.0'))
|
||||
)
|
||||
|
||||
|
@ -58,6 +58,17 @@ from voicebot.models import Peer, MessageData
|
||||
from voicebot.utils import create_ssl_context, log_network_info
|
||||
|
||||
|
||||
def _convert_http_to_ws_url(url: str) -> str:
|
||||
"""Convert HTTP/HTTPS URL to WebSocket URL by replacing scheme."""
|
||||
if url.startswith("https://"):
|
||||
return url.replace("https://", "wss://", 1)
|
||||
elif url.startswith("http://"):
|
||||
return url.replace("http://", "ws://", 1)
|
||||
else:
|
||||
# Assume it's already a WebSocket URL
|
||||
return url
|
||||
|
||||
|
||||
class WebSocketProtocol(Protocol):
|
||||
def send(self, message: object, text: Optional[bool] = None) -> Awaitable[None]: ...
|
||||
def close(self, code: int = 1000, reason: str = "") -> Awaitable[None]: ...
|
||||
@ -93,7 +104,7 @@ class WebRTCSignalingClient:
|
||||
self.websocket: Optional[object] = None
|
||||
|
||||
# Optional password to register or takeover a name
|
||||
self.name_password: Optional[str] = None
|
||||
self.name_password: Optional[str] = session_name
|
||||
|
||||
self.peers: dict[str, Peer] = {}
|
||||
self.peer_connections: dict[str, RTCPeerConnection] = {}
|
||||
@ -120,18 +131,29 @@ class WebRTCSignalingClient:
|
||||
|
||||
async def connect(self):
|
||||
"""Connect to the signaling server"""
|
||||
ws_url = f"{self.server_url}/ws/lobby/{self.lobby_id}/{self.session_id}"
|
||||
base_ws_url = _convert_http_to_ws_url(self.server_url)
|
||||
ws_url = f"{base_ws_url}/ws/lobby/{self.lobby_id}/{self.session_id}"
|
||||
logger.info(f"Connecting to signaling server: {ws_url}")
|
||||
|
||||
# Log network information for debugging
|
||||
log_network_info()
|
||||
|
||||
try:
|
||||
# If insecure (self-signed certs), create an SSL context for the websocket
|
||||
ws_ssl = create_ssl_context(self.insecure)
|
||||
# Create SSL context based on URL scheme and insecure setting
|
||||
if ws_url.startswith("wss://"):
|
||||
# For wss://, we need an SSL context
|
||||
if self.insecure:
|
||||
# Accept self-signed certificates
|
||||
ws_ssl = create_ssl_context(insecure=True)
|
||||
else:
|
||||
# Use default SSL context for secure connections
|
||||
ws_ssl = True
|
||||
else:
|
||||
# For ws://, no SSL context needed
|
||||
ws_ssl = None
|
||||
|
||||
logger.info(
|
||||
f"Attempting websocket connection to {ws_url} with ssl={bool(ws_ssl)}"
|
||||
f"Attempting websocket connection to {ws_url} with ssl={ws_ssl}"
|
||||
)
|
||||
self.websocket = await websockets.connect(ws_url, ssl=ws_ssl)
|
||||
logger.info("Connected to signaling server")
|
||||
@ -263,10 +285,21 @@ class WebRTCSignalingClient:
|
||||
self.websocket = None
|
||||
|
||||
# Reconnect
|
||||
ws_url = f"{self.server_url}/ws/lobby/{self.lobby_id}/{self.session_id}"
|
||||
base_ws_url = _convert_http_to_ws_url(self.server_url)
|
||||
ws_url = f"{base_ws_url}/ws/lobby/{self.lobby_id}/{self.session_id}"
|
||||
|
||||
# If insecure (self-signed certs), create an SSL context for the websocket
|
||||
ws_ssl = create_ssl_context(self.insecure)
|
||||
# Create SSL context based on URL scheme and insecure setting
|
||||
if ws_url.startswith("wss://"):
|
||||
# For wss://, we need an SSL context
|
||||
if self.insecure:
|
||||
# Accept self-signed certificates
|
||||
ws_ssl = create_ssl_context(insecure=True)
|
||||
else:
|
||||
# Use default SSL context for secure connections
|
||||
ws_ssl = True
|
||||
else:
|
||||
# For ws://, no SSL context needed
|
||||
ws_ssl = None
|
||||
|
||||
logger.info(f"Reconnecting to signaling server: {ws_url}")
|
||||
self.websocket = await websockets.connect(ws_url, ssl=ws_ssl)
|
||||
@ -377,7 +410,13 @@ class WebRTCSignalingClient:
|
||||
async def _process_message(self, message: MessageData):
|
||||
"""Process incoming signaling messages"""
|
||||
try:
|
||||
# Validate the base message structure first
|
||||
# Handle error messages specially since they have a different structure
|
||||
if message.get("type") == "error" and "error" in message:
|
||||
error_msg = message.get("error", "Unknown error")
|
||||
logger.error(f"Received error from signaling server: {error_msg}")
|
||||
return
|
||||
|
||||
# Validate the base message structure for non-error messages
|
||||
validated_message = WebSocketMessageModel.model_validate(message)
|
||||
msg_type = validated_message.type
|
||||
data = validated_message.data
|
||||
@ -448,6 +487,10 @@ class WebRTCSignalingClient:
|
||||
logger.error(f"Invalid update payload: {e}", exc_info=True)
|
||||
return
|
||||
logger.info(f"Received update message: {validated}")
|
||||
elif msg_type == "status_check":
|
||||
# Handle status check messages - these are used to verify connection
|
||||
logger.debug(f"Received status check message: {data}")
|
||||
# No special processing needed for status checks, just acknowledge receipt
|
||||
else:
|
||||
logger.info(f"Unhandled message type: {msg_type} with data: {data}")
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user