diff options
author | bobzel <zzzman@gmail.com> | 2023-05-22 11:25:32 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2023-05-22 11:25:32 -0400 |
commit | bed3309e1fda6597b2a8fea10ad82cd3a0402051 (patch) | |
tree | fe599bbdc5fca2c221e1e0f7a60995b7cd39f870 /src/server/websocket.ts | |
parent | 887a4f7e0fc25fde87b20a5de2e7b0aee561cc78 (diff) | |
parent | 3d26d5b2654841a9b92f3d66b28d1dc8e36cca6a (diff) |
merged physics with master
Diffstat (limited to 'src/server/websocket.ts')
-rw-r--r-- | src/server/websocket.ts | 109 |
1 files changed, 102 insertions, 7 deletions
diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 9b91a35a6..be5cdb202 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -12,16 +12,19 @@ import { GoogleCredentialsLoader, SSL } from './apis/google/CredentialsLoader'; import YoutubeApi from './apis/youtube/youtubeApiSample'; import { initializeGuest } from './authentication/DashUserModel'; import { Client } from './Client'; +import { DashStats } from './DashStats'; import { Database } from './database'; import { DocumentsCollection } from './IDatabase'; import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from './Message'; import { Search } from './Search'; import { resolvedPorts } from './server_Initialization'; +var _ = require('lodash'); export namespace WebSocket { export let _socket: Socket; - const clients: { [key: string]: Client } = {}; + export const clients: { [key: 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) { @@ -49,6 +52,8 @@ export namespace WebSocket { next(); }); + socket.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); + // convenience function to log server messages on the client function log(message?: any, ...optionalParams: any[]) { socket.emit('log', ['Message from server:', message, ...optionalParams]); @@ -97,6 +102,15 @@ export namespace WebSocket { console.log('received bye'); }); + socket.on('disconnect', function () { + let currentUser = socketMap.get(socket); + if (!(currentUser === undefined)) { + let currentUsername = currentUser.split(' ')[0]; + DashStats.logUserLogout(currentUsername, socket); + delete timeMap[currentUsername]; + } + }); + Utils.Emit(socket, MessageStore.Foo, 'handshooken'); Utils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); @@ -130,6 +144,12 @@ export namespace WebSocket { socket.disconnect(true); }; }); + + setInterval(function () { + // Utils.Emit(socket, MessageStore.UpdateStats, DashStats.getUpdatedStatsBundle()); + + io.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); + }, DashStats.SAMPLING_INTERVAL); } function processGesturePoints(socket: Socket, content: GestureContent) { @@ -176,7 +196,12 @@ export namespace WebSocket { 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}`)); + printActiveUsers(); + + timeMap[userEmail] = Date.now(); socketMap.set(socket, userEmail + ' at ' + datetime); + userOperations.set(userEmail, 0); + DashStats.logUserLogin(userEmail, socket); } function getField([id, callback]: [string, (result?: Transferable) => void]) { @@ -199,7 +224,7 @@ export namespace WebSocket { return Database.Instance.getDocument(id, callback); } function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { - process.stdout.write(`.`); + process.stdout.write(`+`); GetRefFieldLocal([id, callback]); } @@ -293,15 +318,79 @@ export namespace WebSocket { ); } + /** + * findClosestIndex() is a helper function that will try to find + * the closest index of a list that has the same value as + * a specified argument/index pair. + * @param list the list to search through + * @param indexesToDelete a list of indexes that are already marked for deletion + * so they will be ignored + * @param value the value of the item to remove + * @param hintIndex the index that the element was at on the client's copy of + * the data + * @returns the closest index with the same value or -1 if the element was not found. + */ + function findClosestIndex(list: any, indexesToDelete: number[], value: any, hintIndex: number) { + let closestIndex = -1; + for (let i = 0; i < list.length; i++) { + if (list[i] === value && !indexesToDelete.includes(i)) { + if (Math.abs(i - hintIndex) < Math.abs(closestIndex - hintIndex)) { + closestIndex = i; + } + } + } + return closestIndex; + } + + /** + * remFromListField() receives the items to remove and a hint + * from the client, and attempts to make the modification to the + * server's copy of the data. If server's copy does not match + * the client's after removal, the server will SEND BACk + * its version to the client. + * @param socket the socket that the client is connected on + * @param diff an object containing the items to remove and a hint + * (the hint contains start index and deleteCount, the number of + * items to delete) + * @param curListItems the server's current copy of the data + */ function remFromListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { diff.diff.$set = diff.diff.$remFromSet; delete diff.diff.$remFromSet; const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; const remListItems = diff.diff.$set[updatefield].fields; const curList = (curListItems as any)?.fields?.[updatefield.replace('fields.', '')]?.fields.filter((f: any) => f !== null) || []; - diff.diff.$set[updatefield].fields = curList?.filter( - (curItem: any) => !remListItems.some((remItem: any) => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem)) - ); + const hint = diff.diff.$set.hint; + + if (hint) { + // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements) + let indexesToRemove: number[] = []; + for (let i = 0; i < hint.deleteCount; i++) { + if (curList.length > i + hint.start && _.isEqual(curList[i + hint.start], remListItems[i])) { + indexesToRemove.push(i + hint.start); + continue; + } + + let closestIndex = findClosestIndex(curList, indexesToRemove, remListItems[i], i + hint.start); + if (closestIndex !== -1) { + indexesToRemove.push(closestIndex); + } else { + console.log('Item to delete was not found - index = -1'); + } + } + + diff.diff.$set[updatefield].fields = curList?.filter((curItem: any, index: number) => !indexesToRemove.includes(index)); + } else { + // go back to the original way to delete if we didn't receive + // a hint from the client + diff.diff.$set[updatefield].fields = curList?.filter( + (curItem: any) => !remListItems.some((remItem: any) => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem)) + ); + } + + // if the client and server have different versions of the data after + // deletion, they will have different lengths and the server will + // send its version of the data to the client const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; delete diff.diff.length; Database.Instance.update( @@ -309,6 +398,7 @@ export namespace WebSocket { diff.diff, () => { if (sendBack) { + // the two copies are different, so the server sends its copy. console.log('SEND BACK'); const id = socket.id; socket.id = ''; @@ -346,6 +436,11 @@ export namespace WebSocket { var CurUser: string | undefined = undefined; function UpdateField(socket: Socket, diff: Diff) { + const curUser = socketMap.get(socket); + if (!curUser) return; + let currentUsername = curUser.split(' ')[0]; + userOperations.set(currentUsername, userOperations.get(currentUsername) !== undefined ? userOperations.get(currentUsername)! + 1 : 0); + if (CurUser !== socketMap.get(socket)) { CurUser = socketMap.get(socket); console.log('Switch User: ' + CurUser); @@ -381,8 +476,8 @@ export namespace WebSocket { if (term !== undefined) { const { suffix, value } = term; update[key + suffix] = { set: value }; - if (key.endsWith('lastModified')) { - update['lastModified' + suffix] = value; + if (key.endsWith('modificationDate')) { + update['modificationDate' + suffix] = value; } } } |