v1.6.0/conference call upgrade
- anyone can start call - colision check for calls - better error handing for calls
This commit is contained in:
+2
-2
@@ -149,9 +149,9 @@ export const UpdatePlayerApi = async (data) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GetVoxeetTokenApi = async () => {
|
export const GetVoxeetTokenApi = async (data) => {
|
||||||
return fetcher({
|
return fetcher({
|
||||||
endpoint: 'validator',
|
endpoint: `validator/${data.partyName}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+31
-8
@@ -33,10 +33,12 @@ export default class CallManager {
|
|||||||
this.__accessToken = LocalData().vrT;
|
this.__accessToken = LocalData().vrT;
|
||||||
this.__sessionInitialized = false;
|
this.__sessionInitialized = false;
|
||||||
this.__admin = false;
|
this.__admin = false;
|
||||||
|
this.__adminOnly = true;
|
||||||
}
|
}
|
||||||
toggleCall(onCall, conference, admin) {
|
toggleCall(onCall, conference, admin, adminOnly) {
|
||||||
this.listener({ callActionPending: true });
|
this.listener({ callActionPending: true });
|
||||||
this.__admin = admin;
|
this.__admin = admin;
|
||||||
|
this.__adminOnly = adminOnly;
|
||||||
if (onCall === true) this.leaveCall();
|
if (onCall === true) this.leaveCall();
|
||||||
else this.boot(conference);
|
else this.boot(conference);
|
||||||
}
|
}
|
||||||
@@ -56,13 +58,17 @@ export default class CallManager {
|
|||||||
console.error('Failed to fetch conference', err);
|
console.error('Failed to fetch conference', err);
|
||||||
this.startCall();
|
this.startCall();
|
||||||
});
|
});
|
||||||
} else if (opened && !conference) this.startCall();
|
} else if (opened && !conference) {
|
||||||
else console.error('Unable to open Voxeet Session');
|
this.startCall();
|
||||||
|
} else {
|
||||||
|
this.listener({ onCall: false, muted: false, callActionPending: false });
|
||||||
|
console.error('Unable to open Voxeet Session');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async startCall() {
|
async startCall() {
|
||||||
if (this.__admin === true) {
|
if (!this.__adminOnly || (this.__adminOnly && this.__admin)) {
|
||||||
VoxeetSDK.conference
|
VoxeetSDK.conference
|
||||||
.create({ alias: 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,
|
||||||
@@ -72,10 +78,21 @@ export default class CallManager {
|
|||||||
})
|
})
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((res) => res.status <= 299)
|
.then((res) => res.status <= 299)
|
||||||
.catch((err) => console.error('Update Voxeet API Error', err));
|
.catch((err) => {
|
||||||
|
if (err.conference) {
|
||||||
|
this.joinCall(err.conference);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
this.notify(err.message);
|
||||||
|
this.listener({ onCall: false, muted: false, callActionPending: false });
|
||||||
|
console.error('Update Voxeet API Error', err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
if (updatedVoxeet === true) {
|
if (updatedVoxeet === true) {
|
||||||
this.joinCall(conference);
|
this.joinCall(conference);
|
||||||
} else {
|
} else {
|
||||||
|
this.listener({ onCall: false, muted: false, callActionPending: false });
|
||||||
console.error('Failed to update party Voxeet');
|
console.error('Failed to update party Voxeet');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -87,7 +104,13 @@ export default class CallManager {
|
|||||||
async joinCall(conference) {
|
async joinCall(conference) {
|
||||||
const joined = await VoxeetSDK.conference
|
const joined = await VoxeetSDK.conference
|
||||||
.join(conference, { constraints: { audio: true, video: false } })
|
.join(conference, { constraints: { audio: true, video: false } })
|
||||||
.then(() => true);
|
.then(() => true)
|
||||||
|
.catch(e => {
|
||||||
|
this.listener({ onCall: false, muted: false, callActionPending: false });
|
||||||
|
this.notify('Unable to join call. Try again in a moment.');
|
||||||
|
console.error('Error joining call', e);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
if (!joined) {
|
if (!joined) {
|
||||||
this.startCall();
|
this.startCall();
|
||||||
}
|
}
|
||||||
@@ -158,7 +181,7 @@ export default class CallManager {
|
|||||||
this.__accessToken !== null ||
|
this.__accessToken !== null ||
|
||||||
this.__refreshToken !== null
|
this.__refreshToken !== null
|
||||||
) {
|
) {
|
||||||
await GetVoxeetTokenApi()
|
await GetVoxeetTokenApi({ partyName: LocalData().partyName })
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((tokenResult) => {
|
.then((tokenResult) => {
|
||||||
if (tokenResult.status <= 299) {
|
if (tokenResult.status <= 299) {
|
||||||
|
|||||||
+5
-3
@@ -235,6 +235,7 @@ export default class Chat extends Component {
|
|||||||
const data = {
|
const data = {
|
||||||
partyName: LocalData().partyName,
|
partyName: LocalData().partyName,
|
||||||
};
|
};
|
||||||
|
if (this.state.onCall) this.mCallManager.toggleCall(this.state.onCall, this.state.conference, this.state.admin, this.state.adminOnly);
|
||||||
DeleteRoomApi(data)
|
DeleteRoomApi(data)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.props.notify('Ended party');
|
this.props.notify('Ended party');
|
||||||
@@ -255,6 +256,7 @@ export default class Chat extends Component {
|
|||||||
partyName: LocalData().partyName,
|
partyName: LocalData().partyName,
|
||||||
userUid: LocalData().userUid,
|
userUid: LocalData().userUid,
|
||||||
};
|
};
|
||||||
|
if (this.state.onCall) this.mCallManager.toggleCall(this.state.onCall, this.state.conference, this.state.admin, this.state.adminOnly);
|
||||||
LeaveRoomApi(data)
|
LeaveRoomApi(data)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.props.notify('Left party');
|
this.props.notify('Left party');
|
||||||
@@ -312,7 +314,7 @@ export default class Chat extends Component {
|
|||||||
: giphyFetch.search(this.state.newMessage, { offset, limit: 1 });
|
: giphyFetch.search(this.state.newMessage, { offset, limit: 1 });
|
||||||
}
|
}
|
||||||
handlePhoneCall() {
|
handlePhoneCall() {
|
||||||
const { onCall, conference, admin } = this.state;
|
const { onCall, conference, admin, adminOnly } = this.state;
|
||||||
if (window.navigator && onCall === false) {
|
if (window.navigator && onCall === false) {
|
||||||
try {
|
try {
|
||||||
const overlay = document.createElement('div');
|
const overlay = document.createElement('div');
|
||||||
@@ -328,7 +330,7 @@ export default class Chat extends Component {
|
|||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
document.getElementById('mic-permission-overlay').remove();
|
document.getElementById('mic-permission-overlay').remove();
|
||||||
this.mCallManager.toggleCall(onCall, conference, admin);
|
this.mCallManager.toggleCall(onCall, conference, admin, adminOnly);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
document.getElementById('mic-permission-overlay').remove();
|
document.getElementById('mic-permission-overlay').remove();
|
||||||
@@ -339,7 +341,7 @@ export default class Chat extends Component {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Handle Phone Call Error', err);
|
console.error('Handle Phone Call Error', err);
|
||||||
}
|
}
|
||||||
} else this.mCallManager.toggleCall(onCall, conference, admin);
|
} else this.mCallManager.toggleCall(onCall, conference, admin, adminOnly);
|
||||||
}
|
}
|
||||||
handleMute() {
|
handleMute() {
|
||||||
this.mCallManager.toggleMute(this.state.muted);
|
this.mCallManager.toggleMute(this.state.muted);
|
||||||
|
|||||||
+8
-1
@@ -1,13 +1,19 @@
|
|||||||
const FunctionModules = require('./modules/index');
|
const FunctionModules = require('./modules/index');
|
||||||
const FunctionModules2 = require('./modules2/index');
|
const FunctionModules2 = require('./modules2/index');
|
||||||
|
const Webhooks = require('./webhooks/index');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
|
|
||||||
|
// WEBHOOKS
|
||||||
|
const webhooks = express();
|
||||||
|
webhooks.use(cors({ origin: true }));
|
||||||
|
webhooks.all('/conferenceEnded',Webhooks.conferenceEnd);
|
||||||
|
|
||||||
// VERSION 1
|
// VERSION 1
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors({ origin: true }));
|
app.use(cors({ origin: true }));
|
||||||
app.use(FunctionModules.authenticator);
|
app.use(FunctionModules.authenticator);
|
||||||
app.get('/validator', FunctionModules.tokenValidator);
|
app.get('/validator/:partyName', FunctionModules.tokenValidator);
|
||||||
app.get('/refresher/:token', FunctionModules.tokenRefresher);
|
app.get('/refresher/:token', FunctionModules.tokenRefresher);
|
||||||
app.post('/create', FunctionModules.createRoom);
|
app.post('/create', FunctionModules.createRoom);
|
||||||
app.post('/join', FunctionModules.joinRoom);
|
app.post('/join', FunctionModules.joinRoom);
|
||||||
@@ -35,4 +41,5 @@ app2.delete('/delete/:rid', FunctionModules2.deleteRoom);
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
v1: app,
|
v1: app,
|
||||||
v2: app2,
|
v2: app2,
|
||||||
|
webhooks,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,3 +19,5 @@ exports.widgets2 = functions.https.onRequest(REST.v2);
|
|||||||
exports.scheduledCleanUp = functions.pubsub
|
exports.scheduledCleanUp = functions.pubsub
|
||||||
.schedule('every 60 minutes')
|
.schedule('every 60 minutes')
|
||||||
.onRun(FunctionModules.scheduledCleanUp);
|
.onRun(FunctionModules.scheduledCleanUp);
|
||||||
|
|
||||||
|
exports.webhooks = functions.https.onRequest(REST.webhooks);
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
const VoxeetSecret = require('../VoxeetSecret.json');
|
const VoxeetSecret = require('../VoxeetSecret.json');
|
||||||
|
const admin = require('firebase-admin');
|
||||||
const fetch = require('node-fetch');
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
module.exports = async (req, res) => {
|
module.exports = async (req, res) => {
|
||||||
|
const bodyData = JSON.parse(req.body);
|
||||||
const { key, secret } = VoxeetSecret;
|
const { key, secret } = VoxeetSecret;
|
||||||
const credentials = Buffer.from(encodeURI(key) + ':' + encodeURI(secret)).toString('base64');
|
const credentials = Buffer.from(encodeURI(key) + ':' + encodeURI(secret)).toString('base64');
|
||||||
const headers = {
|
const headers = {
|
||||||
@@ -14,8 +17,48 @@ module.exports = async (req, res) => {
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
grant_type: 'client_credentials',
|
grant_type: 'client_credentials',
|
||||||
}),
|
}),
|
||||||
})
|
}).then((oauthResponse) => oauthResponse.json())
|
||||||
.then((oauthResponse) => oauthResponse.json())
|
.catch((err) => res.status(500).send({err, message: 'Unable to generate token for call'}));
|
||||||
.catch((err) => res.status(500).send(err));
|
|
||||||
if (oauth) res.status(200).send(oauth);
|
const [exists, conferencePending, conference, adminOnly, adminUid] = await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(req.params.partyName)
|
||||||
|
.get()
|
||||||
|
.then(snap => {
|
||||||
|
const data = snap.exists ? snap.data() : {};
|
||||||
|
return [snap.exists, data.conferencePending, data.conference, data.adminOnly, data.adminUid];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exists === true) {
|
||||||
|
if (conference === undefined || conference === null) {
|
||||||
|
if (conferencePending === undefined || conferencePending === null) {
|
||||||
|
if (!adminOnly || (adminOnly && (adminUid === bodyData.uid)) ) {
|
||||||
|
await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(req.params.partyName)
|
||||||
|
.update({
|
||||||
|
conferencePending: bodyData.uid
|
||||||
|
});
|
||||||
|
await admin
|
||||||
|
.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(req.params.partyName)
|
||||||
|
.collection('messages')
|
||||||
|
.add({
|
||||||
|
uid: '<system>',
|
||||||
|
name: '',
|
||||||
|
text: 'A call session is being created (will be available soon).',
|
||||||
|
time: new Date(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oauth) res.status(200).send(oauth);
|
||||||
|
} else {
|
||||||
|
res.status(400).send({ message: 'Unable to get party for call.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,47 +1,68 @@
|
|||||||
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 } = JSON.parse(req.body);
|
const { conference, partyName, partyPin, userName, uid } = JSON.parse(req.body);
|
||||||
// GET ROOM PIN
|
// GET ROOM PIN
|
||||||
const roomPin = await admin
|
const [exists, roomPin, conferencePending, partyConference] = await admin
|
||||||
.firestore()
|
.firestore()
|
||||||
.collection('rooms')
|
.collection('rooms')
|
||||||
.doc(partyName)
|
.doc(partyName)
|
||||||
.get()
|
.get()
|
||||||
.then((roomSnap) => (roomSnap.exists ? roomSnap.data().pin : null));
|
.then((roomSnap) => {
|
||||||
|
const data = roomSnap.exists ? roomSnap.data() : {};
|
||||||
|
return [roomSnap.exists, data.pin, data.conferencePending, data.conference];
|
||||||
|
});
|
||||||
// CHECK IF ROOM EXISTS
|
// CHECK IF ROOM EXISTS
|
||||||
if (roomPin) {
|
if (exists === true) {
|
||||||
// CHECK FOR CORRECT PIN
|
if (roomPin) {
|
||||||
if (roomPin === partyPin) {
|
// CHECK FOR CORRECT PIN
|
||||||
// UPDATE CONFERENCE DETAILS
|
if (roomPin === partyPin) {
|
||||||
await admin
|
if (conferencePending) {
|
||||||
.firestore()
|
if (conferencePending === uid) {
|
||||||
.collection('rooms')
|
// UPDATE CONFERENCE DETAILS
|
||||||
.doc(partyName)
|
await admin
|
||||||
.update({ conference })
|
.firestore()
|
||||||
.catch((err) =>
|
.collection('rooms')
|
||||||
res.status(500).send({ message: 'Unable to update the call details', error: err })
|
.doc(partyName)
|
||||||
);
|
.update({ conference })
|
||||||
// ADD SYSTEM MESSAGE
|
.catch((err) =>
|
||||||
await admin
|
res.status(500).send({ message: 'Unable to update the call details', error: err })
|
||||||
.firestore()
|
);
|
||||||
.collection('rooms')
|
// REMOVE PENDING STATUS
|
||||||
.doc(partyName)
|
await admin
|
||||||
.collection('messages')
|
.firestore()
|
||||||
.add({
|
.collection('rooms')
|
||||||
uid: '<system>',
|
.doc(partyName)
|
||||||
name: '',
|
.update({ conferencePending : admin.firestore.FieldValue.delete() })
|
||||||
text: `${userName} started the call.`,
|
.catch((err) => console.error('Failed to remove pending status', err));
|
||||||
time: new Date(),
|
// ADD SYSTEM MESSAGE
|
||||||
})
|
await admin
|
||||||
.catch((err) => console.error('Failed to add update conference message', err));
|
.firestore()
|
||||||
res.status(200).send({ message: 'Started the conference' });
|
.collection('rooms')
|
||||||
} else {
|
.doc(partyName)
|
||||||
// WRONG ROOM PIN
|
.collection('messages')
|
||||||
return res.status(401).send({ message: 'Wrong party pin, try rejoining' });
|
.add({
|
||||||
|
uid: '<system>',
|
||||||
|
name: '',
|
||||||
|
text: `${userName} started the call, everyone can join now.`,
|
||||||
|
time: new Date(),
|
||||||
|
})
|
||||||
|
.catch((err) => console.error('Failed to add update conference message', err));
|
||||||
|
res.status(200).send({ message: 'Started the conference' });
|
||||||
|
} else {
|
||||||
|
res.status(409).send({ message: 'Looks like someone is already starting a call' });
|
||||||
|
}
|
||||||
|
} else if (partyConference) {
|
||||||
|
res.status(409).send({ message: 'Call already exists', conference: partyConference });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// WRONG ROOM PIN
|
||||||
|
res.status(401).send({ message: 'Wrong party pin, try rejoining' });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ROOM DOESN'T EXIST
|
// ROOM DOESN'T EXIST
|
||||||
return res.status(404).send({ message: 'Party Not Found' });
|
res.status(404).send({ message: 'Party Not Found' });
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
const admin = require('firebase-admin');
|
||||||
|
|
||||||
|
module.exports = async (req, res) => {
|
||||||
|
console.info(`[START]\tWEBHOOKS/Conference End\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`);
|
||||||
|
if (req.body.eventType === 'Conference.Ended') {
|
||||||
|
if (req.body.participants.length > 0) {
|
||||||
|
if (req.body.confAlias.startsWith('AUTODELETE_')) {
|
||||||
|
const partyName = req.body.confAlias.replace(/AUTODELETE_/, "");
|
||||||
|
admin.firestore()
|
||||||
|
.collection('rooms')
|
||||||
|
.doc(partyName)
|
||||||
|
.update({ conference: admin.firestore.FieldValue.delete() })
|
||||||
|
.then(() => {
|
||||||
|
console.info(`[DONE]\tWEBHOOKS/Conference End\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`);
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(`[ERROR]\tWEBHOOKS/Conference End/Firebase Error\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}\nError:${JSON.stringify(err)}`)
|
||||||
|
});
|
||||||
|
res.status(200).send({ message: 'Processed conference end'});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.info(`[DONE]\tWEBHOOKS/Conference End/End Of Duplicate Conference\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error(`[ERROR]\tWEBHOOKS/Conference End/Wrong Event Type\nID:${req.body.conference.confId}\nParty:${req.body.conference.confAlias}`)
|
||||||
|
res.status(400).send({ message: 'Wrong event type' });
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const conferenceEnd = require('./conferenceEnd');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
conferenceEnd,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user