moved requests from Firestore to Realtime DB

optimize-reads
Simon Huang 6 years ago
parent a5d20f5d16
commit 5cdf300651

@ -21,14 +21,6 @@ const collection = {
roomId: { roomId: {
createdAt: 'timestamp', createdAt: 'timestamp',
ownerId: 'userId', ownerId: 'userId',
requests: [
{
createdAt: 'timestamp',
data: '01:25:44', // Contents of data depend on type of request
type: 'updateState',
senderId: 'userId',
},
],
}, },
}, },
], ],
@ -69,6 +61,18 @@ const turtle = {
}, },
}, },
// Keeping state requests in Realtime DB could also lower cost
requests: {
roomId: {
requestId: {
createdAt: '2020-10-31T00:12:14.234Z',
data: '01:25:44', // Contents of data depend on type of request
type: 'updateState',
senderId: 'userId',
},
},
},
// Keeping track of which users are present in a room // Keeping track of which users are present in a room
rooms: { rooms: {
roomId: { roomId: {

@ -1,7 +1,7 @@
import { IonCol, IonContent, IonFabButton, IonGrid, IonIcon, IonInput, IonRow, IonToolbar } from '@ionic/react'; import { IonCol, IonContent, IonFabButton, IonGrid, IonIcon, IonInput, IonRow, IonToolbar } from '@ionic/react';
import { sendOutline } from 'ionicons/icons'; import { sendOutline } from 'ionicons/icons';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { db, rtdb } from '../services/firebase'; import { rtdb } from '../services/firebase';
import { secondsToTimestamp } from '../services/utilities'; import { secondsToTimestamp } from '../services/utilities';
import './Messages.css'; import './Messages.css';
@ -56,16 +56,9 @@ const Messages: React.FC<MessagesProps> = ({ pane, ownerId, roomId, userId, user
// Listen for new system messages // Listen for new system messages
useEffect(() => { useEffect(() => {
const roomUnsubscribe = db
.collection('rooms')
.doc(roomId)
.onSnapshot((docSnapshot) => {
const docData = docSnapshot.data();
if (docData !== undefined) {
const requests = docData.requests;
let arr: Message[] = []; let arr: Message[] = [];
for (const req of requests) { rtdb.ref('/requests/' + roomId).on('child_added', (snapshot) => {
const req = snapshot.val();
if (req.createdAt > joinTime && req.type !== 'updateState') { if (req.createdAt > joinTime && req.type !== 'updateState') {
arr.push({ arr.push({
content: processType(req.type, req.data), content: processType(req.type, req.data),
@ -74,14 +67,13 @@ const Messages: React.FC<MessagesProps> = ({ pane, ownerId, roomId, userId, user
senderId: req.senderId, senderId: req.senderId,
type: req.type, type: req.type,
}); });
} let copyArr = [...arr];
} setSystemMessages(copyArr);
setSystemMessages(arr);
} }
}); });
return () => { return () => {
roomUnsubscribe(); rtdb.ref('/requests/' + roomId).off('child_added');
}; };
}, [roomId, joinTime]); }, [roomId, joinTime]);

@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import ReactPlayer from 'react-player'; import ReactPlayer from 'react-player';
import { arrayUnion, db } from '../../services/firebase'; import { db, rtdb } from '../../services/firebase';
import { SYNC_MARGIN } from '../../services/utilities'; import { SYNC_MARGIN } from '../../services/utilities';
type ReactPlayerFrameProps = { type ReactPlayerFrameProps = {
@ -25,11 +25,7 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
time: currTime, time: currTime,
}); });
db.collection('rooms') rtdb.ref('/requests/' + roomId).push({ createdAt: Date.now(), senderId: userId, data: currTime, type: 'play' });
.doc(roomId)
.update({
requests: arrayUnion({ createdAt: Date.now(), senderId: userId, data: currTime, type: 'play' }),
});
} }
} }
}; };
@ -45,11 +41,9 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
time: currTime, time: currTime,
}); });
db.collection('rooms') rtdb
.doc(roomId) .ref('/requests/' + roomId)
.update({ .push({ createdAt: Date.now(), senderId: userId, data: currTime, type: 'pause' });
requests: arrayUnion({ createdAt: Date.now(), senderId: userId, data: currTime, type: 'pause' }),
});
} }
} }
}; };
@ -57,14 +51,12 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
// Listen for requests from Firebase (owner only) // Listen for requests from Firebase (owner only)
useEffect(() => { useEffect(() => {
if (ownerId === userId) { if (ownerId === userId) {
const roomRef = db.collection('rooms').doc(roomId);
const stateRef = db.collection('states').doc(roomId); const stateRef = db.collection('states').doc(roomId);
const requestRef = rtdb.ref('/requests/' + roomId);
// Add a listener to 'rooms' collection, listening for updateState requests // Add a listener to 'rooms' collection, listening for updateState requests
const roomUnsubscribe = roomRef.onSnapshot((docSnapshot) => { requestRef.limitToLast(1).on('child_added', (snapshot) => {
const requests = docSnapshot.data()?.requests; const req = snapshot.val();
const req = requests[requests.length - 1];
if (!!req && req.type === 'updateState' && req.senderId !== userId) { if (!!req && req.type === 'updateState' && req.senderId !== userId) {
const currTime = player.current?.getCurrentTime(); const currTime = player.current?.getCurrentTime();
if (currTime !== undefined) { if (currTime !== undefined) {
@ -77,7 +69,7 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
}); });
return () => { return () => {
roomUnsubscribe(); requestRef.limitToLast(1).off('child_added');
}; };
} }
}, [ownerId, roomId, userId]); }, [ownerId, roomId, userId]);
@ -85,11 +77,7 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
// Request an update after buffering is finished (member only) // Request an update after buffering is finished (member only)
const onBufferEnd = () => { const onBufferEnd = () => {
if (ownerId !== userId) { if (ownerId !== userId) {
db.collection('rooms') rtdb.ref('/requests/' + roomId).push({ createdAt: Date.now(), senderId: userId, data: 0, type: 'updateState' });
.doc(roomId)
.update({
requests: arrayUnion({ createdAt: Date.now(), senderId: userId, data: 0, type: 'updateState' }),
});
} }
}; };
@ -97,7 +85,7 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
useEffect(() => { useEffect(() => {
if (ownerId !== userId) { if (ownerId !== userId) {
const stateRef = db.collection('states').doc(roomId); const stateRef = db.collection('states').doc(roomId);
const roomRef = db.collection('rooms').doc(roomId); const requestRef = rtdb.ref('/requests/' + roomId);
let allowUpdate = true; let allowUpdate = true;
// listen to 'states' collection for video state changes from owner // listen to 'states' collection for video state changes from owner
@ -118,9 +106,7 @@ const ReactPlayerFrame: React.FC<ReactPlayerFrameProps> = ({ ownerId, userId, ro
}, 5000); }, 5000);
player.current?.seekTo(realTimeState); player.current?.seekTo(realTimeState);
roomRef.update({ requestRef.push({ createdAt: Date.now(), senderId: userId, data: 0, type: 'updateState' });
requests: arrayUnion({ createdAt: Date.now(), senderId: userId, data: 0, type: 'updateState' }),
});
} }
} }
}); });

@ -2,7 +2,7 @@ import { IonFabButton, IonIcon, IonInput, IonTitle, IonToolbar } from '@ionic/re
import { add } from 'ionicons/icons'; import { add } from 'ionicons/icons';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { db, arrayUnion } from '../services/firebase'; import { db, rtdb } from '../services/firebase';
import './RoomHeader.css'; import './RoomHeader.css';
type RoomHeaderProps = { type RoomHeaderProps = {
@ -21,13 +21,7 @@ const RoomHeader: React.FC<RoomHeaderProps> = ({ roomId, userId, ownerId }) => {
url: videoUrl, url: videoUrl,
}); });
await db await rtdb.ref('/requests/' + roomId).push({ createdAt: Date.now(), senderId: userId, data: 0, type: 'change' });
.collection('rooms')
.doc(roomId)
.update({
requests: arrayUnion({ createdAt: Date.now(), senderId: userId, data: 0, type: 'change' }),
});
setVideoUrl(''); setVideoUrl('');
} }
}; };

@ -17,7 +17,7 @@ import {
import { logoGithub } from 'ionicons/icons'; import { logoGithub } from 'ionicons/icons';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Controller, useForm } from 'react-hook-form'; import { Controller, useForm } from 'react-hook-form';
import { arrayUnion, db, rtdb } from '../services/firebase'; import { db, rtdb } from '../services/firebase';
import './Settings.css'; import './Settings.css';
type SettingsProps = { type SettingsProps = {
@ -42,16 +42,9 @@ const Settings: React.FC<SettingsProps> = ({ pane, roomId, userId }) => {
rtdb.ref('/rooms/' + roomId + '/' + userId).set({ name: newName }); rtdb.ref('/rooms/' + roomId + '/' + userId).set({ name: newName });
// Send 'nameChange' request for all clients to get a message about the name change // Send 'nameChange' request for all clients to get a message about the name change
db.collection('rooms') rtdb
.doc(roomId) .ref('/requests/' + roomId)
.update({ .push({ createdAt: Date.now(), senderId: userId, data: { prev: prevName, curr: newName }, type: 'nameChange' });
requests: arrayUnion({
createdAt: Date.now(),
senderId: userId,
data: { prev: prevName, curr: newName },
type: 'nameChange',
}),
});
setShowNameChange(true); setShowNameChange(true);
} }
@ -103,12 +96,12 @@ const Settings: React.FC<SettingsProps> = ({ pane, roomId, userId }) => {
<IonRow class="externals-row"> <IonRow class="externals-row">
<IonCol size="3"></IonCol> <IonCol size="3"></IonCol>
<IonCol size="3"> <IonCol size="3">
<IonRouterLink href="https://github.com/shuang854/Turtle" target="_blank"> <IonRouterLink href="https://github.com/shuang854/Turtle" target="_blank" rel="noopener noreferrer">
<IonIcon icon={logoGithub} class="about-icons"></IonIcon> <IonIcon icon={logoGithub} class="about-icons"></IonIcon>
</IonRouterLink> </IonRouterLink>
</IonCol> </IonCol>
<IonCol size="3"> <IonCol size="3">
<IonRouterLink href="https://discord.gg/NEw3Msu" target="_blank"> <IonRouterLink href="https://discord.gg/NEw3Msu" target="_blank" rel="noopener noreferrer">
<Icon icon={discordIcon} className="about-icons"></Icon> <Icon icon={discordIcon} className="about-icons"></Icon>
</IonRouterLink> </IonRouterLink>
</IonCol> </IonCol>

@ -52,8 +52,6 @@ const Home: React.FC = () => {
const roomId = await db.collection('rooms').add({ const roomId = await db.collection('rooms').add({
createdAt: timestamp, createdAt: timestamp,
ownerId: userId, ownerId: userId,
requests: [],
state: { time: 0, isPlaying: false },
}); });
await db.collection('playlists').doc(roomId.id).set({ await db.collection('playlists').doc(roomId.id).set({
createdAt: timestamp, createdAt: timestamp,
@ -112,7 +110,7 @@ const Home: React.FC = () => {
</IonRow> </IonRow>
<IonRow> <IonRow>
<IonCol class="request-col"> <IonCol class="request-col">
<a href="https://discord.gg/NEw3Msu" target="_blank"> <a href="https://discord.gg/NEw3Msu" target="_blank" rel="noopener noreferrer">
Request more options Request more options
</a> </a>
</IonCol> </IonCol>

Loading…
Cancel
Save