Repository navigation
Chore/videocall #173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chore/videocall #173
Changes from all commits
d5001d2
0499894
219c4c8
a5d06fb
215097a
78a2b5a
2b39e9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -117,6 +117,23 @@ export default function VideoCall() { | |||||||||||||||||||||
| const [_matchedUserId, setMatchedUserId] = useState<string | null>(null); | ||||||||||||||||||||||
| const [gatewayRoomId, setGatewayRoomId] = useState<string | null>(null); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const [isLiked, setIsLiked] = useState(false); | ||||||||||||||||||||||
| const [receivedLike, setReceivedLike] = useState(false); | ||||||||||||||||||||||
| const [mutualLike, setMutualLike] = useState(false); | ||||||||||||||||||||||
| const chatRoomIdRef = useRef<string | null>(null); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| if (!receivedLike) return; | ||||||||||||||||||||||
| const t = setTimeout(() => setReceivedLike(false), 5000); | ||||||||||||||||||||||
| return () => clearTimeout(t); | ||||||||||||||||||||||
| }, [receivedLike]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| if (!mutualLike) return; | ||||||||||||||||||||||
| const t = setTimeout(() => setMutualLike(false), 4000); | ||||||||||||||||||||||
| return () => clearTimeout(t); | ||||||||||||||||||||||
| }, [mutualLike]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const matchmakingSocketRef = useRef<Socket | null>(null); | ||||||||||||||||||||||
| const stopTracksRef = useRef<() => void>(() => {}); | ||||||||||||||||||||||
| const connectingIntentRef = useRef(false); | ||||||||||||||||||||||
|
|
@@ -462,6 +479,7 @@ export default function VideoCall() { | |||||||||||||||||||||
| await createRecvTransport(device); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const socket: Socket = io(BASE_URL, { | ||||||||||||||||||||||
| auth: { token }, | ||||||||||||||||||||||
| query: { peerId: peerIdRef.current, roomId: currentRoomId }, | ||||||||||||||||||||||
| transports: ["websocket"], | ||||||||||||||||||||||
| forceNew: true, | ||||||||||||||||||||||
|
|
@@ -484,6 +502,20 @@ export default function VideoCall() { | |||||||||||||||||||||
| }, | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| socket.on("receive_like", () => { | ||||||||||||||||||||||
| setReceivedLike(true); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| socket.on("mutual_like", ({ chatRoomId: id }: { chatRoomId: string }) => { | ||||||||||||||||||||||
| setMutualLike(true); | ||||||||||||||||||||||
| setReceivedLike(false); | ||||||||||||||||||||||
| chatRoomIdRef.current = id; | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| socket.on("peer_left", () => { | ||||||||||||||||||||||
| handleNextUserRef.current(); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| await new Promise<void>((resolve) => { | ||||||||||||||||||||||
| if (socket.connected) resolve(); | ||||||||||||||||||||||
| else socket.once("connect", () => resolve()); | ||||||||||||||||||||||
|
|
@@ -504,6 +536,7 @@ export default function VideoCall() { | |||||||||||||||||||||
| } | ||||||||||||||||||||||
| }, [ | ||||||||||||||||||||||
| screen, | ||||||||||||||||||||||
| token, | ||||||||||||||||||||||
| api, | ||||||||||||||||||||||
| consumeProducer, | ||||||||||||||||||||||
| createRecvTransport, | ||||||||||||||||||||||
|
|
@@ -556,6 +589,12 @@ export default function VideoCall() { | |||||||||||||||||||||
| body: JSON.stringify({ peerId: peerIdRef.current }), | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| await api("/matchmaking/decline", { | ||||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||||
| body: JSON.stringify({ roomId: currentRoomId }), | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| try { | ||||||||||||||||||||||
|
|
@@ -584,6 +623,10 @@ export default function VideoCall() { | |||||||||||||||||||||
| setMatchedUserId(null); | ||||||||||||||||||||||
| setMatchState("idle"); | ||||||||||||||||||||||
| setMatchmakingReady(false); | ||||||||||||||||||||||
| setIsLiked(false); | ||||||||||||||||||||||
| setReceivedLike(false); | ||||||||||||||||||||||
| setMutualLike(false); | ||||||||||||||||||||||
| chatRoomIdRef.current = null; | ||||||||||||||||||||||
| roomIdRef.current = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| matchmakingSocketRef.current?.disconnect(); | ||||||||||||||||||||||
|
|
@@ -611,6 +654,16 @@ export default function VideoCall() { | |||||||||||||||||||||
| [api, log], | ||||||||||||||||||||||
| ); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const stopCallRef = useRef(stopCall); | ||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| stopCallRef.current = stopCall; | ||||||||||||||||||||||
| }, [stopCall]); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const handleNextUserRef = useRef<() => Promise<void>>(async () => {}); | ||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||
| handleNextUserRef.current = handleNextUser; | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| const handleStartConnecting = useCallback( | ||||||||||||||||||||||
| async (_camera: string, _mic: string, _interests: string[]) => { | ||||||||||||||||||||||
| connectingIntentRef.current = true; | ||||||||||||||||||||||
|
|
@@ -702,10 +755,90 @@ export default function VideoCall() { | |||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| function handleLike() { | ||||||||||||||||||||||
| Alert.alert("Liked", "User wurde geliked."); | ||||||||||||||||||||||
| if (isLiked) return; | ||||||||||||||||||||||
| socketRef.current?.emit("send_like"); | ||||||||||||||||||||||
| setIsLiked(true); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| function handleLikeBack() { | ||||||||||||||||||||||
| console.log("[LikeBack] User liked back in room:", roomIdRef.current); | ||||||||||||||||||||||
| socketRef.current?.emit("send_like_back"); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
Comment on lines
+686
to
+689
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make Unlike Suggested fix function handleLikeBack() {
- console.log("[LikeBack] User liked back in room:", roomIdRef.current);
- socketRef.current?.emit("send_like_back");
+ if (isLiked || mutualLike) return;
+ setIsLiked(true);
+ setReceivedLike(false);
+ socketRef.current?.emit("send_like_back");
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| function handleNextUser() { | ||||||||||||||||||||||
| Alert.alert("Next user", "Hier kannst du den nächsten Match laden."); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| async function handleNextUser() { | ||||||||||||||||||||||
| const roomId = roomIdRef.current; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Decline current match so these two users won't match again | ||||||||||||||||||||||
| if (roomId) { | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| await api("/matchmaking/decline", { | ||||||||||||||||||||||
| method: "POST", | ||||||||||||||||||||||
| body: JSON.stringify({ roomId }), | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Clean up video session without touching the matchmaking socket | ||||||||||||||||||||||
| localStreamRef.current?.getTracks()?.forEach((t: any) => t.stop()); | ||||||||||||||||||||||
| localStreamRef.current = null; | ||||||||||||||||||||||
| startingRef.current = false; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (icebreakerTimeoutRef.current) clearTimeout(icebreakerTimeoutRef.current); | ||||||||||||||||||||||
| setIcebreakerVisible(false); | ||||||||||||||||||||||
| icebreakerOpacity.setValue(0); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| socketRef.current?.disconnect(); | ||||||||||||||||||||||
| socketRef.current = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if (roomId) { | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| await api(`/video/room/${roomId}/leave`, { | ||||||||||||||||||||||
| method: "DELETE", | ||||||||||||||||||||||
| body: JSON.stringify({ peerId: peerIdRef.current }), | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| sendTransportRef.current?.close(); | ||||||||||||||||||||||
| recvTransportRef.current?.close(); | ||||||||||||||||||||||
| sendTransportRef.current = null; | ||||||||||||||||||||||
| recvTransportRef.current = null; | ||||||||||||||||||||||
| remoteStreamRef.current = new MediaStream(); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| consumersRef.current.forEach((c) => { | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| c.close(); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| consumersRef.current.clear(); | ||||||||||||||||||||||
| consumedProducerIdsRef.current.clear(); | ||||||||||||||||||||||
| consumingProducerIdsRef.current.clear(); | ||||||||||||||||||||||
| remoteVideoStreamRef.current = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| iceRefreshTimerRef.current && clearTimeout(iceRefreshTimerRef.current); | ||||||||||||||||||||||
| iceRefreshTimerRef.current = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Generate a fresh peerId for the new call | ||||||||||||||||||||||
| peerIdRef.current = `peer-${Math.random().toString(36).slice(2, 10)}`; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| setLocalUrl(null); | ||||||||||||||||||||||
| setRemoteUrl(null); | ||||||||||||||||||||||
| setGatewayRoomId(null); | ||||||||||||||||||||||
| setMatchedUserId(null); | ||||||||||||||||||||||
| setMatchState("idle"); | ||||||||||||||||||||||
| setIsLiked(false); | ||||||||||||||||||||||
| setReceivedLike(false); | ||||||||||||||||||||||
| setMutualLike(false); | ||||||||||||||||||||||
| chatRoomIdRef.current = null; | ||||||||||||||||||||||
| roomIdRef.current = null; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Re-enter matchmaking — deactivate first to guarantee IDLE state | ||||||||||||||||||||||
| setScreen("connecting"); | ||||||||||||||||||||||
| await connectMatchmakingGateway(); | ||||||||||||||||||||||
| try { | ||||||||||||||||||||||
| await deactivateMatchmakingRef.current(); | ||||||||||||||||||||||
| } catch {} | ||||||||||||||||||||||
| await activateMatchmaking(); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| function handleReaction() { | ||||||||||||||||||||||
| Alert.alert("Reaction", "Emoji Picker oder Quick Reaction öffnen."); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard
handleNextUseragainst concurrent execution.handleNextUsercan be triggered automatically from Line 454 (peer_left) and manually via the Next button path, but there is no in-flight guard. Overlapping runs can duplicate decline/leave/deactivate/activate sequences and produce inconsistent call state.Suggested fix
Also applies to: 691-765
🤖 Prompt for AI Agents