← Cloudflare Realtime / realtime / realtimekit / core
Waiting Room
Функция зала ожидания позволяет организаторам контролировать, кто может присоединиться к встрече. Когда она включена, участники должны дождаться одобрения, прежде чем войти во встречу.
Как работает зал ожидания
После вызова meeting.join(), произойдёт одно из двух событий:
roomJoined- Вам разрешено немедленно присоединиться к встречеwaitlisted- Вы помещены в зал ожидания и должны дождаться одобрения организатора
Используйте meeting.self.roomState для отслеживания состояния пользователя во встрече.
Состояния зала ожидания
Поток состояний
join()
↓
[waitlisted] ←------ (host rejects)
↓ ↓
(host accepts) [rejected]
↓
[joined]Отслеживание изменений состояния
Событие присоединения
Срабатывает, когда локальный пользователь успешно присоединяется к встрече.
Отслеживайте, когда локальный пользователь присоединяется к встрече:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react";
import { useEffect } from "react";
function MeetingStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const joined = roomState === "joined";
useEffect(() => {
if (joined) {
console.log("Successfully joined the meeting");
}
}, [joined]);
return joined ? <div>You are in the meeting</div> : null;
}Как вариант, используйте обработчики событий:
import { useRealtimeKitClient } from "@cloudflare/realtimekit-react";
useEffect(() => {
if (!meeting) return;
const handleRoomJoined = () => {
console.log("Successfully joined the meeting");
};
meeting.self.on("roomJoined", handleRoomJoined);
return () => {
meeting.self.off("roomJoined", handleRoomJoined);
};
}, [meeting]);meeting.self.on("roomJoined", () => {
// Local user is in the meeting
console.log("Successfully joined the meeting");
});meeting.addMeetingRoomEventListener(object : RtkMeetingRoomEventListener {
override fun onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) {
// Local user is in the meeting
}
})extension MeetingViewModel: RtkMeetingRoomEventListener {
func onMeetingRoomJoinCompleted(meeting: RealtimeKitClient) {
// Local user is in the meeting
}
}Отслеживайте, когда локальный пользователь присоединяется к встрече:
import { useRealtimeKitSelector } from "@cloudflare/realtimekit-react-native";
import { useEffect } from "react";
function MeetingStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const joined = roomState === "joined";
useEffect(() => {
if (joined) {
console.log("Successfully joined the meeting");
}
}, [joined]);
return joined ? <Text>You are in the meeting</Text> : null;
}Как вариант, используйте обработчики событий:
import { useRealtimeKitClient } from "@cloudflare/realtimekit-react-native";
useEffect(() => {
if (!meeting) return;
const handleRoomJoined = () => {
console.log("Successfully joined the meeting");
};
meeting.self.on("roomJoined", handleRoomJoined);
return () => {
meeting.self.off("roomJoined", handleRoomJoined);
};
}, [meeting]);Waitlisted Event
Срабатывает, когда локальный пользователь помещается в зал ожидания.
Отслеживайте, когда локальный пользователь находится в зале ожидания:
function WaitingRoomStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const isWaitlisted = roomState === "waitlisted";
useEffect(() => {
if (isWaitlisted) {
console.log("You are in the waiting room");
}
}, [isWaitlisted]);
return isWaitlisted ? <div>Waiting for host approval...</div> : null;
}Как вариант, используйте обработчики событий:
useEffect(() => {
if (!meeting) return;
const handleWaitlisted = () => {
console.log("You are in the waiting room");
};
meeting.self.on("waitlisted", handleWaitlisted);
return () => {
meeting.self.off("waitlisted", handleWaitlisted);
};
}, [meeting]);meeting.self.on("waitlisted", () => {
// Local user is waitlisted
console.log("You are in the waiting room. Waiting for host approval...");
});meeting.addSelfEventListener(object : RtkSelfEventListener {
override fun onWaitListStatusUpdate(waitListStatus: WaitListStatus) {
when (waitListStatus) {
WAITING -> {
// Local user is in the waiting room
}
REJECTED -> {
// Local user's join room request was rejected by the host
}
NONE, ACCEPTED -> {
// Local user is not in the wait list or was already accepted
}
}
}
})extension MeetingViewModel: RtkSelfEventListener {
func onWaitListStatusUpdate(waitListStatus: WaitListStatus) {
switch waitListStatus {
case .accepted:
// Local user's join room request was accepted by the host
case .waiting:
// Local user is in the waiting room
case .rejected:
// Local user's join room request was rejected by the host
default:
return .none
}
}
}Отслеживайте, когда локальный пользователь находится в зале ожидания:
function WaitingRoomStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const isWaitlisted = roomState === "waitlisted";
useEffect(() => {
if (isWaitlisted) {
console.log("You are in the waiting room");
}
}, [isWaitlisted]);
return isWaitlisted ? <Text>Waiting for host approval...</Text> : null;
}Как вариант, используйте обработчики событий:
useEffect(() => {
if (!meeting) return;
const handleWaitlisted = () => {
console.log("You are in the waiting room");
};
meeting.self.on("waitlisted", handleWaitlisted);
return () => {
meeting.self.off("waitlisted", handleWaitlisted);
};
}, [meeting]);Событие Rejected
Срабатывает, когда организатор отклоняет запрос на вход.
Отслеживайте, когда организатор отклоняет запрос на вход:
function RejectionStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const rejected = roomState === "rejected";
useEffect(() => {
if (rejected) {
console.log("Your entry request was rejected");
}
}, [rejected]);
return rejected ? <div>Your entry was rejected by the host</div> : null;
}Как вариант, используйте обработчики событий:
useEffect(() => {
if (!meeting) return;
const handleRoomLeft = ({ state }) => {
if (state === "rejected") {
console.log("Your entry request was rejected");
}
};
meeting.self.on("roomLeft", handleRoomLeft);
return () => {
meeting.self.off("roomLeft", handleRoomLeft);
};
}, [meeting]);meeting.self.on("roomLeft", ({ state }) => {
if (state === "rejected") {
// Host rejected the entry
console.log("Your entry request was rejected");
}
});Когда организатор отклоняет запрос на вход, onWaitListStatusUpdate колбэк вызывается с WaitListStatus.REJECTED:
meeting.addSelfEventListener(object : RtkSelfEventListener {
override fun onWaitListStatusUpdate(waitListStatus: WaitListStatus) {
when (waitListStatus) {
WaitListStatus.REJECTED -> {
// Local user's join room request was rejected by the host
Log.d("WaitingRoom", "Your entry request was rejected")
}
WaitListStatus.WAITING -> {
// Local user is in the waiting room
}
WaitListStatus.ACCEPTED, WaitListStatus.NONE -> {
// Local user was accepted or not in waitlist
}
}
}
})Когда организатор отклоняет запрос на вход, onWaitListStatusUpdate колбэк вызывается с WaitListStatus.rejected:
extension MeetingViewModel: RtkSelfEventListener {
func onWaitListStatusUpdate(waitListStatus: WaitListStatus) {
switch waitListStatus {
case .rejected:
// Local user's join room request was rejected by the host
print("Your entry request was rejected")
case .waiting:
// Local user is in the waiting room
break
case .accepted:
// Local user's join room request was accepted by the host
break
default:
break
}
}
}Отслеживайте, когда организатор отклоняет запрос на вход:
function RejectionStatus() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
const rejected = roomState === "rejected";
useEffect(() => {
if (rejected) {
console.log("Your entry request was rejected");
}
}, [rejected]);
return rejected ? <Text>Your entry was rejected by the host</Text> : null;
}Как вариант, используйте обработчики событий:
useEffect(() => {
if (!meeting) return;
const handleRoomLeft = ({ state }) => {
if (state === "rejected") {
console.log("Your entry request was rejected");
}
};
meeting.self.on("roomLeft", handleRoomLeft);
return () => {
meeting.self.off("roomLeft", handleRoomLeft);
};
}, [meeting]);Отслеживание состояния через roomState
Также можно напрямую проверить текущее состояние комнаты.
Обработка всех состояний зала ожидания в одном компоненте:
function WaitingRoomManager() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
switch (roomState) {
case "init":
return <div>Connecting...</div>;
case "waitlisted":
return <div>Waiting for host approval...</div>;
case "joined":
return <div>You are in the meeting</div>;
case "rejected":
return <div>Your entry was rejected</div>;
case "left":
return <div>You left the meeting</div>;
case "kicked":
return <div>You were removed from the meeting</div>;
case "ended":
return <div>The meeting has ended</div>;
case "disconnected":
return <div>Connection lost</div>;
default:
return null;
}
}const currentState = meeting.self.roomState;
if (currentState === "waitlisted") {
console.log("Waiting for approval");
} else if (currentState === "joined") {
console.log("In the meeting");
} else if (currentState === "rejected") {
console.log("Entry was rejected");
}Используйте показанные выше обработчики событий, чтобы отслеживать изменения состояния.
Используйте показанные выше обработчики событий, чтобы отслеживать изменения состояния.
Обработка всех состояний зала ожидания в одном компоненте:
function WaitingRoomManager() {
const roomState = useRealtimeKitSelector((m) => m.self.roomState);
switch (roomState) {
case "init":
return <Text>Connecting...</Text>;
case "waitlisted":
return <Text>Waiting for host approval...</Text>;
case "joined":
return <Text>You are in the meeting</Text>;
case "rejected":
return <Text>Your entry was rejected</Text>;
case "left":
return <Text>You left the meeting</Text>;
case "kicked":
return <Text>You were removed from the meeting</Text>;
case "ended":
return <Text>The meeting has ended</Text>;
case "disconnected":
return <Text>Connection lost</Text>;
default:
return null;
}
}Действия организатора
Организаторы могут управлять запросами на вход в зал ожидания с помощью методов управления участниками. См. Удалённые участники подробнее о:
acceptWaitingRoomRequest(participantId)- Принять участника из зала ожиданияrejectWaitingRoomRequest(participantId)- Отклоните запрос участника на вход
Пример: хост принимает участников
import {
useRealtimeKitClient,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react";
function WaitingRoomHost() {
const [meeting] = useRealtimeKitClient();
const waitlistedParticipants = useRealtimeKitSelector((m) =>
m.participants.waitlisted.toArray(),
);
const acceptParticipant = async (participantId) => {
await meeting.participants.acceptWaitingRoomRequest(participantId);
};
const rejectParticipant = async (participantId) => {
await meeting.participants.rejectWaitingRoomRequest(participantId);
};
return (
<div>
<h3>Waiting Room ({waitlistedParticipants.length})</h3>
{waitlistedParticipants.map((participant) => (
<div key={participant.id}>
<span>{participant.name}</span>
<button onClick={() => acceptParticipant(participant.id)}>
Accept
</button>
<button onClick={() => rejectParticipant(participant.id)}>
Reject
</button>
</div>
))}
</div>
);
}// Get waitlisted participants
const waitlistedParticipants = meeting.participants.waitlisted.toArray();
// Accept the first waitlisted participant
if (waitlistedParticipants.length > 0) {
const participantId = waitlistedParticipants[0].id;
await meeting.participants.acceptWaitingRoomRequest(participantId);
}// Get waitlisted participants
val waitlistedParticipants = meeting.participants.waitlisted
// Accept a participant from the waiting room
if (waitlistedParticipants.isNotEmpty()) {
val participant = waitlistedParticipants[0]
meeting.participants.acceptWaitingRoomRequest(participant.id)
}
// Reject a participant's entry request
if (waitlistedParticipants.isNotEmpty()) {
val participant = waitlistedParticipants[0]
meeting.participants.rejectWaitingRoomRequest(participant.id)
}
// Listen for waiting room events
meeting.addWaitlistEventListener(object : RtkWaitlistEventListener {
override fun onWaitListParticipantJoined(participant: RtkRemoteParticipant) {
// Called when a new participant joins the waiting room
}
override fun onWaitListParticipantAccepted(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant is accepted into the meeting
}
override fun onWaitListParticipantRejected(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant is denied entry
}
override fun onWaitListParticipantClosed(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant leaves the waiting room
}
})// Get waitlisted participants
let waitlistedParticipants = meeting.participants.waitlisted
// Accept a participant from the waiting room
if let participant = waitlistedParticipants.first {
meeting.participants.acceptWaitingRoomRequest(id: participant.id)
}
// Reject a participant's entry request
if let participant = waitlistedParticipants.first {
meeting.participants.rejectWaitingRoomRequest(participant.id)
}
// Listen for waiting room events
extension MeetingViewModel: RtkWaitlistEventListener {
func onWaitListParticipantJoined(participant: RtkRemoteParticipant) {
// Called when a new participant joins the waiting room
}
func onWaitListParticipantAccepted(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant is accepted into the meeting
}
func onWaitListParticipantRejected(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant is denied entry
}
func onWaitListParticipantClosed(participant: RtkRemoteParticipant) {
// Called when a waitlisted participant leaves the waiting room
}
}import {
useRealtimeKitClient,
useRealtimeKitSelector,
} from "@cloudflare/realtimekit-react-native";
import { View, Text, Button } from "react-native";
function WaitingRoomHost() {
const [meeting] = useRealtimeKitClient();
const waitlistedParticipants = useRealtimeKitSelector((m) =>
m.participants.waitlisted.toArray(),
);
const acceptParticipant = async (participantId) => {
await meeting.participants.acceptWaitingRoomRequest(participantId);
};
const rejectParticipant = async (participantId) => {
await meeting.participants.rejectWaitingRoomRequest(participantId);
};
return (
<View>
<Text>Waiting Room ({waitlistedParticipants.length})</Text>
{waitlistedParticipants.map((participant) => (
<View key={participant.id}>
<Text>{participant.name}</Text>
<Button
title="Accept"
onPress={() => acceptParticipant(participant.id)}
/>
<Button
title="Reject"
onPress={() => rejectParticipant(participant.id)}
/>
</View>
))}
</View>
);
}Лучшие практики
- Давайте чёткую обратную связь - Покажите пользователям, что они находятся в зале ожидания и ждут одобрения
- Определение ожиданий - Сообщите пользователям, что их запрос рассматривается
- Корректная обработка отказа - Укажите дружелюбное сообщение на случай отказа во входе
- Отслеживание изменений состояния - Подпишитесь на изменения состояния зала, чтобы соответствующим образом обновлять интерфейс
- Проверьте разрешения - Убедитесь, что в пресете вашего приложения настроены необходимые разрешения для использования функций зала ожидания