diff options
-rw-r--r-- | src/server/Client.ts | 13 | ||||
-rw-r--r-- | src/server/DashStats.ts | 119 | ||||
-rw-r--r-- | src/server/index.ts | 6 | ||||
-rw-r--r-- | src/server/stats/userLoginStats.csv | 77 | ||||
-rw-r--r-- | src/server/websocket.ts | 24 | ||||
-rw-r--r-- | views/stats.pug | 22 | ||||
-rw-r--r-- | views/stylesheets/statsview.css | 56 |
7 files changed, 290 insertions, 27 deletions
diff --git a/src/server/Client.ts b/src/server/Client.ts index e6f953712..be1ffc2ba 100644 --- a/src/server/Client.ts +++ b/src/server/Client.ts @@ -1,11 +1,22 @@ -import { computed } from "mobx"; +import { action, computed } from "mobx"; export class Client { private _guid: string; + // private operations: number; constructor(guid: string) { this._guid = guid; + // this.operations = 0; } + // @computed public get OPERATIONS(): number { + // return this.operations; + // } + + // @action + // public setOperations(newOperations: number): void { + // this.operations = newOperations; + // } + @computed public get GUID(): string { return this._guid; } }
\ No newline at end of file diff --git a/src/server/DashStats.ts b/src/server/DashStats.ts index 13ee61b3a..a10b28608 100644 --- a/src/server/DashStats.ts +++ b/src/server/DashStats.ts @@ -1,11 +1,11 @@ -import { magenta } from 'colors'; +import { cyan, magenta } from 'colors'; import { Request, Response } from 'express'; +import { Server } from 'http'; import SocketIO from 'socket.io'; -import { Client } from './Client'; +import { timeMap } from './ApiManagers/UserManager'; import { WebSocket } from './websocket'; const fs = require('fs'); const csv = require('csv-parser'); -import { stringify } from 'csv-stringify/sync'; export namespace DashStats { const statsCSVFilename = './src/server/stats/userLoginStats.csv'; @@ -14,6 +14,8 @@ export namespace DashStats { interface SocketPair { socketId: string; username: string; + time: string; + operations: number; } interface CSVStore { @@ -22,49 +24,128 @@ export namespace DashStats { TIME: string; } - export function handleStatsView(res: Response) { + enum ServerTraffic { + NOT_BUSY, + BUSY, + VERY_BUSY + } + + const BUSY_SERVER_BOUND = 2; + const VERY_BUSY_SERVER_BOUND = 3; + + const serverTrafficMessages = [ + "Not Busy", + "Busy", + "Very Busy" + ] + + export function handleStats(res: Response) { + let current = getCurrentConnections(); const results: CSVStore[] = []; - fs.createReadStream(statsCSVFilename) - .pipe(csv(columns)) - .on('data', (data: any) => results.push(data)) - .on('end', () => { - console.log(results); + res.json({ + message: 'welcome to stats', + currentConnections: current.length, + socketMap: current, }); - // let newRow = stringify([{ USERNAME: 'hi', ACTION: 'hi', TIME: 'hi' }], { header: true, columns: columns }); - // console.log(newRow); + // fs.createReadStream(statsCSVFilename) + // .pipe(csv()) + // .on('data', (data: any) => results.push(data)) + // .on('end', () => { + // console.log(results); + // res.json({ + // message: 'welcome to stats', + // currentConnections: current.length, + // socketMap: current, + // results: results, + // }); + // }); + } + export function handleStatsView(res: Response) { let current = getCurrentConnections(); - res.json({ - message: 'welcome to stats', - currentConnections: current.length, - socketMap: current, + + 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: current.length, + serverTraffic: serverTraffic, + serverTrafficMessage : serverTrafficMessages[serverTraffic], + connectedUsers: connectedUsers }); } 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()}`)); - console.log('stringify -> '); + // console.log(magenta(`User ${username.split(' ')[0]} logged in at: ${currentDate.toISOString()}`)); + + let toWrite: CSVStore = { + USERNAME : username, + ACTION : "loggedIn", + TIME : currentDate.toISOString() + } + + let statsFile = fs.createWriteStream(statsCSVFilename, { flags: "a"}); + statsFile.write(convertToCSV(toWrite)); + statsFile.end(); + console.log(cyan(convertToCSV(toWrite))); } } export function logUserLogout(username: string | undefined, socket: SocketIO.Socket) { if (!(username === undefined)) { let currentDate = new Date(); - console.log(magenta(`User ${username.split(' ')[0]} logged out at: ${currentDate.toISOString()}`)); + // console.log(magenta(`User ${username.split(' ')[0]} logged out at: ${currentDate.toISOString()}`)); + + let statsFile = fs.createWriteStream(statsCSVFilename, { flags: "a"}); + let toWrite: CSVStore = { + USERNAME : username, + ACTION : "loggedOut", + TIME : currentDate.toISOString() + } + statsFile.write(convertToCSV(toWrite)); + statsFile.end(); } } function getCurrentConnections(): SocketPair[] { + console.log("timeMap: " + timeMap); + console.log("clients:" + WebSocket.clients); let socketPairs: SocketPair[] = []; for (let [key, value] of WebSocket.socketMap) { + let username = value.split(' ')[0]; + let connectionTime = new Date(timeMap[username]); + + let connectionTimeString = connectionTime.toLocaleDateString() + " " + connectionTime.toLocaleTimeString(); + if (!key.disconnected) { - socketPairs.push({ socketId: key.id, username: value.split(' ')[0] }); + socketPairs.push({ + socketId: key.id, + username: username, + time: connectionTimeString.includes("Invalid Date") ? "" : connectionTimeString, + operations : WebSocket.userOperations.get(username) ? WebSocket.userOperations.get(username)! : 0, + }); } } console.log(socketPairs); + // console.log([...WebSocket.clients.entries()]); return socketPairs; } + + function convertToCSV(dataObject: CSVStore): string { + return `${dataObject.USERNAME},${dataObject.ACTION},${dataObject.TIME}\n`; + } } diff --git a/src/server/index.ts b/src/server/index.ts index 0848d828e..d76f12b95 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -87,6 +87,12 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: addSupervisedRoute({ method: Method.GET, subscription: '/stats', + secureHandler: ({ res }) => DashStats.handleStats(res), + }); + + addSupervisedRoute({ + method: Method.GET, + subscription: '/statsview', secureHandler: ({ res }) => DashStats.handleStatsView(res), }); diff --git a/src/server/stats/userLoginStats.csv b/src/server/stats/userLoginStats.csv index ec33b01b2..d5e56502c 100644 --- a/src/server/stats/userLoginStats.csv +++ b/src/server/stats/userLoginStats.csv @@ -1,2 +1,75 @@ -USERNAME,ACTION,TIME -boo15869,loggedIn,2023-01
\ No newline at end of file +USER,ACTION,TIME +aaa@gmail.com,loggedIn,2023-03-18T20:10:29.928Z +guest,loggedIn,2023-03-18T20:10:47.384Z +aaa@gmail.com,loggedOut,2023-03-18T20:10:55.364Z +aaa@gmail.com,loggedIn,2023-03-18T20:11:15.879Z +guest,loggedIn,2023-03-18T20:18:03.724Z +aaa@gmail.com,loggedIn,2023-03-18T20:18:03.860Z +guest,loggedOut,2023-03-18T20:19:00.211Z +guest,loggedIn,2023-03-18T20:19:03.087Z +guest,loggedOut,2023-03-18T20:19:50.668Z +boo15869@gmail.com,loggedIn,2023-03-18T20:20:17.890Z +boo15869@gmail.com,loggedOut,2023-03-18T20:21:03.542Z +boo15869@gmail.com,loggedIn,2023-03-18T20:21:06.149Z +boo15869@gmail.com,loggedOut,2023-03-18T20:21:51.874Z +a@gmail.com,loggedIn,2023-03-18T20:22:02.122Z +aaa@gmail.com,loggedOut,2023-03-18T20:22:42.882Z +aaa@gmail.com,loggedIn,2023-03-18T20:22:45.631Z +aaa@gmail.com,loggedIn,2023-03-18T20:25:34.658Z +a@gmail.com,loggedIn,2023-03-18T20:25:34.681Z +aaa@gmail.com,loggedIn,2023-03-18T20:29:04.297Z +a@gmail.com,loggedIn,2023-03-18T20:29:08.701Z +a@gmail.com,loggedIn,2023-03-18T20:29:18.565Z +aaa@gmail.com,loggedIn,2023-03-18T20:29:21.974Z +aaa@gmail.com,loggedIn,2023-03-18T20:29:51.477Z +a@gmail.com,loggedIn,2023-03-18T20:29:51.489Z +aaa@gmail.com,loggedIn,2023-03-18T20:30:15.011Z +aaa@gmail.com,loggedIn,2023-03-18T20:30:57.818Z +a@gmail.com,loggedIn,2023-03-18T20:30:57.838Z +aaa@gmail.com,loggedIn,2023-03-18T20:31:12.061Z +a@gmail.com,loggedIn,2023-03-18T20:31:12.080Z +a@gmail.com,loggedIn,2023-03-18T20:31:19.447Z +aaa@gmail.com,loggedIn,2023-03-18T20:31:22.738Z +aaa@gmail.com,loggedIn,2023-03-18T20:32:36.919Z +a@gmail.com,loggedIn,2023-03-18T20:32:36.929Z +a@gmail.com,loggedIn,2023-03-18T20:32:56.212Z +aaa@gmail.com,loggedIn,2023-03-18T20:32:59.300Z +aaa@gmail.com,loggedIn,2023-03-18T20:34:27.543Z +a@gmail.com,loggedIn,2023-03-18T20:34:27.570Z +a@gmail.com,loggedIn,2023-03-18T20:34:35.299Z +aaa@gmail.com,loggedIn,2023-03-18T20:34:35.302Z +a@gmail.com,loggedIn,2023-03-18T20:34:51.579Z +aaa@gmail.com,loggedIn,2023-03-18T20:34:52.392Z +a@gmail.com,loggedIn,2023-03-18T20:35:08.509Z +aaa@gmail.com,loggedIn,2023-03-18T20:35:15.202Z +a@gmail.com,loggedIn,2023-03-18T20:36:46.796Z +aaa@gmail.com,loggedIn,2023-03-18T20:36:51.756Z +a@gmail.com,loggedIn,2023-03-18T20:36:55.286Z +a@gmail.com,loggedIn,2023-03-18T20:40:06.226Z +a@gmail.com,loggedIn,2023-03-18T20:40:18.474Z +aaa@gmail.com,loggedIn,2023-03-18T20:40:31.894Z +a@gmail.com,loggedIn,2023-03-18T20:40:31.903Z +a@gmail.com,loggedIn,2023-03-18T20:42:25.301Z +aaa@gmail.com,loggedIn,2023-03-18T20:42:31.182Z +aaa@gmail.com,loggedOut,2023-03-18T20:43:05.741Z +aaa@gmail.com,loggedIn,2023-03-18T20:43:09.203Z +a@gmail.com,loggedOut,2023-03-18T20:45:24.343Z +a@gmail.com,loggedIn,2023-03-18T20:45:27.207Z +aaa@gmail.com,loggedIn,2023-03-18T20:46:15.618Z +a@gmail.com,loggedIn,2023-03-18T20:46:56.163Z +a@gmail.com,loggedOut,2023-03-18T20:48:37.464Z +a@gmail.com,loggedIn,2023-03-18T20:48:40.562Z +a@gmail.com,loggedOut,2023-03-18T20:50:32.478Z +a@gmail.com,loggedIn,2023-03-18T20:50:40.384Z +a@gmail.com,loggedOut,2023-03-18T20:51:34.159Z +a@gmail.com,loggedIn,2023-03-18T20:51:49.206Z +a@gmail.com,loggedOut,2023-03-18T20:52:04.673Z +qw@gmail.com,loggedIn,2023-03-18T20:52:36.270Z +qw@gmail.com,loggedIn,2023-03-18T20:53:58.175Z +aaa@gmail.com,loggedIn,2023-03-18T20:53:58.204Z +aaa@gmail.com,loggedIn,2023-03-18T20:54:20.518Z +qw@gmail.com,loggedIn,2023-03-18T20:54:24.225Z +qw@gmail.com,loggedIn,2023-03-18T20:54:37.007Z +aaa@gmail.com,loggedIn,2023-03-18T20:54:39.959Z +aaa@gmail.com,loggedOut,2023-03-18T20:55:55.199Z +qw@gmail.com,loggedOut,2023-03-18T20:55:59.010Z diff --git a/src/server/websocket.ts b/src/server/websocket.ts index e556ecc17..54944e944 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -1,4 +1,4 @@ -import { blue, magenta } from 'colors'; +import { blue, magenta, yellow } from 'colors'; import * as express from 'express'; import { createServer, Server } from 'https'; import { networkInterfaces } from 'os'; @@ -22,7 +22,9 @@ import { resolvedPorts } from './server_Initialization'; export namespace WebSocket { export let _socket: Socket; export const clients: { [key: string]: Client } = {}; + // export const clients = new Map<string, Client>(); export const socketMap = new Map<SocketIO.Socket, string>(); + export const userOperations = new Map<string, number>(); export let disconnect: Function; export async function initialize(isRelease: boolean, app: express.Express) { @@ -101,7 +103,9 @@ export namespace WebSocket { socket.on('disconnect', function () { let currentUser = socketMap.get(socket); if (!(currentUser === undefined)) { - DashStats.logUserLogout(socketMap.get(socket), socket); + let currentUsername = currentUser.split(' ')[0] + DashStats.logUserLogout(currentUsername, socket); + delete timeMap[currentUsername] } }); @@ -180,16 +184,20 @@ export namespace WebSocket { } function barReceived(socket: SocketIO.Socket, userEmail: string) { - clients[userEmail] = new Client(userEmail.toString()); + clients[userEmail] = new Client(userEmail.toString()); + // clients.set(userEmail, new Client(userEmail.toString())); const currentdate = new Date(); const datetime = currentdate.getDate() + '/' + (currentdate.getMonth() + 1) + '/' + currentdate.getFullYear() + ' @ ' + currentdate.getHours() + ':' + currentdate.getMinutes() + ':' + currentdate.getSeconds(); console.log(blue(`user ${userEmail} has connected to the web socket at: ${datetime}`)); - console.log(magenta(`currently connected: ${JSON.stringify(clients)}`)); + // console.log(magenta(`currently connected: ${[...clients.entries()]}`)); // console.log(magenta('socket map below')); // console.log([...socketMap.entries()]); printActiveUsers(); + + timeMap[userEmail] = Date.now(); socketMap.set(socket, userEmail + ' at ' + datetime); - DashStats.logUserLogin(socketMap.get(socket), socket); + userOperations.set(userEmail, 0); + DashStats.logUserLogin(userEmail, socket); } function getField([id, callback]: [string, (result?: Transferable) => void]) { @@ -359,6 +367,12 @@ export namespace WebSocket { var CurUser: string | undefined = undefined; function UpdateField(socket: Socket, diff: Diff) { + console.log(magenta(`1 OP ${socketMap.get(socket)}`)); + + let currentUsername = socketMap.get(socket)!.split(' ')[0]; + userOperations.set(currentUsername, userOperations.get(currentUsername) !== undefined ? userOperations.get(currentUsername)! + 1 : 0); + console.log(yellow("Total Operations: " + userOperations.get(currentUsername))); + if (CurUser !== socketMap.get(socket)) { CurUser = socketMap.get(socket); console.log('Switch User: ' + CurUser); diff --git a/views/stats.pug b/views/stats.pug new file mode 100644 index 000000000..54c017e70 --- /dev/null +++ b/views/stats.pug @@ -0,0 +1,22 @@ +extends ./layout + +block content + style + include ./stylesheets/authentication.css + include ./stylesheets/statsview.css + .outermost + .stats-container + h1 Dash Stats + p(class="stats-content") Current Connections: #{numConnections} + div(class="stats-content stats-server-status-container") + p Server Status: + div(class="stats-server-status-item stats-server-status-" + serverTraffic) + p #{serverTrafficMessage} + div(class="stats-content stats-connected-users") + p Connected Users: + ul + each username in connectedUsers + li(class="none")= username + + +
\ No newline at end of file diff --git a/views/stylesheets/statsview.css b/views/stylesheets/statsview.css new file mode 100644 index 000000000..c018bedfc --- /dev/null +++ b/views/stylesheets/statsview.css @@ -0,0 +1,56 @@ +.outermost { + background-color: #251f1f; + display: flex; + flex-direction: row; + height: 98vh; + width: 99vw; + justify-content: center; + position: relative; +} + +.stats-container { + background-color: white; + + padding: 1rem; + width: 80vw; + border-radius: 8px; +} + +.stats-content { + font-size: 1.25em; + +} + +.stats-server-status-container { + display: flex; + flex-direction: row; +} + +.stats-server-status-item { + margin-left: 0.25rem; + padding: 0px 5px; + + border-radius: 3px; + width: 8rem; + text-align: center; +} + +.stats-server-status-0 { + /* not busy */ + border: 3px green solid; +} + +.stats-server-status-1 { + /* busy */ + border: 3px #ffcc00 solid; +} + +.stats-server-status-2 { + /* very busy */ + border: 3px red solid; +} + +.stats-connected-users { + max-height: 70vh; + overflow-y: auto; +}
\ No newline at end of file |