diff --git a/client/src/App.css b/client/src/App.css
index 45cc428..ee94161 100644
--- a/client/src/App.css
+++ b/client/src/App.css
@@ -26,6 +26,11 @@
height: 603px !important;
}
+video {
+ max-width: 200px !important;
+ max-height: 200px !important;
+}
+
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
diff --git a/client/src/pages/CodeUI.js b/client/src/pages/CodeUI.js
index 053e1ff..228cdbc 100644
--- a/client/src/pages/CodeUI.js
+++ b/client/src/pages/CodeUI.js
@@ -19,10 +19,13 @@ import "codemirror/lib/codemirror.css";
import "codemirror/theme/material.css";
import { theme } from "../themes/theme";
import socket from "../socket/socket";
+import Video from 'twilio-video';
+import ParticipantVideo from "../video-chat/ParticipantVideo";
require("codemirror/mode/xml/xml");
require("codemirror/mode/python/python");
require("codemirror/mode/clike/clike");
require("codemirror/mode/javascript/javascript");
+
const codeUIStyle = (theme) => ({
root: {
flexGrow: 1,
@@ -65,6 +68,14 @@ const codeUIStyle = (theme) => ({
fill: "black",
},
},
+ remoteParticipant: {
+ width: 200,
+ height: 200,
+ zIndex: 9,
+ position: 'absolute',
+ right: 0,
+ margin: "0 auto",
+ }
});
const qtitle = "Diagonal Difference";
const qdesc =
@@ -84,6 +95,9 @@ function CodeUI(props) {
const [runResult, setrunResult] = useState(null);
const [inRoom, setInRoom] = useState(false);
const history = useHistory();
+ const [videoRoom, setVideoRoom] = useState(null);
+ const [videoParticipants, setVideoParticipants] = useState([]);
+ const [token, setToken] = useState(null);
const [language, setLanguage] = useState("text/x-python");
useEffect(() => {
@@ -118,6 +132,60 @@ function CodeUI(props) {
});
}, []);
+ //For video chat room creation
+ useEffect(() => {
+ fetch(`/video/token/${props.match.params.id}`, {
+ method: 'POST',
+ body: JSON.stringify({}),
+ headers: { 'Content-Type': 'application/json' }
+ })
+ .then(res => res.json())
+ .then(data => setToken(data.token));
+ },[]);
+
+ //For video chat connection
+ useEffect(() => {
+ if (token) {
+ const participantConnected = participant => {
+ setVideoParticipants(prevParticipants => [...prevParticipants, participant]);
+ };
+
+ const participantDisconnected = participant => {
+ setVideoParticipants(prevParticipants =>
+ prevParticipants.filter(p => p !== participant)
+ );
+ };
+
+ Video.connect(token, {
+ name: props.match.params.id
+ }).then(videoRoom => {
+ setVideoRoom(videoRoom);
+ videoRoom.on('participantConnected', participantConnected);
+ videoRoom.on('participantDisconnected', participantDisconnected);
+ videoRoom.participants.forEach(participantConnected);
+ });
+
+ return () => {
+ setVideoRoom(currentRoom => {
+ if (currentRoom && currentRoom.localParticipant.state === 'connected') {
+ currentRoom.localParticipant.tracks.forEach(function(trackPublication) {
+ trackPublication.track.stop();
+ });
+ currentRoom.disconnect();
+ return null;
+ } else {
+ return currentRoom;
+ }
+ });
+ };
+ }
+ }, [props.match.params.id, token]);
+
+ //For video chat other participant video
+ const remoteParticipants = videoParticipants.map(participant => (
+
+ ));
+
const handleInRoom = () => {
inRoom ? setInRoom(false) : setInRoom(true);
};
@@ -142,6 +210,7 @@ function CodeUI(props) {
fetch(`/interviews/endInterview/${props.match.params.id}`)
.then((res) => socket.emit("endInterview", { id: props.match.params.id }))
.catch((err) => console.log(err));
+ setToken(null);//For video-chat logout
}
const changeLanguage = (lang) => {
@@ -203,6 +272,8 @@ function CodeUI(props) {
+
{remoteParticipants}
+ {/* I want this above
*/}
{}}
+ style={{position: 'absolute'}}
/>
+ {/* {remoteParticipants}
*/}
diff --git a/client/src/video-chat/ParticipantVideo.js b/client/src/video-chat/ParticipantVideo.js
new file mode 100644
index 0000000..f21b9bb
--- /dev/null
+++ b/client/src/video-chat/ParticipantVideo.js
@@ -0,0 +1,83 @@
+import React, { useState, useEffect, useRef } from "react";
+import { makeStyles } from "@material-ui/core/styles";
+
+const useStyles = makeStyles((theme) => ({
+ screen: {
+ maxWidth: "200px",
+ maxHeight: "200px"
+ }
+}));
+
+const ParticipantVideo = ({ participant }) => {
+ const classes = useStyles();
+ const [videoTracks, setVideoTracks] = useState([]);
+ const [audioTracks, setAudioTracks] = useState([]);
+
+ const videoRef = useRef();
+ const audioRef = useRef();
+
+ const trackpubsToTracks = (trackMap) =>
+ Array.from(trackMap.values())
+ .map((publication) => publication.track)
+ .filter((track) => track !== null);
+
+ useEffect(() => {
+ setVideoTracks(trackpubsToTracks(participant.videoTracks));
+ setAudioTracks(trackpubsToTracks(participant.audioTracks));
+
+ const trackSubscribed = (track) => {
+ if (track.kind === "video") {
+ setVideoTracks((videoTracks) => [...videoTracks, track]);
+ } else if (track.kind === "audio") {
+ setAudioTracks((audioTracks) => [...audioTracks, track]);
+ }
+ };
+
+ const trackUnsubscribed = (track) => {
+ if (track.kind === "video") {
+ setVideoTracks((videoTracks) => videoTracks.filter((v) => v !== track));
+ } else if (track.kind === "audio") {
+ setAudioTracks((audioTracks) => audioTracks.filter((a) => a !== track));
+ }
+ };
+
+ participant.on("trackSubscribed", trackSubscribed);
+ participant.on("trackUnsubscribed", trackUnsubscribed);
+
+ return () => {
+ setVideoTracks([]);
+ setAudioTracks([]);
+ participant.removeAllListeners();
+ };
+ }, [participant]);
+
+ useEffect(() => {
+ const videoTrack = videoTracks[0];
+ if (videoTrack) {
+ videoTrack.attach(videoRef.current);
+ return () => {
+ videoTrack.detach();
+ };
+ }
+ }, [videoTracks]);
+
+ useEffect(() => {
+ const audioTrack = audioTracks[0];
+ if (audioTrack) {
+ audioTrack.attach(audioRef.current);
+ return () => {
+ audioTrack.detach();
+ };
+ }
+ }, [audioTracks]);
+
+ return (
+
+
{participant.identity}
+
+
+
+ );
+};
+
+export default ParticipantVideo;
diff --git a/server/app.js b/server/app.js
index b437247..c3be4fc 100644
--- a/server/app.js
+++ b/server/app.js
@@ -8,6 +8,7 @@ const interviewRouter = require("./interview/interview.controller");
const accountRouter = require("./users/users.controller");
const questionRouter = require("./question/question.controller");
const runCode = require("./helpers/runcode");
+const videoRouter = require("./video-chat/videoChatApis");
const { json, urlencoded } = express;
@@ -23,6 +24,7 @@ app.use("/", accountRouter);
app.use("/users", require("./users/users.controller"));
app.use("/interviews", interviewRouter);
app.use("/questions", questionRouter);
+app.use("/video", videoRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
diff --git a/server/package-lock.json b/server/package-lock.json
index 5e6b217..9838a14 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -4,10 +4,14 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
- "@twilio/webrtc": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/@twilio/webrtc/-/webrtc-4.3.1.tgz",
- "integrity": "sha512-T9Slk8TyKrKqjc4PH4aPknjmEozny/M1TzVyfRRyEQSt548hXXhLYrSp3nUcK49bfzVrgbYuRj6ojExYh2qLqw=="
+ "@types/body-parser": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
+ "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
+ "requires": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
},
"@types/chai": {
"version": "4.1.7",
@@ -15,17 +19,69 @@
"integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==",
"dev": true
},
+ "@types/connect": {
+ "version": "3.4.33",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
+ "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/cookiejar": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.1.tgz",
"integrity": "sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==",
"dev": true
},
+ "@types/express": {
+ "version": "4.17.7",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.7.tgz",
+ "integrity": "sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ==",
+ "requires": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "*",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "@types/express-serve-static-core": {
+ "version": "4.17.9",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz",
+ "integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==",
+ "requires": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
+ }
+ },
+ "@types/mime": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz",
+ "integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q=="
+ },
"@types/node": {
"version": "12.6.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz",
- "integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==",
- "dev": true
+ "integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg=="
+ },
+ "@types/qs": {
+ "version": "6.9.3",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz",
+ "integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA=="
+ },
+ "@types/range-parser": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
+ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
+ },
+ "@types/serve-static": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz",
+ "integrity": "sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==",
+ "requires": {
+ "@types/express-serve-static-core": "*",
+ "@types/mime": "*"
+ }
},
"@types/superagent": {
"version": "3.8.7",
@@ -141,6 +197,11 @@
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
},
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
@@ -173,19 +234,19 @@
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
},
+ "axios": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
+ "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
+ "requires": {
+ "follow-redirects": "1.5.10"
+ }
+ },
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
"integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
},
- "backoff": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz",
- "integrity": "sha1-9hbtqdPktmuMp/ynn2lXIsX44m8=",
- "requires": {
- "precond": "0.2"
- }
- },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -664,6 +725,11 @@
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
"integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
},
+ "dayjs": {
+ "version": "1.8.30",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.30.tgz",
+ "integrity": "sha512-5s5IGuP5bVvIbOWkEDcfmXsUj24fZW1NMHVVSdSFF/kW8d+alZcI9SpBKC+baEyBe+z3fUp17y75ulstv5swUw=="
+ },
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -1185,6 +1251,24 @@
}
}
},
+ "follow-redirects": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
+ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+ "requires": {
+ "debug": "=3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -3010,16 +3094,16 @@
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
+ "pop-iterate": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pop-iterate/-/pop-iterate-1.0.1.tgz",
+ "integrity": "sha1-zqz9q0q/NT16DyqqLB/Hs/lBO6M="
+ },
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
- "precond": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
- "integrity": "sha1-qpWRvKokkj8eD0hJ0kD0fvwQdaw="
- },
"prepend-http": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
@@ -3059,11 +3143,26 @@
"once": "^1.3.1"
}
},
+ "q": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/q/-/q-2.0.3.tgz",
+ "integrity": "sha1-dbjbAlWhpa+C9Yw/Oqoe/sfQ0TQ=",
+ "requires": {
+ "asap": "^2.0.0",
+ "pop-iterate": "^1.0.1",
+ "weak-map": "^1.0.5"
+ }
+ },
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
+ "querystringify": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
+ "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
+ },
"range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -3182,6 +3281,11 @@
"semver": "^5.1.0"
}
},
+ "requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ },
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
@@ -3197,6 +3301,11 @@
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
},
+ "rootpath": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/rootpath/-/rootpath-0.1.2.tgz",
+ "integrity": "sha1-Wzeah9ypBum5HWkKWZQ5vvJn6ms="
+ },
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -3224,6 +3333,11 @@
"sparse-bitfield": "^3.0.3"
}
},
+ "scmp": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz",
+ "integrity": "sha512-o/mRQGk9Rcer/jEEw/yw4mwo3EU/NvYvp577/Btqrym9Qy5/MdWGBqipbALgd2lrdWTJ5/gqDusxfnQBxOxT2Q=="
+ },
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
@@ -3775,26 +3889,33 @@
"nopt": "~1.0.10"
}
},
- "twilio-video": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/twilio-video/-/twilio-video-2.7.0.tgz",
- "integrity": "sha512-juAMupRjBGh1pqVvE9CwpMGoGyJOlmJbzG2C3TstK1bAcHDLFUvFkBlNwL+ubIUTipX0nrrxzVfcQrEI3wWHqA==",
- "requires": {
- "@twilio/webrtc": "4.3.1",
- "backoff": "^2.5.0",
- "ws": "^3.3.1",
- "xmlhttprequest": "^1.8.0"
+ "twilio": {
+ "version": "3.48.0",
+ "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.48.0.tgz",
+ "integrity": "sha512-FDPCze9PxPF88pULND7ZfaVkZtAGh8i0Xo1ZpuW6aOzd4SRGplJBZSrx4IiH1q56di+yKQ6ABw2uXb5rRH+rbQ==",
+ "requires": {
+ "@types/express": "^4.17.7",
+ "axios": "^0.19.2",
+ "dayjs": "^1.8.29",
+ "jsonwebtoken": "^8.5.1",
+ "lodash": "^4.17.19",
+ "q": "2.0.x",
+ "qs": "^6.9.4",
+ "rootpath": "^0.1.2",
+ "scmp": "^2.1.0",
+ "url-parse": "^1.4.7",
+ "xmlbuilder": "^13.0.2"
},
"dependencies": {
- "ws": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
- "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
- "requires": {
- "async-limiter": "~1.0.0",
- "safe-buffer": "~5.1.0",
- "ultron": "~1.1.0"
- }
+ "lodash": {
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
+ },
+ "qs": {
+ "version": "6.9.4",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
+ "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
}
}
},
@@ -3813,11 +3934,6 @@
"mime-types": "~2.1.24"
}
},
- "ultron": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
- "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og=="
- },
"undefsafe": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz",
@@ -3918,6 +4034,15 @@
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
},
+ "url-parse": {
+ "version": "1.4.7",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
+ "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
+ "requires": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
"url-parse-lax": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
@@ -3951,6 +4076,11 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
},
+ "weak-map": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/weak-map/-/weak-map-1.0.5.tgz",
+ "integrity": "sha1-eWkVhNmGB/UHC9O3CkDmuyLkAes="
+ },
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -4055,10 +4185,10 @@
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
"integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ="
},
- "xmlhttprequest": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz",
- "integrity": "sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw="
+ "xmlbuilder": {
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz",
+ "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ=="
},
"xmlhttprequest-ssl": {
"version": "1.5.5",
diff --git a/server/package.json b/server/package.json
index d015d69..0991dd1 100644
--- a/server/package.json
+++ b/server/package.json
@@ -22,7 +22,7 @@
"morgan": "~1.9.1",
"nodemon": "^1.19.1",
"socket.io": "^2.3.0",
- "twilio-video": "^2.7.0"
+ "twilio": "^3.48.0"
},
"devDependencies": {
"chai": "^4.2.0",
diff --git a/server/video-chat/twilioTokens.js b/server/video-chat/twilioTokens.js
new file mode 100644
index 0000000..4c70ca8
--- /dev/null
+++ b/server/video-chat/twilioTokens.js
@@ -0,0 +1,26 @@
+const twilio = require('twilio');
+const AccessToken = twilio.jwt.AccessToken;
+const { VideoGrant } = AccessToken;
+
+const generateToken = () => {
+ return new AccessToken(
+ process.env.TWILIO_ACCOUNT_SID,
+ process.env.TWILIO_API_KEY,
+ process.env.TWILIO_API_SECRET
+ );
+};
+
+const videoToken = (identity, room) => {
+ let videoGrant;
+ if (typeof room !== 'undefined') {
+ videoGrant = new VideoGrant({ room });
+ } else {
+ videoGrant = new VideoGrant();
+ }
+ const token = generateToken();
+ token.addGrant(videoGrant);
+ token.identity = identity;
+ return token;
+};
+
+module.exports = { videoToken };
diff --git a/server/video-chat/videoChatApis.js b/server/video-chat/videoChatApis.js
new file mode 100644
index 0000000..1b47b76
--- /dev/null
+++ b/server/video-chat/videoChatApis.js
@@ -0,0 +1,33 @@
+const express = require("express");
+const router = express.Router();
+const { videoToken } = require('./twilioTokens');
+const verifyToken = require("../helpers/verifyToken");
+
+const sendTokenResponse = (token, res) => {
+ res.set('Content-Type', 'application/json');
+ res.send(
+ JSON.stringify({
+ token: token.toJwt()
+ })
+ );
+ };
+
+router.get('/token/:interviewId', verifyToken, (req, res) => {
+ const user = req.user;
+ const interviewId = req.params.interviewId;
+ const identity = user.id;
+ const room = interviewId;
+ const token = videoToken(identity, room);
+ sendTokenResponse(token, res);
+ });
+
+router.post('/token/:interviewId', verifyToken, (req, res) => {
+ const user = req.user;
+ const interviewId = req.params.interviewId;
+ const identity = user.id;
+ const room = interviewId;
+ const token = videoToken(identity, room);
+ sendTokenResponse(token, res);
+ });
+
+ module.exports = router;
\ No newline at end of file