fix: change livkit udp ports and add ttl for livekit token

This commit is contained in:
roai_linux 2026-03-29 16:35:10 +03:30
parent 6d687e7361
commit 720f8e6b7c
5 changed files with 143 additions and 4 deletions

View File

@ -38,5 +38,5 @@ class RateLimiter:
# But Starlette's HTTPException is also handled by FastAPI for WebSockets by closing the connection. # But Starlette's HTTPException is also handled by FastAPI for WebSockets by closing the connection.
raise HTTPException( raise HTTPException(
status_code=status.HTTP_429_TOO_MANY_REQUESTS, status_code=status.HTTP_429_TOO_MANY_REQUESTS,
detail="Too many requests. Please try again later." detail="تعداد درخواست‌های شما از حد مجاز گذشته است. لطفاً بعداً دوباره تلاش کنید."
) )

View File

@ -42,7 +42,7 @@ services:
ports: ports:
- "7780:7880" - "7780:7880"
- "7781:7881" - "7781:7881"
- "51000-51100:51000-51100/udp" - "51000-52000:51000-52000/udp"
env_file: env_file:
- .env - .env
volumes: volumes:

View File

@ -1,7 +1,7 @@
from livekit import api from livekit import api
from core.config import settings from core.config import settings
from datetime import timedelta
def generate_join_token( def generate_join_token(
user_id: str, user_id: str,
@ -15,6 +15,7 @@ def generate_join_token(
) )
token.with_identity(user_id) token.with_identity(user_id)
token.with_ttl(timedelta(hours=2))
token.with_grants( token.with_grants(
api.VideoGrants( api.VideoGrants(

View File

@ -3,7 +3,7 @@ port: 7880
rtc: rtc:
tcp_port: 7881 tcp_port: 7881
port_range_start: 51000 port_range_start: 51000
port_range_end: 51100 port_range_end: 52000
use_external_ip: false use_external_ip: false
# node_ip: "94.183.170.121" # node_ip: "94.183.170.121"

View File

@ -102,7 +102,145 @@ def test_group_routes_are_namespaced():
} }
assert ("/groups/", "POST") in route_map assert ("/groups/", "POST") in route_map
assert ("/groups/{group_id}/members/{user_id}", "DELETE") in route_map
assert ("/admin/groups/", "POST") in route_map assert ("/admin/groups/", "POST") in route_map
assert ("/admin/groups/", "GET") in route_map assert ("/admin/groups/", "GET") in route_map
assert ("/admin/groups/{group_id}/members", "GET") in route_map assert ("/admin/groups/{group_id}/members", "GET") in route_map
assert ("/admin/groups/{group_id}/members", "POST") in route_map assert ("/admin/groups/{group_id}/members", "POST") in route_map
@pytest.mark.asyncio
async def test_remove_member_from_group_allows_manager_to_remove_member(monkeypatch):
db = object()
group_id = uuid.uuid4()
manager_id = uuid.uuid4()
member_id = uuid.uuid4()
group = SimpleNamespace(owner_id=uuid.uuid4())
removed = AsyncMock()
async def fake_get_group_member(db, requested_group_id, requested_user_id):
if requested_user_id == manager_id:
return SimpleNamespace(role=GroupMemberRole.MANAGER)
if requested_user_id == member_id:
return SimpleNamespace(role=GroupMemberRole.MEMBER)
return None
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(service, "get_group_member", fake_get_group_member)
monkeypatch.setattr(service, "delete_group_member", removed)
requester = SimpleNamespace(id=manager_id, is_admin=False)
await service.remove_member_from_group(db, group_id, member_id, requester)
removed.assert_awaited_once_with(db, group_id, member_id)
@pytest.mark.asyncio
async def test_remove_member_from_group_rejects_non_manager(monkeypatch):
group_id = uuid.uuid4()
requester_id = uuid.uuid4()
member_id = uuid.uuid4()
group = SimpleNamespace(owner_id=uuid.uuid4())
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(
service,
"get_group_member",
AsyncMock(return_value=SimpleNamespace(role=GroupMemberRole.MEMBER)),
)
monkeypatch.setattr(service, "delete_group_member", AsyncMock())
requester = SimpleNamespace(id=requester_id, is_admin=False)
with pytest.raises(PermissionError, match="دسترسی لازم را ندارید"):
await service.remove_member_from_group(object(), group_id, member_id, requester)
@pytest.mark.asyncio
async def test_remove_member_from_group_rejects_owner_removal(monkeypatch):
group_id = uuid.uuid4()
manager_id = uuid.uuid4()
owner_id = uuid.uuid4()
group = SimpleNamespace(owner_id=owner_id)
async def fake_get_group_member(db, requested_group_id, requested_user_id):
if requested_user_id == manager_id:
return SimpleNamespace(role=GroupMemberRole.MANAGER)
return SimpleNamespace(role=GroupMemberRole.MEMBER)
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(service, "get_group_member", fake_get_group_member)
monkeypatch.setattr(service, "delete_group_member", AsyncMock())
requester = SimpleNamespace(id=manager_id, is_admin=False)
with pytest.raises(ValueError, match="حذف سازنده گروه مجاز نیست"):
await service.remove_member_from_group(object(), group_id, owner_id, requester)
@pytest.mark.asyncio
async def test_remove_member_from_group_rejects_missing_target_membership(monkeypatch):
group_id = uuid.uuid4()
manager_id = uuid.uuid4()
member_id = uuid.uuid4()
group = SimpleNamespace(owner_id=uuid.uuid4())
async def fake_get_group_member(db, requested_group_id, requested_user_id):
if requested_user_id == manager_id:
return SimpleNamespace(role=GroupMemberRole.MANAGER)
return None
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(service, "get_group_member", fake_get_group_member)
monkeypatch.setattr(service, "delete_group_member", AsyncMock())
requester = SimpleNamespace(id=manager_id, is_admin=False)
with pytest.raises(ValueError, match="کاربر عضو این گروه نیست"):
await service.remove_member_from_group(object(), group_id, member_id, requester)
@pytest.mark.asyncio
async def test_remove_member_from_group_rejects_manager_target_for_non_admin(monkeypatch):
group_id = uuid.uuid4()
manager_id = uuid.uuid4()
other_manager_id = uuid.uuid4()
group = SimpleNamespace(owner_id=uuid.uuid4())
async def fake_get_group_member(db, requested_group_id, requested_user_id):
if requested_user_id == manager_id:
return SimpleNamespace(role=GroupMemberRole.MANAGER)
if requested_user_id == other_manager_id:
return SimpleNamespace(role=GroupMemberRole.MANAGER)
return None
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(service, "get_group_member", fake_get_group_member)
monkeypatch.setattr(service, "delete_group_member", AsyncMock())
requester = SimpleNamespace(id=manager_id, is_admin=False)
with pytest.raises(ValueError, match="حذف مدیر گروه مجاز نیست"):
await service.remove_member_from_group(object(), group_id, other_manager_id, requester)
@pytest.mark.asyncio
async def test_remove_member_from_group_allows_admin_to_remove_manager(monkeypatch):
db = object()
group_id = uuid.uuid4()
target_manager_id = uuid.uuid4()
group = SimpleNamespace(owner_id=uuid.uuid4())
removed = AsyncMock()
monkeypatch.setattr(service, "get_group_by_id", AsyncMock(return_value=group))
monkeypatch.setattr(
service,
"get_group_member",
AsyncMock(return_value=SimpleNamespace(role=GroupMemberRole.MANAGER)),
)
monkeypatch.setattr(service, "delete_group_member", removed)
requester = SimpleNamespace(id=uuid.uuid4(), is_admin=True)
await service.remove_member_from_group(db, group_id, target_manager_id, requester)
removed.assert_awaited_once_with(db, group_id, target_manager_id)