Skip to content

Commit

Permalink
Fix OR operator typo and increase number of pods (#148)
Browse files Browse the repository at this point in the history
Co-authored-by: Ong Jun Xiong <[email protected]>
Co-authored-by: Charisma Kausar <[email protected]>
Co-authored-by: Charisma Kausar <[email protected]>
Co-authored-by: Gabriel Goh <[email protected]>
Co-authored-by: chunweii <[email protected]>
  • Loading branch information
6 people authored Oct 19, 2023
1 parent fc57765 commit 747ef9a
Show file tree
Hide file tree
Showing 26 changed files with 316 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /app/services/collaboration-service
# Copy the entire services directory and prisma
COPY services/collaboration-service /app/services/collaboration-service
COPY prisma ./prisma/
COPY utils /app/utils/

# Install all dependencies using Yarn Workspaces
RUN yarn install --frozen-lockfile --cwd /app
Expand Down
1 change: 1 addition & 0 deletions deployment/dev-dockerfiles/Dockerfile.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /app/frontend
# Copy the entire frontend directory and prisma
COPY frontend /app/frontend
COPY prisma ./prisma/
COPY utils /app/utils/

# Install all dependencies using Yarn Workspaces
RUN yarn install --frozen-lockfile --cwd /app
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: admin-service
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: admin-service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: collaboration-service
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: collaboration-service
Expand Down
2 changes: 1 addition & 1 deletion deployment/gke-prod-manifests/frontend-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: frontend
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: frontend
Expand Down
2 changes: 1 addition & 1 deletion deployment/gke-prod-manifests/gateway-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: gateway
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: gateway
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: matching-service
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: matching-service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: question-service
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: question-service
Expand Down
2 changes: 1 addition & 1 deletion deployment/gke-prod-manifests/user-service-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ metadata:
name: user-service
namespace: default
spec:
replicas: 1
replicas: 3
selector:
matchLabels:
io.kompose.service: user-service
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /app/services/collaboration-service
# Copy the entire services directory and prisma
COPY services/collaboration-service /app/services/collaboration-service
COPY prisma ./prisma/
COPY utils /app/utils/

# Install all dependencies using Yarn Workspaces
RUN yarn install --frozen-lockfile --cwd /app
Expand Down
1 change: 1 addition & 0 deletions deployment/prod-dockerfiles/Dockerfile.frontend-prod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /app/frontend
# Copy the entire frontend directory and prisma
COPY frontend /app/frontend
COPY prisma ./prisma/
COPY utils /app/utils/

# Install all dependencies using Yarn Workspaces
RUN yarn install --frozen-lockfile --cwd /app
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ services:
- "5003:5003"
environment:
PORT: 5003
TWILIO_ACCOUNT_SID: ${TWILIO_ACCOUNT_SID}
TWILIO_API_KEY: ${TWILIO_API_KEY}
TWILIO_API_SECRET: ${TWILIO_API_SECRET}
PRISMA_DATABASE_URL: ${PRISMA_DATABASE_URL}

question-service:
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"tailwind-merge": "^1.14.0",
"tailwindcss": "3.3.3",
"tailwindcss-animate": "^1.0.7",
"twilio-video": "^2.28.1",
"typescript": "5.2.2",
"zod": "^3.22.4"
},
Expand Down
28 changes: 3 additions & 25 deletions frontend/src/components/room/description.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import { Room } from "twilio-video";
import { Question } from "../../types/QuestionTypes";
import { Badge } from "../ui/badge";
import { Button } from "../ui/button";
import { Card } from "../ui/card";
import { TypographyH2, TypographySmall } from "../ui/typography";
import { Video, Mic } from "lucide-react";
import VideoRoom from "./video-room";

// todo change this

type DescriptionProps = {
question: Question;
className?: string;
participants?: string[];
room: Room | null;
};

export default function Description({
question,
className,
participants,
}: DescriptionProps) {
return (
<Card className={`m-2 ml-0 px-6 h-full ${className} overflow-y-auto overflow-x-wrap pb-4`}>
Expand All @@ -43,29 +44,6 @@ export default function Description({
<div dangerouslySetInnerHTML={{ __html: question.description }} className="max-w-2xl overflow-x-auto"></div>
</TypographySmall>
</div>
{/* <div className="flex gap-4 absolute bottom-10">
{participants?.map((participant) => (
<div
className="flex items-center justify-start gap-4"
key={participant}
>
<div className="w-64 h-36 p-2 flex flex-col items-center justify-center border border-primary rounded-lg">
<div className="w-full h-full items-center justify-center flex"></div>
<div className="flex-1 ml-1 w-full h-8 flex items-center justify-between">
<p>{participant}</p>
<div className="flex flex-row gap-2 justify-end">
<Button variant="ghost" size="icon">
<Video />
</Button>
<Button variant="ghost" size="icon">
<Mic />
</Button>
</div>
</div>
</div>
</div>
))}
</div> */}
</Card>
);
}
161 changes: 161 additions & 0 deletions frontend/src/components/room/video-room.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import React, { useEffect, useRef, useState } from 'react';
import { LocalParticipant, LocalVideoTrack, Participant, RemoteParticipant, RemoteAudioTrack, RemoteVideoTrack, Room, Track } from 'twilio-video';
import { Button } from '../ui/button';
import { Mic, MicOff, Video, VideoOff } from 'lucide-react';

interface VideoRoomProps {
room: Room | null;
className?: string;
}

function SingleVideoTrack({ track, userId, isLocal, isMute, toggleMute, isCameraOn, toggleCamera }:
{
track: RemoteVideoTrack | LocalVideoTrack, userId: string, isLocal: boolean,
isMute: boolean, toggleMute: () => void,
isCameraOn: boolean, toggleCamera: () => void
}) {
const videoContainer = useRef<HTMLDivElement>(null);
useEffect(() => {
const videoElement = track.attach();
videoElement.classList.add("w-full", "h-full", "items-center", "justify-center", "flex");
videoContainer.current?.appendChild(videoElement);
return () => {
track.detach().forEach(element => element.remove());
videoElement.remove();
};
}, [isLocal, track]);
return (<div
className="flex items-center justify-start gap-4"
key={userId}
>
<div className="w-64 p-2 flex flex-col items-center justify-center border border-primary rounded-lg">
<div ref={videoContainer}></div>
<div className="flex-1 ml-1 w-full h-8 flex items-center justify-between">
<p>{userId}</p>
{isLocal ? <div className="flex flex-row gap-2 justify-end">
<Button variant="ghost" size="icon" onClick={toggleCamera}>
{isCameraOn ? <Video /> : <VideoOff />}
</Button>
<Button variant="ghost" size="icon" onClick={toggleMute}>
{isMute ? <MicOff /> : <Mic />}
</Button>
</div> : null}
</div>
</div>
</div>);
}

function SingleAudioTrack({track}: {track: RemoteAudioTrack}) {
const audioContainer = useRef<HTMLDivElement>(null);
useEffect(() => {
const audioElement = track.attach();
audioContainer.current?.appendChild(audioElement);
return () => {
track.detach().forEach(element => element.remove());
audioElement.remove();
};
}, [track]);
return (<div
ref={audioContainer}
></div>);
}

const VideoRoom: React.FC<VideoRoomProps> = ({ room, className }) => {
const [isCameraOn, setIsCameraOn] = useState(true);
const [isMute, setIsMute] = useState(false);
const [participants, setParticipants] = useState<RemoteParticipant[]>([]);
const [localParticipant, setLocalParticipant] = useState<LocalParticipant | null>(null);


const handleNewParticipant = (participant: RemoteParticipant) => {

participant.on('trackSubscribed', track => {
setParticipants(p => [...p])
});

participant.on('trackUnsubscribed', track => {
setParticipants(p => [...p])
});
};

const participantConnected = (participant: RemoteParticipant) => {
console.log('Participant "%s" connected,', participant.identity);

setParticipants(participants => [...participants, participant]);

handleNewParticipant(participant);
};

const participantDisconnected = (participant: RemoteParticipant) => {
console.log('Participant "%s" disconnected', participant.identity);
participant.removeAllListeners();
setParticipants(participants.filter(p => p.identity !== participant.identity));
};

const toggleCamera = () => {
room?.localParticipant.videoTracks.forEach(publication => {
if (publication.track) {
publication.track.enable(!isCameraOn);
setIsCameraOn(!isCameraOn);
}
});
};

const toggleMute = () => {
room?.localParticipant.audioTracks.forEach(publication => {
if (publication.track) {
publication.track.enable(isMute);
setIsMute(!isMute);
}
});
};

useEffect(() => {
if (!room) return;

room.on('participantConnected', participantConnected);
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', error => room.participants.forEach(participantDisconnected));

setLocalParticipant(room.localParticipant);

room.participants.forEach(handleNewParticipant);

setParticipants(Array.from(room.participants.values()));

return () => {
room.disconnect();
};
}, [room]);

return (
<div className={className}>
<div className="flex gap-4 absolute bottom-10">
{localParticipant ? Array.from(localParticipant.videoTracks.values()).map(publication => {
if (publication.track.kind === 'video') {
return <SingleVideoTrack track={publication.track} key={localParticipant.identity} userId={localParticipant.identity} isLocal={true} isMute={isMute} toggleMute={toggleMute} isCameraOn={isCameraOn} toggleCamera={toggleCamera} />;
} else { return null; }
}) : null}
{participants.flatMap(participant => {
return Array.from(participant.videoTracks.values()).map(publication => {
if (publication.track?.kind === 'video') {
return <SingleVideoTrack track={publication.track} key={participant.identity} userId={participant.identity} isLocal={false} isMute={isMute} toggleMute={toggleMute} isCameraOn={isCameraOn} toggleCamera={toggleCamera} />;
} else {
return null;
}
});
})}
{participants.flatMap(participant => {
return Array.from(participant.audioTracks.values()).map(audioPublication => {
if (audioPublication.track?.kind === 'audio') {
return <SingleAudioTrack track={audioPublication.track} key={participant.identity} />;
} else {
return null;
}
});
})}
</div></div>
);
};

export default VideoRoom;
2 changes: 1 addition & 1 deletion frontend/src/firebase-client/gateway-address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* - Leave GATEWAY_ADDRESS empty for dev environments
* - For prod, pass in a separate address to GATEWAY_ADDRESS
*/
const gatewayAddress = process.env.GATEWAY_ADDRESS ?? "http://localhost:4000/"
const gatewayAddress = process.env.GATEWAY_ADDRESS || "http://localhost:4000/"

export const userApiPathAddress = gatewayAddress + "api/user-service/";
export const questionApiPathAddress = gatewayAddress + "api/question-service/";
Loading

0 comments on commit 747ef9a

Please sign in to comment.