Conference: correction détection déconnexion

This commit is contained in:
wpetit 2020-10-12 21:56:19 +02:00
parent 6f757002b1
commit 0b93b0875e
2 changed files with 40 additions and 30 deletions

View File

@ -13,22 +13,23 @@ const StatusThumbsUp = 'thumbs-up';
const StatusThumbsDown = 'thumbs-down'; const StatusThumbsDown = 'thumbs-down';
const StatusNoVote = 'no-vote'; const StatusNoVote = 'no-vote';
const HeartbeatInterval = 5000;
export const ConferencePage:FunctionComponent<ConferencePageProps> = () => { export const ConferencePage:FunctionComponent<ConferencePageProps> = () => {
const { user } = useUserProfile(); const { user } = useUserProfile();
const { id, data, peers, setNickname, setEmail, ping, setStatus } = useConference(); const { uuid, data, setNickname, setEmail, ping, setStatus, forget } = useConference();
const currentStatus = data.statuses[id]; const currentStatus = data.statuses[uuid];
useEffect(() => { useEffect(() => {
if (peers.length === 0) return; if (!user.name && !user.email) return;
if (!id || (!user.name && !user.email)) return;
setNickname(user.name || user.email.split('@')[0]); setNickname(user.name || user.email.split('@')[0]);
setEmail(user.email); setEmail(user.email);
}, [user.name, user.email, peers.length]); }, [user.name, user.email]);
useEffect(() => { useEffect(() => {
ping(); ping();
const intervalId = setInterval(() => ping(), 30000); const intervalId = setInterval(() => ping(), HeartbeatInterval);
return () => clearInterval(intervalId); return () => clearInterval(intervalId);
}, []); }, []);
@ -78,11 +79,21 @@ export const ConferencePage:FunctionComponent<ConferencePageProps> = () => {
<h3 className="is-size-3">Assemblée</h3> <h3 className="is-size-3">Assemblée</h3>
<div className="columns mt-1"> <div className="columns mt-1">
<UserCard className="column is-narrow" <UserCard className="column is-narrow"
nickname={data.nicknames[id]} nickname={data.nicknames[uuid]}
status={currentStatus} status={currentStatus}
email={user.email} /> email={user.email} />
{ {
peers.map(p => { Object.keys(data.peers).map(p => {
const now = new Date();
const lastHeartBeat = new Date(data.peers[p]);
if (p === uuid) return null;
if (now.getTime() > lastHeartBeat.getTime() + HeartbeatInterval) {
forget(p);
return null;
}
const nickname = data.nicknames[p] || '???'; const nickname = data.nicknames[p] || '???';
const email = data.emails[p] || ''; const email = data.emails[p] || '';
return ( return (

View File

@ -1,19 +1,21 @@
import * as Y from 'yjs' import * as Y from 'yjs'
import { WebrtcProvider, } from 'y-webrtc' import { WebrtcProvider, } from 'y-webrtc'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { uuidV4 } from '../util/uuid';
const uuid = uuidV4();
export function useConference() { export function useConference() {
const docRef = useRef(new Y.Doc()); const docRef = useRef(new Y.Doc());
const [ state, setState ] = useState({ const [ state, setState ] = useState({
data: { data: {
heartbeats: {},
emails: {}, emails: {},
nicknames: {}, nicknames: {},
statuses: {}, statuses: {},
peers: {},
}, },
peers: [], uuid,
id: null,
}); });
const setData = (key: string, value: any) => { const setData = (key: string, value: any) => {
@ -25,17 +27,8 @@ export function useConference() {
const roomName = `${window.location.protocol}//${window.location.host}/daddy/conference`; const roomName = `${window.location.protocol}//${window.location.host}/daddy/conference`;
const provider = new WebrtcProvider(roomName, docRef.current); const provider = new WebrtcProvider(roomName, docRef.current);
const onPeers = (evt) => { const peers = doc.getMap('peers');
let peers = [...state.peers]; peers.observe(evt => setData('peers', evt.currentTarget.toJSON()));
peers = peers.filter(p => evt.removed.indexOf(p) === -1);
peers.push(...evt.added);
setState(state => ({ ...state, id: provider.room.peerId, peers }));
};
provider.on('peers', onPeers);
const heartbeats = doc.getMap('heartbeats');
heartbeats.observe(evt => setData('heartbeats', evt.currentTarget.toJSON()));
const nicknames = doc.getMap('nicknames'); const nicknames = doc.getMap('nicknames');
nicknames.observe(evt => setData('nicknames', evt.currentTarget.toJSON())); nicknames.observe(evt => setData('nicknames', evt.currentTarget.toJSON()));
@ -47,7 +40,6 @@ export function useConference() {
statuses.observe(evt => setData('statuses', evt.currentTarget.toJSON())); statuses.observe(evt => setData('statuses', evt.currentTarget.toJSON()));
return () => { return () => {
provider.off('peers', onPeers);
provider.destroy(); provider.destroy();
docRef.current.destroy(); docRef.current.destroy();
}; };
@ -55,31 +47,38 @@ export function useConference() {
return { return {
data: state.data, data: state.data,
peers: state.peers, uuid: state.uuid,
id: state.id,
setStatus: (status: string) => { setStatus: (status: string) => {
const doc = docRef.current; const doc = docRef.current;
const statuses = doc.getMap('statuses'); const statuses = doc.getMap('statuses');
statuses.set(state.id, status); statuses.set(state.uuid, status);
}, },
ping: () => { ping: () => {
const doc = docRef.current; const doc = docRef.current;
const heartbeats = doc.getMap('heartbeats'); const peers = doc.getMap('peers');
heartbeats.set(state.id, (new Date()).toJSON()); peers.set(state.uuid, (new Date()).toJSON());
}, },
setNickname: (nickname: string) => { setNickname: (nickname: string) => {
console.log('setNickname', nickname);
const doc = docRef.current; const doc = docRef.current;
const nicknames = doc.getMap('nicknames'); const nicknames = doc.getMap('nicknames');
nicknames.set(state.id, nickname); nicknames.set(state.uuid, nickname);
}, },
setEmail: (email: string) => { setEmail: (email: string) => {
console.log('setEmail', email);
const doc = docRef.current; const doc = docRef.current;
const emails = doc.getMap('emails'); const emails = doc.getMap('emails');
emails.set(state.id, email); emails.set(state.uuid, email);
},
forget: (uuid: string) => {
const doc = docRef.current;
const peers = doc.getMap('peers');
peers.delete(uuid);
}, },
}; };
} }