mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Implement LiveKit calls
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
"""
|
||||
Mint LiveKit participant JWTs for DM calls. Requires LIVEKIT_API_KEY, LIVEKIT_API_SECRET,
|
||||
and LIVEKIT_URL (WebSocket URL for clients, e.g. wss://livekit.example.com or ws://host:7880).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from ..dependencies import get_current_user, get_db
|
||||
from ..models import User
|
||||
|
||||
logger = logging.getLogger("uvicorn.error")
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class LiveKitTokenRequest(BaseModel):
|
||||
peer_user_id: int = Field(..., description="The other participant (DM peer)")
|
||||
room_name: str | None = Field(
|
||||
None,
|
||||
description="Existing room from an invite; omit to create a new room",
|
||||
)
|
||||
|
||||
|
||||
class LiveKitTokenResponse(BaseModel):
|
||||
server_url: str
|
||||
token: str
|
||||
room_name: str
|
||||
|
||||
|
||||
def _livekit_env() -> tuple[str, str, str]:
|
||||
api_key = os.getenv("LIVEKIT_API_KEY", "").strip()
|
||||
api_secret = os.getenv("LIVEKIT_API_SECRET", "").strip()
|
||||
server_url = os.getenv("LIVEKIT_URL", "").strip()
|
||||
if not api_key or not api_secret or not server_url:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="LiveKit is not configured (LIVEKIT_API_KEY / LIVEKIT_API_SECRET / LIVEKIT_URL)",
|
||||
)
|
||||
return api_key, api_secret, server_url
|
||||
|
||||
|
||||
@router.post("/token", response_model=LiveKitTokenResponse)
|
||||
async def create_livekit_token(
|
||||
body: LiveKitTokenRequest,
|
||||
db: Session = Depends(get_db),
|
||||
user: User = Depends(get_current_user),
|
||||
):
|
||||
"""
|
||||
Issue a short-lived JWT for joining a 1:1 call room with peer_user_id.
|
||||
"""
|
||||
if body.peer_user_id == user.id:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="peer_user_id must differ from caller")
|
||||
|
||||
peer = db.query(User).filter(User.id == body.peer_user_id).first()
|
||||
if not peer:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Peer user not found")
|
||||
|
||||
api_key, api_secret, server_url = _livekit_env()
|
||||
|
||||
if body.room_name and body.room_name.strip():
|
||||
room_name = body.room_name.strip()
|
||||
else:
|
||||
room_name = f"call-{uuid.uuid4().hex}"
|
||||
|
||||
try:
|
||||
from livekit.api import AccessToken, VideoGrants
|
||||
except ImportError as e:
|
||||
logger.exception("livekit-api not installed")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail="LiveKit SDK unavailable on server",
|
||||
) from e
|
||||
|
||||
grants = VideoGrants(
|
||||
room_join=True,
|
||||
room=room_name,
|
||||
can_publish=True,
|
||||
can_subscribe=True,
|
||||
can_publish_data=True,
|
||||
)
|
||||
|
||||
token = (
|
||||
AccessToken(api_key, api_secret)
|
||||
.with_identity(str(user.id))
|
||||
.with_name(user.username or str(user.id))
|
||||
.with_ttl(timedelta(hours=1))
|
||||
.with_grants(grants)
|
||||
)
|
||||
|
||||
jwt_token = token.to_jwt()
|
||||
|
||||
return LiveKitTokenResponse(server_url=server_url, token=jwt_token, room_name=room_name)
|
||||
@@ -46,10 +46,12 @@ os.makedirs(FILES_ENCRYPTED_DIR, exist_ok=True)
|
||||
|
||||
|
||||
def _get_file_storage_url() -> str:
|
||||
lan = os.getenv("LAN_IP", "").strip()
|
||||
default_fs = f"http://{lan}:8302" if lan else "http://127.0.0.1:8302"
|
||||
return (
|
||||
os.getenv("FILE_STORAGE_SERVICE_URL")
|
||||
or os.getenv("FILE_STORAGE_URL")
|
||||
or "http://127.0.0.1:8302"
|
||||
or default_fs
|
||||
)
|
||||
|
||||
_SPAM_WINDOW_SECONDS = 45
|
||||
|
||||
Reference in New Issue
Block a user