168 lines
5.7 KiB
JavaScript
168 lines
5.7 KiB
JavaScript
import { FavoritesManager } from "./favorites";
|
|
import { GraphDisplayManager } from "./graph";
|
|
import { PercentageBar } from "./percbar";
|
|
import { ServerRegistry } from "./servers";
|
|
import { SocketManager } from "./socket";
|
|
import { SortController } from "./sort";
|
|
import { Caption, Tooltip, formatNumber } from "./util";
|
|
|
|
export class App {
|
|
publicConfig;
|
|
|
|
constructor() {
|
|
this.tooltip = new Tooltip();
|
|
this.caption = new Caption();
|
|
this.serverRegistry = new ServerRegistry(this);
|
|
this.socketManager = new SocketManager(this);
|
|
this.sortController = new SortController(this);
|
|
this.graphDisplayManager = new GraphDisplayManager(this);
|
|
this.percentageBar = new PercentageBar(this);
|
|
this.favoritesManager = new FavoritesManager(this);
|
|
|
|
this._taskIds = [];
|
|
}
|
|
|
|
// Called once the DOM is ready and the app can begin setup
|
|
init() {
|
|
this.socketManager.createWebSocket();
|
|
}
|
|
|
|
setPageReady(isReady) {
|
|
document.getElementById("push").style.display = isReady ? "block" : "none";
|
|
document.getElementById("footer").style.display = isReady
|
|
? "block"
|
|
: "none";
|
|
document.getElementById("status-overlay").style.display = isReady
|
|
? "none"
|
|
: "block";
|
|
}
|
|
|
|
setPublicConfig(publicConfig) {
|
|
this.publicConfig = publicConfig;
|
|
|
|
this.serverRegistry.assignServers(publicConfig.servers);
|
|
|
|
// Start repeating frontend tasks once it has received enough data to be considered active
|
|
// This simplifies management logic at the cost of each task needing to safely handle empty data
|
|
this.initTasks();
|
|
}
|
|
|
|
handleSyncComplete() {
|
|
this.caption.hide();
|
|
|
|
// Load favorites since all servers are registered
|
|
this.favoritesManager.loadLocalStorage();
|
|
|
|
// Run a single bulk server sort instead of per-add event since there may be multiple
|
|
this.sortController.show();
|
|
this.percentageBar.redraw();
|
|
|
|
// The data may not be there to correctly compute values, but run an attempt
|
|
// Otherwise they will be updated by #initTasks
|
|
this.updateGlobalStats();
|
|
}
|
|
|
|
initTasks() {
|
|
this._taskIds.push(setInterval(this.sortController.sortServers, 5000));
|
|
}
|
|
|
|
handleDisconnect() {
|
|
this.tooltip.hide();
|
|
|
|
// Reset individual tracker elements to flush any held data
|
|
this.serverRegistry.reset();
|
|
this.socketManager.reset();
|
|
this.sortController.reset();
|
|
this.graphDisplayManager.reset();
|
|
this.percentageBar.reset();
|
|
|
|
// Undefine publicConfig, resynced during the connection handshake
|
|
this.publicConfig = undefined;
|
|
|
|
// Clear all task ids, if any
|
|
this._taskIds.forEach(clearInterval);
|
|
|
|
this._taskIds = [];
|
|
|
|
// Reset hidden values created by #updateGlobalStats
|
|
this._lastTotalPlayerCount = undefined;
|
|
this._lastServerRegistrationCount = undefined;
|
|
|
|
// Reset modified DOM structures
|
|
document.getElementById("stat_totalPlayers").innerText = 0;
|
|
document.getElementById("stat_networks").innerText = 0;
|
|
|
|
this.setPageReady(false);
|
|
}
|
|
|
|
getTotalPlayerCount() {
|
|
return this.serverRegistry
|
|
.getServerRegistrations()
|
|
.map((serverRegistration) => serverRegistration.playerCount)
|
|
.reduce((sum, current) => sum + current, 0);
|
|
}
|
|
|
|
addServer = (serverId, payload, timestampPoints) => {
|
|
// Even if the backend has never pinged the server, the frontend is promised a placeholder object.
|
|
// result = undefined
|
|
// error = defined with "Waiting" description
|
|
// info = safely defined with configured data
|
|
const serverRegistration =
|
|
this.serverRegistry.createServerRegistration(serverId);
|
|
|
|
serverRegistration.initServerStatus(payload);
|
|
|
|
// playerCountHistory is only defined when the backend has previous ping data
|
|
// undefined playerCountHistory means this is a placeholder ping generated by the backend
|
|
if (typeof payload.playerCountHistory !== "undefined") {
|
|
// Push the historical data into the graph
|
|
// This will trim and format the data so it is ready for the graph to render once init
|
|
serverRegistration.addGraphPoints(
|
|
payload.playerCountHistory,
|
|
timestampPoints
|
|
);
|
|
|
|
// Set initial playerCount to the payload's value
|
|
// This will always exist since it is explicitly generated by the backend
|
|
// This is used for any post-add rendering of things like the percentageBar
|
|
serverRegistration.playerCount = payload.playerCount;
|
|
}
|
|
|
|
// Create the plot instance internally with the restructured and cleaned data
|
|
serverRegistration.buildPlotInstance();
|
|
|
|
// Handle the last known state (if any) as an incoming update
|
|
// This triggers the main update pipeline and enables centralized update handling
|
|
serverRegistration.updateServerStatus(
|
|
payload,
|
|
this.publicConfig.minecraftVersions
|
|
);
|
|
|
|
// Allow the ServerRegistration to bind any DOM events with app instance context
|
|
serverRegistration.initEventListeners();
|
|
};
|
|
|
|
updateGlobalStats = () => {
|
|
// Only redraw when needed
|
|
// These operations are relatively cheap, but the site already does too much rendering
|
|
const totalPlayerCount = this.getTotalPlayerCount();
|
|
|
|
if (totalPlayerCount !== this._lastTotalPlayerCount) {
|
|
this._lastTotalPlayerCount = totalPlayerCount;
|
|
document.getElementById("stat_totalPlayers").innerText =
|
|
formatNumber(totalPlayerCount);
|
|
}
|
|
|
|
// Only redraw when needed
|
|
// These operations are relatively cheap, but the site already does too much rendering
|
|
const serverRegistrationCount =
|
|
this.serverRegistry.getServerRegistrations().length;
|
|
|
|
if (serverRegistrationCount !== this._lastServerRegistrationCount) {
|
|
this._lastServerRegistrationCount = serverRegistrationCount;
|
|
document.getElementById("stat_networks").innerText =
|
|
serverRegistrationCount;
|
|
}
|
|
};
|
|
}
|