Предварительная работа для очереди рук и принудительного мьюта (B1/B2): build_join кладёт is_organizer:true в метаданные токена организатора (создатель мгновенной конференции и владелец при обычном входе). Метаданные токена — только подсказка для UI (см. предупреждение в докстринге build_join), любое серверное действие организатора обязано перепроверяться по conference.owner_id в БД — так и сделано в mute_participant (B2). На фронте — общий парсер метаданных участника (lib/participantMetadata.ts, переиспользован в RoomParticipantTile вместо локальной копии) и хук useIsOrganizer (читает подсказку для локального участника через useLocalParticipant — вызывается только внутри LiveKitRoom).
27 lines
1.4 KiB
TypeScript
27 lines
1.4 KiB
TypeScript
/**
|
||
* Метаданные участника из LiveKit access-токена (см. `AccessToken.with_metadata`
|
||
* на backend, `services/conference_access.py::build_join`) — JSON
|
||
* `{"avatar_url"?: string, "is_organizer"?: true}`. У гостей и участников без
|
||
* аватара/прав организатора соответствующие поля отсутствуют.
|
||
*/
|
||
export interface ParticipantMetadata {
|
||
avatar_url?: string | null
|
||
/**
|
||
* Подсказка для UI — организатор ли участник. НЕ источник авторизации:
|
||
* метаданные читает и потенциально может подделать сам клиент. Любое
|
||
* серверное действие организатора (например, принудительный мьют)
|
||
* перепроверяется backend'ом по владельцу конференции в БД.
|
||
*/
|
||
is_organizer?: boolean
|
||
}
|
||
|
||
/** Разобрать `participant.metadata` — пустой объект, если поля нет, метаданные пусты или невалидны. */
|
||
export function parseParticipantMetadata(metadata: string | undefined): ParticipantMetadata {
|
||
if (!metadata) return {}
|
||
try {
|
||
return JSON.parse(metadata) as ParticipantMetadata
|
||
} catch {
|
||
return {}
|
||
}
|
||
}
|