first commit
This commit is contained in:
commit
efa5080897
127 changed files with 18610 additions and 0 deletions
66
backend/app/voice/tunnel.py
Normal file
66
backend/app/voice/tunnel.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"""Transparent WebSocket frame relay — no parse, no audio processing."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import websockets
|
||||
from fastapi import WebSocket, WebSocketDisconnect
|
||||
from websockets.exceptions import ConnectionClosed
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def relay_text_websockets(left: WebSocket, right: WebSocket) -> None:
|
||||
stop = asyncio.Event()
|
||||
|
||||
async def forward(source: WebSocket, destination: WebSocket) -> None:
|
||||
try:
|
||||
while not stop.is_set():
|
||||
message = await source.receive_text()
|
||||
await destination.send_text(message)
|
||||
except (WebSocketDisconnect, RuntimeError):
|
||||
stop.set()
|
||||
|
||||
await asyncio.gather(forward(left, right), forward(right, left))
|
||||
|
||||
|
||||
async def relay_provider_to_upstream(
|
||||
provider: WebSocket,
|
||||
upstream_url: str,
|
||||
*,
|
||||
initial_frames: list[str] | None = None,
|
||||
additional_headers: dict[str, str] | None = None,
|
||||
) -> None:
|
||||
"""Raw carrier ↔ customer upstream tunnel."""
|
||||
logger.info("Opening upstream tunnel to %s", upstream_url)
|
||||
async with websockets.connect(
|
||||
upstream_url,
|
||||
open_timeout=10,
|
||||
close_timeout=5,
|
||||
additional_headers=additional_headers,
|
||||
ping_interval=20,
|
||||
ping_timeout=20,
|
||||
max_queue=16,
|
||||
) as upstream:
|
||||
for frame in initial_frames or []:
|
||||
await upstream.send(frame)
|
||||
|
||||
async def provider_to_upstream() -> None:
|
||||
try:
|
||||
while True:
|
||||
raw = await provider.receive_text()
|
||||
await upstream.send(raw)
|
||||
except (WebSocketDisconnect, RuntimeError):
|
||||
return
|
||||
|
||||
async def upstream_to_provider() -> None:
|
||||
try:
|
||||
while True:
|
||||
raw = await upstream.recv()
|
||||
if isinstance(raw, bytes):
|
||||
raw = raw.decode("utf-8")
|
||||
await provider.send_text(raw)
|
||||
except (ConnectionClosed, WebSocketDisconnect, RuntimeError):
|
||||
return
|
||||
|
||||
await asyncio.gather(provider_to_upstream(), upstream_to_provider())
|
||||
Loading…
Add table
Add a link
Reference in a new issue