v1.6.0/speculative fix for call conflict

This commit is contained in:
2020-08-08 17:41:40 -04:00
parent f375d33311
commit 6ccf7c6201
4 changed files with 157 additions and 75 deletions
+53 -33
View File
@@ -9,14 +9,14 @@ ALL CONTENT ON WATCH PARTY'S WEBSITE OR IN WATCH PARTY'S CHROME EXTENSION APP, U
CITED ARE THE SOLE INTELECTUAL PROPERTY OF AYUSHYA AMITABH, AND MAY NOT BE CITED ARE THE SOLE INTELECTUAL PROPERTY OF AYUSHYA AMITABH, AND MAY NOT BE
COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION. COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION.
************************************************************************/ ************************************************************************/
import VoxeetSDK from '@voxeet/voxeet-web-sdk'; import VoxeetSDK from "@voxeet/voxeet-web-sdk";
import { import {
GetVoxeetTokenApi, GetVoxeetTokenApi,
GetRefreshedVoxeetTokenApi, GetRefreshedVoxeetTokenApi,
LocalData, LocalData,
UpdateVoxeetApi, UpdateVoxeetApi,
updateLocalData, updateLocalData,
} from './Api'; } from "./Api";
export default class CallManager { export default class CallManager {
constructor(listener, notify) { constructor(listener, notify) {
@@ -29,11 +29,15 @@ export default class CallManager {
this.__adminOnly = true; this.__adminOnly = true;
} }
toggleCall(onCall, conference, admin, adminOnly) { toggleCall(onCall, conference, admin, adminOnly) {
this.listener({ callActionPending: true }); try {
this.__admin = admin; this.listener({ callActionPending: true });
this.__adminOnly = adminOnly; this.__admin = admin;
if (onCall === true) this.leaveCall(); this.__adminOnly = adminOnly;
else this.boot(conference); if (onCall === true) this.leaveCall();
else this.boot(conference);
} catch (e) {
this.notify("Uh oh something went wrong, try rejoining the call.");
}
} }
toggleMute(muted) { toggleMute(muted) {
this.listener({ callActionPending: true }); this.listener({ callActionPending: true });
@@ -48,20 +52,23 @@ export default class CallManager {
.fetch(conference._id) .fetch(conference._id)
.then(this.joinCall) .then(this.joinCall)
.catch((err) => { .catch((err) => {
console.error('Failed to fetch conference', err); console.error("Failed to fetch conference", err);
this.startCall(); this.startCall();
}); });
} else if (opened && !conference) { } else if (opened && !conference) {
this.startCall(); this.startCall();
} else { } else {
this.listener({ onCall: false, muted: false, callActionPending: false }); this.listener({ onCall: false, muted: false, callActionPending: false });
console.error('Unable to open Voxeet Session'); console.error("Unable to open Voxeet Session");
} }
} }
async startCall() { async startCall() {
if (!this.__adminOnly || (this.__adminOnly && this.__admin)) { if (!this.__adminOnly || (this.__adminOnly && this.__admin)) {
VoxeetSDK.conference VoxeetSDK.conference
.create({ alias: `AUTODELETE_${LocalData().partyName}`, pin: LocalData().partyPin }) .create({
alias: `AUTODELETE_${LocalData().partyName}`,
pin: LocalData().partyPin,
})
.then(async (conference) => { .then(async (conference) => {
const updatedVoxeet = await UpdateVoxeetApi({ const updatedVoxeet = await UpdateVoxeetApi({
conference, conference,
@@ -77,20 +84,28 @@ export default class CallManager {
return true; return true;
} else { } else {
this.notify(err.message); this.notify(err.message);
this.listener({ onCall: false, muted: false, callActionPending: false }); this.listener({
console.error('Update Voxeet API Error', err); onCall: false,
muted: false,
callActionPending: false,
});
console.error("Update Voxeet API Error", err);
return false; return false;
} }
}); });
if (updatedVoxeet === true) { if (updatedVoxeet === true) {
this.joinCall(conference); this.joinCall(conference);
} else { } else {
this.listener({ onCall: false, muted: false, callActionPending: false }); this.listener({
console.error('Failed to update party Voxeet'); onCall: false,
muted: false,
callActionPending: false,
});
console.error("Failed to update party Voxeet");
} }
}); });
} else { } else {
this.notify('Ask your party admin to start the call.'); this.notify("Ask your party admin to start the call.");
this.leaveCall(); this.leaveCall();
} }
} }
@@ -99,14 +114,15 @@ export default class CallManager {
.join(conference, { constraints: { audio: true, video: false } }) .join(conference, { constraints: { audio: true, video: false } })
.then(() => true) .then(() => true)
.catch((e) => { .catch((e) => {
this.listener({ onCall: false, muted: false, callActionPending: false }); this.listener({
this.notify('Unable to join call. Try again in a moment.'); onCall: false,
console.error('Error joining call', e); muted: false,
callActionPending: false,
});
this.notify("Unable to join call. Try again in a moment.");
console.error("Error joining call", e);
return true; return true;
}); });
if (!joined) {
this.startCall();
}
} }
async leaveCall() { async leaveCall() {
VoxeetSDK.conference.leave().then(() => { VoxeetSDK.conference.leave().then(() => {
@@ -123,9 +139,9 @@ export default class CallManager {
}); });
return true; return true;
} catch (error) { } catch (error) {
console.error('Error Opening Voxeet Session', error); console.error("Error Opening Voxeet Session", error);
} }
console.error('Session not initialized'); console.error("Session not initialized");
return false; return false;
} }
return true; return true;
@@ -138,22 +154,26 @@ export default class CallManager {
this.listener({ usersOnCall }); this.listener({ usersOnCall });
} }
async initialize() { async initialize() {
VoxeetSDK.conference.on('participantAdded', () => this.usersListHandle()); VoxeetSDK.conference.on("participantAdded", () => this.usersListHandle());
VoxeetSDK.conference.on('participantUpdated', () => this.usersListHandle()); VoxeetSDK.conference.on("participantUpdated", () => this.usersListHandle());
VoxeetSDK.conference.on('joined', () => { VoxeetSDK.conference.on("joined", () => {
this.listener({ onCall: true, callActionPending: false }); this.listener({ onCall: true, callActionPending: false });
}); });
VoxeetSDK.conference.on('left', () => { VoxeetSDK.conference.on("left", () => {
this.listener({ onCall: false, callActionPending: false, usersOnCall: {} }); this.listener({
onCall: false,
callActionPending: false,
usersOnCall: {},
});
}); });
VoxeetSDK.conference.on('streamAdded', (participant, stream) => { VoxeetSDK.conference.on("streamAdded", (participant, stream) => {
this.listener({ callActionPending: false }); this.listener({ callActionPending: false });
}); });
VoxeetSDK.conference.on('streamRemoved', (participant, stream) => { VoxeetSDK.conference.on("streamRemoved", (participant, stream) => {
this.listener({ callActionPending: false }); this.listener({ callActionPending: false });
}); });
@@ -171,11 +191,11 @@ export default class CallManager {
this.updateTokens(access_token, refresh_token); this.updateTokens(access_token, refresh_token);
VoxeetSDK.initializeToken(access_token, refresh_token); VoxeetSDK.initializeToken(access_token, refresh_token);
} else { } else {
console.error('Get Voxeet Token API Result Error', tokenResult); console.error("Get Voxeet Token API Result Error", tokenResult);
} }
}) })
.catch((err) => { .catch((err) => {
console.error('Get Voxeet Token API error', err); console.error("Get Voxeet Token API error", err);
}); });
} else { } else {
VoxeetSDK.initializeToken(this.__accessToken, this.__refreshToken); VoxeetSDK.initializeToken(this.__accessToken, this.__refreshToken);
@@ -191,7 +211,7 @@ export default class CallManager {
resolve(access_token); resolve(access_token);
}) })
.catch((err) => { .catch((err) => {
console.error('Get Voxeet Token API error', err); console.error("Get Voxeet Token API error", err);
reject(err); reject(err);
}); });
}); });
+3 -2
View File
@@ -12,8 +12,9 @@ COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION.
.thread-container * { .thread-container * {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: 'Roboto', sans-serif !important; font-family: "Roboto", sans-serif !important;
letter-spacing: 1.15px; letter-spacing: 1.15px;
word-break: break-word !important;
} }
.thread-container { .thread-container {
max-height: none; max-height: none;
@@ -99,7 +100,7 @@ COPIED, EDITED, OR REPRODUCED WITHOUT PERMISSION.
line-height: 16px; line-height: 16px;
font-size: 13px; font-size: 13px;
font-weight: 100; font-weight: 100;
font-family: 'Roboto'; font-family: "Roboto";
letter-spacing: 1.5px; letter-spacing: 1.5px;
white-space: break-spaces; white-space: break-spaces;
word-break: break-all; word-break: break-all;
+42 -21
View File
@@ -1,16 +1,23 @@
const admin = require('firebase-admin'); const admin = require("firebase-admin");
module.exports = async (req, res) => { module.exports = async (req, res) => {
const { conference, partyName, partyPin, userName, uid } = JSON.parse(req.body); const { conference, partyName, partyPin, userName, uid } = JSON.parse(
req.body
);
// GET ROOM PIN // GET ROOM PIN
const [exists, roomPin, conferencePending, partyConference] = await admin const [exists, roomPin, conferencePending, partyConference] = await admin
.firestore() .firestore()
.collection('rooms') .collection("rooms")
.doc(partyName) .doc(partyName)
.get() .get()
.then((roomSnap) => { .then((roomSnap) => {
const data = roomSnap.exists ? roomSnap.data() : {}; const data = roomSnap.exists ? roomSnap.data() : {};
return [roomSnap.exists, data.pin, data.conferencePending, data.conference]; return [
roomSnap.exists,
data.pin,
data.conferencePending,
data.conference,
];
}); });
// CHECK IF ROOM EXISTS // CHECK IF ROOM EXISTS
if (exists === true) { if (exists === true) {
@@ -22,47 +29,61 @@ module.exports = async (req, res) => {
// UPDATE CONFERENCE DETAILS // UPDATE CONFERENCE DETAILS
await admin await admin
.firestore() .firestore()
.collection('rooms') .collection("rooms")
.doc(partyName) .doc(partyName)
.update({ conference }) .update({ conference })
.catch((err) => .catch((err) =>
res.status(500).send({ message: 'Unable to update the call details', error: err }) res.status(500).send({
message: "Unable to update the call details",
error: err,
})
); );
// REMOVE PENDING STATUS // REMOVE PENDING STATUS
await admin await admin
.firestore() .firestore()
.collection('rooms') .collection("rooms")
.doc(partyName) .doc(partyName)
.update({ conferencePending : admin.firestore.FieldValue.delete() }) .update({
.catch((err) => console.error('Failed to remove pending status', err)); conferencePending: admin.firestore.FieldValue.delete(),
})
.catch((err) =>
console.error("Failed to remove pending status", err)
);
// ADD SYSTEM MESSAGE // ADD SYSTEM MESSAGE
await admin await admin
.firestore() .firestore()
.collection('rooms') .collection("rooms")
.doc(partyName) .doc(partyName)
.collection('messages') .collection("messages")
.add({ .add({
uid: '<system>', uid: "<system>",
name: '', name: "",
text: `${userName} started the call, everyone can join now.`, text: `${userName} started the call, everyone can join now.`,
time: new Date(), time: new Date(),
}) })
.catch((err) => console.error('Failed to add update conference message', err)); .catch((err) =>
res.status(200).send({ message: 'Started the conference' }); console.error("Failed to add update conference message", err)
);
res.status(200).send({ message: "Started the conference" });
} else { } else {
res.status(409).send({ message: 'Looks like someone is already starting a call' }); res.status(409).send({
message: "Looks like someone is already starting a call",
});
} }
} else if (partyConference) { } else if (partyConference) {
res.status(409).send({ message: 'Call already exists', conference: partyConference }); res.status(409).send({
message: "Call already exists",
conference: partyConference,
});
} }
} else { } else {
// WRONG ROOM PIN // WRONG ROOM PIN
res.status(401).send({ message: 'Wrong party pin, try rejoining' }); res.status(401).send({ message: "Wrong party pin, try rejoining" });
} }
} }
} else { } else {
// ROOM DOESN'T EXIST // ROOM DOESN'T EXIST
res.status(404).send({ message: 'Party Not Found' }); res.status(404).send({ message: "Party Not Found" });
} }
return; return;
}; };
+59 -19
View File
@@ -1,30 +1,70 @@
const admin = require('firebase-admin'); const admin = require("firebase-admin");
module.exports = async (req, res) => { module.exports = async (req, res) => {
console.info(`[START]\tWEBHOOKS/Conference End\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`); console.info(
if (req.body.eventType === 'Conference.Ended') { `[START]\tWEBHOOKS/Conference End\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
// MAKE SURE CORRECT EVENT TYPE
if (req.body.eventType === "Conference.Ended") {
// MAKE SURE IT'S NOT A DUPLICATE FROM CREATE CONFLICT
if (req.body.participants.length > 0) { if (req.body.participants.length > 0) {
if (req.body.confAlias.startsWith('AUTODELETE_')) { // MAKE SURE ELIGIBLE FOR DELETE
if (req.body.confAlias.startsWith("AUTODELETE_")) {
const partyName = req.body.confAlias.replace(/AUTODELETE_/, ""); const partyName = req.body.confAlias.replace(/AUTODELETE_/, "");
admin.firestore() const existingConference = await admin
.collection('rooms') .firestore()
.doc(partyName) .collection("rooms")
.update({ conference: admin.firestore.FieldValue.delete() }) .doc(partyName)
.then(() => { .get()
console.info(`[DONE]\tWEBHOOKS/Conference End\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`); .then((snap) => (snap.exists ? snap.data().conference : null));
return; // MAKE SURE EXISTS AND HAS NOT BEEN REPLACED
}) if (
.catch(err => { existingConference &&
console.error(`[ERROR]\tWEBHOOKS/Conference End/Firebase Error\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}\nError:${JSON.stringify(err)}`) existingConference._id === req.body.conference.confId
}); ) {
res.status(200).send({ message: 'Processed conference end'}); // REMOVE CONFERENCE DETAILS
await admin
.firestore()
.collection("rooms")
.doc(partyName)
.update({ conference: admin.firestore.FieldValue.delete() })
.then(() => {
console.info(
`[DONE]\tWEBHOOKS/Conference End\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
return;
})
.catch((err) => {
console.error(
`[ERROR]\tWEBHOOKS/Conference End/Firebase Error\tID:${
req.body.conference.confId
}\tParty:${
req.body.conference.confAlias
}\tError:${JSON.stringify(err)}`
);
});
} else {
console.info(
`[DONE]\tWEBHOOKS/Conference End/Conference Was Already Replaced\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
}
res.status(200).send({ message: "Processed conference end" });
} else {
console.info(
`[DONE]\tWEBHOOKS/Conference End/Not Eligible For Autodelete\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
res.status(200).send({ message: "Processed conference end" });
} }
} else { } else {
console.info(`[DONE]\tWEBHOOKS/Conference End/End Of Duplicate Conference\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`); console.info(
`[DONE]\tWEBHOOKS/Conference End/End Of Duplicate Conference\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
} }
} else { } else {
console.error(`[ERROR]\tWEBHOOKS/Conference End/Wrong Event Type\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`) console.error(
res.status(400).send({ message: 'Wrong event type' }); `[ERROR]\tWEBHOOKS/Conference End/Wrong Event Type\tID:${req.body.conference.confId}\tParty:${req.body.conference.confAlias}`
);
res.status(400).send({ message: "Wrong event type" });
} }
return; return;
}; };