aboutsummaryrefslogtreecommitdiff
path: root/src/server/DashStats.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/DashStats.ts')
-rw-r--r--src/server/DashStats.ts244
1 files changed, 118 insertions, 126 deletions
diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts
index a9e6af67c..808d2c6f2 100644
--- a/src/server/DashStats.ts
+++ b/src/server/DashStats.ts
@@ -1,9 +1,7 @@
import { cyan, magenta } from 'colors';
import { Response } from 'express';
-import SocketIO from 'socket.io';
-import { timeMap } from './ApiManagers/UserManager';
-import { WebSocket } from './websocket';
import * as fs from 'fs';
+import { socketMap, timeMap, userOperations } from './SocketData';
/**
* DashStats focuses on tracking user data for each session.
@@ -17,7 +15,6 @@ export namespace DashStats {
const statsCSVDirectory = './src/server/stats/';
const statsCSVFilename = statsCSVDirectory + 'userLoginStats.csv';
- const columns = ['USERNAME', 'ACTION', 'TIME'];
/**
* UserStats holds the stats associated with a particular user.
@@ -78,111 +75,14 @@ export namespace DashStats {
export const lastUserOperations = new Map<string, UserLastOperations>();
/**
- * handleStats is called when the /stats route is called, providing a JSON
- * object with relevant stats. In this case, we return the number of
- * current connections and
- * @param res Response object from Express
- */
- export function handleStats(res: Response) {
- let current = getCurrentStats();
- const results: CSVStore[] = [];
- res.json({
- currentConnections: current.length,
- socketMap: current,
- });
- }
-
- /**
- * getUpdatedStatesBundle() sends an updated copy of the current stats to the
- * frontend /statsview route via websockets.
- *
- * @returns a StatsDataBundle that is sent to the frontend view on each websocket update
- */
- export function getUpdatedStatsBundle(): StatsDataBundle {
- let current = getCurrentStats();
-
- return {
- connectedUsers: current,
- };
- }
-
- /**
- * handleStatsView() is called when the /statsview route is called. This
- * will use pug to render a frontend view of the current stats
- *
- * @param res
- */
- export function handleStatsView(res: Response) {
- let current = getCurrentStats();
-
- let connectedUsers = current.map(socketPair => {
- return socketPair.time + ' - ' + socketPair.username + ' Operations: ' + socketPair.operations;
- });
-
- let serverTraffic = ServerTraffic.NOT_BUSY;
- if (current.length < BUSY_SERVER_BOUND) {
- serverTraffic = ServerTraffic.NOT_BUSY;
- } else if (current.length >= BUSY_SERVER_BOUND && current.length < VERY_BUSY_SERVER_BOUND) {
- serverTraffic = ServerTraffic.BUSY;
- } else {
- serverTraffic = ServerTraffic.VERY_BUSY;
- }
-
- res.render('stats.pug', {
- title: 'Dash Stats',
- numConnections: connectedUsers.length,
- serverTraffic: serverTraffic,
- serverTrafficMessage: serverTrafficMessages[serverTraffic],
- connectedUsers: connectedUsers,
- });
- }
-
- /**
- * logUserLogin() writes a login event to the CSV file.
- *
- * @param username the username in the format of "username@domain.com logged in"
- * @param socket the websocket associated with the current connection
- */
- export function logUserLogin(username: string | undefined, socket: SocketIO.Socket) {
- if (!(username === undefined)) {
- let currentDate = new Date();
- console.log(magenta(`User ${username.split(' ')[0]} logged in at: ${currentDate.toISOString()}`));
-
- let toWrite: CSVStore = {
- USERNAME: username,
- ACTION: 'loggedIn',
- TIME: currentDate.toISOString(),
- };
-
- if (!fs.existsSync(statsCSVDirectory)) fs.mkdirSync(statsCSVDirectory);
- let statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' });
- statsFile.write(convertToCSV(toWrite));
- statsFile.end();
- console.log(cyan(convertToCSV(toWrite)));
- }
- }
-
- /**
- * logUserLogout() writes a logout event to the CSV file.
- *
- * @param username the username in the format of "username@domain.com logged in"
- * @param socket the websocket associated with the current connection.
+ * convertToCSV() is a helper method that stringifies a CSVStore object
+ * that can be written to the CSV file later.
+ * @param dataObject the object to stringify
+ * @returns the object as a string.
*/
- export function logUserLogout(username: string | undefined, socket: SocketIO.Socket) {
- if (!(username === undefined)) {
- let currentDate = new Date();
-
- let statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' });
- let toWrite: CSVStore = {
- USERNAME: username,
- ACTION: 'loggedOut',
- TIME: currentDate.toISOString(),
- };
- statsFile.write(convertToCSV(toWrite));
- statsFile.end();
- }
+ function convertToCSV(dataObject: CSVStore): string {
+ return `${dataObject.USERNAME},${dataObject.ACTION},${dataObject.TIME}\n`;
}
-
/**
* getLastOperationsOrDefault() is a helper method that will attempt
* to query the lastUserOperations map for a specified username. If the
@@ -193,7 +93,7 @@ export namespace DashStats {
*/
function getLastOperationsOrDefault(username: string): UserLastOperations {
if (lastUserOperations.get(username) === undefined) {
- let initializeOperationsQueue = [];
+ const initializeOperationsQueue = [];
for (let i = 0; i < RATE_INTERVAL; i++) {
initializeOperationsQueue.push(0);
}
@@ -217,7 +117,7 @@ export namespace DashStats {
*/
function updateLastOperations(lastOperationData: UserLastOperations, currentOperations: number): UserLastOperations {
// create a copy of the UserLastOperations to modify
- let newLastOperationData: UserLastOperations = {
+ const newLastOperationData: UserLastOperations = {
sampleOperations: lastOperationData.sampleOperations,
lastSampleOperations: lastOperationData.lastSampleOperations,
previousOperationsQueue: lastOperationData.previousOperationsQueue.slice(),
@@ -225,7 +125,7 @@ export namespace DashStats {
let newSampleOperations = newLastOperationData.sampleOperations;
newSampleOperations -= newLastOperationData.previousOperationsQueue.shift()!; // removes and returns the first element of the queue
- let operationsThisCycle = currentOperations - lastOperationData.lastSampleOperations;
+ const operationsThisCycle = currentOperations - lastOperationData.lastSampleOperations;
newSampleOperations += operationsThisCycle; // add the operations this cycle to find out what our count for the interval should be (e.g operations in the last 10 seconds)
// update values for the copy object
@@ -245,7 +145,7 @@ export namespace DashStats {
* @returns the total number of operations recorded up to this sampling cycle.
*/
function getUserOperationsOrDefault(username: string): number {
- return WebSocket.userOperations.get(username) === undefined ? 0 : WebSocket.userOperations.get(username)!;
+ return userOperations.get(username) === undefined ? 0 : userOperations.get(username)!;
}
/**
@@ -255,37 +155,129 @@ export namespace DashStats {
* @returns an array of UserStats storing data for each user at the current moment.
*/
function getCurrentStats(): UserStats[] {
- let socketPairs: UserStats[] = [];
- for (let [key, value] of WebSocket.socketMap) {
- let username = value.split(' ')[0];
- let connectionTime = new Date(timeMap[username]);
+ const socketPairs: UserStats[] = [];
+ Array.from(socketMap.entries()).forEach(([key, value]) => {
+ const username = value.split(' ')[0];
+ const connectionTime = new Date(timeMap[username]);
- let connectionTimeString = connectionTime.toLocaleDateString() + ' ' + connectionTime.toLocaleTimeString();
+ const connectionTimeString = connectionTime.toLocaleDateString() + ' ' + connectionTime.toLocaleTimeString();
if (!key.disconnected) {
- let lastRecordedOperations = getLastOperationsOrDefault(username);
- let currentUserOperationCount = getUserOperationsOrDefault(username);
+ const lastRecordedOperations = getLastOperationsOrDefault(username);
+ const currentUserOperationCount = getUserOperationsOrDefault(username);
socketPairs.push({
socketId: key.id,
username: username,
time: connectionTimeString.includes('Invalid Date') ? '' : connectionTimeString,
- operations: WebSocket.userOperations.get(username) ? WebSocket.userOperations.get(username)! : 0,
+ operations: userOperations.get(username) ? userOperations.get(username)! : 0,
rate: lastRecordedOperations.sampleOperations,
});
lastUserOperations.set(username, updateLastOperations(lastRecordedOperations, currentUserOperationCount));
}
- }
+ });
return socketPairs;
}
/**
- * convertToCSV() is a helper method that stringifies a CSVStore object
- * that can be written to the CSV file later.
- * @param dataObject the object to stringify
- * @returns the object as a string.
+ * handleStats is called when the /stats route is called, providing a JSON
+ * object with relevant stats. In this case, we return the number of
+ * current connections and
+ * @param res Response object from Express
*/
- function convertToCSV(dataObject: CSVStore): string {
- return `${dataObject.USERNAME},${dataObject.ACTION},${dataObject.TIME}\n`;
+ export function handleStats(res: Response) {
+ const current = getCurrentStats();
+ res.json({
+ currentConnections: current.length,
+ socketMap: current,
+ });
+ }
+
+ /**
+ * getUpdatedStatesBundle() sends an updated copy of the current stats to the
+ * frontend /statsview route via websockets.
+ *
+ * @returns a StatsDataBundle that is sent to the frontend view on each websocket update
+ */
+ export function getUpdatedStatsBundle(): StatsDataBundle {
+ const current = getCurrentStats();
+
+ return {
+ connectedUsers: current,
+ };
+ }
+
+ /**
+ * handleStatsView() is called when the /statsview route is called. This
+ * will use pug to render a frontend view of the current stats
+ *
+ * @param res
+ */
+ export function handleStatsView(res: Response) {
+ const current = getCurrentStats();
+ const connectedUsers = current.map(({ time, username, operations }) => time + ' - ' + username + ' Operations: ' + operations);
+
+ let serverTraffic = ServerTraffic.NOT_BUSY;
+ if (current.length < BUSY_SERVER_BOUND) {
+ serverTraffic = ServerTraffic.NOT_BUSY;
+ } else if (current.length >= BUSY_SERVER_BOUND && current.length < VERY_BUSY_SERVER_BOUND) {
+ serverTraffic = ServerTraffic.BUSY;
+ } else {
+ serverTraffic = ServerTraffic.VERY_BUSY;
+ }
+
+ res.render('stats.pug', {
+ title: 'Dash Stats',
+ numConnections: connectedUsers.length,
+ serverTraffic: serverTraffic,
+ serverTrafficMessage: serverTrafficMessages[serverTraffic],
+ connectedUsers: connectedUsers,
+ });
+ }
+
+ /**
+ * logUserLogin() writes a login event to the CSV file.
+ *
+ * @param username the username in the format of "username@domain.com logged in"
+ * @param socket the websocket associated with the current connection
+ */
+ export function logUserLogin(username: string | undefined) {
+ if (!(username === undefined)) {
+ const currentDate = new Date();
+ console.log(magenta(`User ${username.split(' ')[0]} logged in at: ${currentDate.toISOString()}`));
+
+ const toWrite: CSVStore = {
+ USERNAME: username,
+ ACTION: 'loggedIn',
+ TIME: currentDate.toISOString(),
+ };
+
+ if (!fs.existsSync(statsCSVDirectory)) fs.mkdirSync(statsCSVDirectory);
+ const statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' });
+ statsFile.write(convertToCSV(toWrite));
+ statsFile.end();
+ console.log(cyan(convertToCSV(toWrite)));
+ }
+ }
+
+ /**
+ * logUserLogout() writes a logout event to the CSV file.
+ *
+ * @param username the username in the format of "username@domain.com logged in"
+ * @param socket the websocket associated with the current connection.
+ */
+ export function logUserLogout(username: string | undefined) {
+ if (!(username === undefined)) {
+ const currentDate = new Date();
+
+ const statsFile = fs.createWriteStream(statsCSVFilename, { flags: 'a' });
+ const toWrite: CSVStore = {
+ USERNAME: username,
+ ACTION: 'loggedOut',
+ TIME: currentDate.toISOString(),
+ };
+ statsFile.write(convertToCSV(toWrite));
+ statsFile.end();
+ }
}
}