VersaWhiteboard/scripts/services/WhiteboardInfoBackendServic...

244 lines
6.8 KiB
JavaScript

const config = require("../config/config");
const ReadOnlyBackendService = require("./ReadOnlyBackendService");
/**
* Class to hold information related to a whiteboard
*/
class WhiteboardInfo {
static defaultScreenResolution = { w: 1000, h: 1000 };
/**
* @type {number}
* @private
*/
#nbConnectedUsers = 0;
get nbConnectedUsers() {
return this.#nbConnectedUsers;
}
/**
* @type {Map<string, {w: number, h: number}>}
* @private
*/
#screenResolutionByClients = new Map();
get screenResolutionByClients() {
return this.#screenResolutionByClients;
}
/**
* Variable to tell if these info have been sent or not
*
* @private
* @type {boolean}
*/
#hasNonSentUpdates = false;
get hasNonSentUpdates() {
return this.#hasNonSentUpdates;
}
incrementNbConnectedUsers() {
this.#nbConnectedUsers++;
this.#hasNonSentUpdates = true;
}
decrementNbConnectedUsers() {
this.#nbConnectedUsers--;
this.#hasNonSentUpdates = true;
}
hasConnectedUser() {
return this.#nbConnectedUsers > 0;
}
/**
* Store information about the client's screen resolution
*
* @param {string} clientId
* @param {number} w client's width
* @param {number} h client's hight
*/
setScreenResolutionForClient(clientId, { w, h }) {
this.#screenResolutionByClients.set(clientId, { w, h });
this.#hasNonSentUpdates = true;
}
/**
* Delete the stored information about the client's screen resoltion
* @param clientId
*/
deleteScreenResolutionOfClient(clientId) {
this.#screenResolutionByClients.delete(clientId);
this.#hasNonSentUpdates = true;
}
/**
* Get the smallest client's screen size on a whiteboard
* @return {{w: number, h: number}}
*/
getSmallestScreenResolution() {
const { screenResolutionByClients: resolutions } = this;
return {
w: Math.min(...Array.from(resolutions.values()).map((res) => res.w)),
h: Math.min(...Array.from(resolutions.values()).map((res) => res.h)),
};
}
infoWasSent() {
this.#hasNonSentUpdates = false;
}
shouldSendInfo() {
return this.#hasNonSentUpdates;
}
asObject() {
const out = {
nbConnectedUsers: this.#nbConnectedUsers,
};
if (config.frontend.showSmallestScreenIndicator) {
out.smallestScreenResolution = this.getSmallestScreenResolution();
}
return out;
}
}
/**
* Wrapper class around map to treat both the editable whiteboard and its read-only version the same
*/
class InfoByWhiteBoardMap extends Map {
get(wid) {
const readOnlyId = ReadOnlyBackendService.getReadOnlyId(wid);
return super.get(readOnlyId);
}
set(wid, val) {
const readOnlyId = ReadOnlyBackendService.getReadOnlyId(wid);
return super.set(readOnlyId, val);
}
has(wid) {
const readOnlyId = ReadOnlyBackendService.getReadOnlyId(wid);
return super.has(readOnlyId);
}
delete(wid) {
const readOnlyId = ReadOnlyBackendService.getReadOnlyId(wid);
return super.delete(readOnlyId);
}
}
class WhiteboardInfoBackendService {
/**
* @type {Map<string, WhiteboardInfo>}
*/
#infoByWhiteboard = new InfoByWhiteBoardMap();
/**
* Start the auto sending of information to all the whiteboards
*
* @param io
*/
start(io) {
// auto clean infoByWhiteboard
setInterval(() => {
this.#infoByWhiteboard.forEach((info, readOnlyWhiteboardId) => {
if (info.shouldSendInfo()) {
// broadcast to editable whiteboard
const wid = ReadOnlyBackendService.getIdFromReadOnlyId(readOnlyWhiteboardId);
io.sockets
.in(wid)
.compress(false)
.emit("whiteboardInfoUpdate", info.asObject());
// also send to readonly whiteboard
io.sockets
.in(readOnlyWhiteboardId)
.compress(false)
.emit("whiteboardInfoUpdate", info.asObject());
info.infoWasSent();
}
});
}, (1 / config.backend.performance.whiteboardInfoBroadcastFreq) * 1000);
}
/**
* Track a join event of client to a whiteboard
*
* @param {string} clientId
* @param {string} whiteboardId
* @param {{w: number, h: number}} screenResolution
*/
join(clientId, whiteboardId, screenResolution) {
const infoByWhiteboard = this.#infoByWhiteboard;
if (!infoByWhiteboard.has(whiteboardId)) {
infoByWhiteboard.set(whiteboardId, new WhiteboardInfo());
}
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
whiteboardServerSideInfo.incrementNbConnectedUsers();
this.setScreenResolution(clientId, whiteboardId, screenResolution);
}
/**
* Set the screen resolution of a client
* @param {string} clientId
* @param {string} whiteboardId
* @param {{w: number, h: number}} screenResolution
*/
setScreenResolution(clientId, whiteboardId, screenResolution) {
const infoByWhiteboard = this.#infoByWhiteboard;
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
if (whiteboardServerSideInfo) {
whiteboardServerSideInfo.setScreenResolutionForClient(
clientId,
screenResolution || WhiteboardInfo.defaultScreenResolution
);
}
}
/**
* Track disconnect from a client
* @param {string} clientId
* @param {string} whiteboardId
*/
leave(clientId, whiteboardId) {
const infoByWhiteboard = this.#infoByWhiteboard;
if (infoByWhiteboard.has(whiteboardId)) {
const whiteboardServerSideInfo = infoByWhiteboard.get(whiteboardId);
if (clientId) {
whiteboardServerSideInfo.deleteScreenResolutionOfClient(clientId);
}
whiteboardServerSideInfo.decrementNbConnectedUsers();
if (whiteboardServerSideInfo.hasConnectedUser()) {
} else {
infoByWhiteboard.delete(whiteboardId);
}
}
}
/**
* Get the number of clients on a whiteboard
*
* @param {string} wid
* @returns number|null
*/
getNbClientOnWhiteboard(wid) {
const infoByWhiteboard = this.#infoByWhiteboard;
const info = infoByWhiteboard.get(wid);
if (info) return info.nbConnectedUsers;
else return null;
}
}
module.exports = new WhiteboardInfoBackendService();