diff options
Diffstat (limited to 'src/server/DashStats.ts')
-rw-r--r-- | src/server/DashStats.ts | 244 |
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(); + } } } |