diff options
author | bobzel <zzzman@gmail.com> | 2024-04-17 12:27:21 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-04-17 12:27:21 -0400 |
commit | 2a313f28fcb8675223708b0657de7517a3281095 (patch) | |
tree | ed6db226cc7d323aee378eddee43dc5f3bdb1ef9 /src/server/websocket.ts | |
parent | 62937027183dc8acf14e489fbb4590aff6fce2cd (diff) |
restoring eslint - updates not complete yet
Diffstat (limited to 'src/server/websocket.ts')
-rw-r--r-- | src/server/websocket.ts | 380 |
1 files changed, 190 insertions, 190 deletions
diff --git a/src/server/websocket.ts b/src/server/websocket.ts index 38134f2c1..cb16bce72 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -3,152 +3,26 @@ import { createServer } from 'https'; import * as _ from 'lodash'; import { networkInterfaces } from 'os'; import { Server, Socket } from 'socket.io'; -import { Utils } from '../Utils'; +import { ServerUtils } from '../ServerUtils'; import { logPort } from './ActionUtilities'; -import { timeMap } from './ApiManagers/UserManager'; import { Client } from './Client'; import { DashStats } from './DashStats'; import { DocumentsCollection } from './IDatabase'; import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent, YoutubeQueryInput, YoutubeQueryTypes } from './Message'; import { Search } from './Search'; +import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData'; import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader'; import YoutubeApi from './apis/youtube/youtubeApiSample'; import { initializeGuest } from './authentication/DashUserModel'; import { Database } from './database'; -import { resolvedPorts } from './server_Initialization'; export namespace WebSocket { + let CurUser: string | undefined; + // eslint-disable-next-line import/no-mutable-exports export let _socket: Socket; + // eslint-disable-next-line import/no-mutable-exports + export let _disconnect: Function; export const clients: { [key: string]: Client } = {}; - export const socketMap = new Map<Socket, string>(); - export const userOperations = new Map<string, number>(); - export let disconnect: Function; - - export async function initialize(isRelease: boolean, credentials:any) { - let io: Server; - if (isRelease) { - const { socketPort } = process.env; - if (socketPort) { - resolvedPorts.socket = Number(socketPort); - } - const httpsServer = createServer(credentials); - io = new Server(httpsServer, {}) - httpsServer.listen(resolvedPorts.socket); - } else { - io = new Server(); - io.listen(resolvedPorts.socket); - } - logPort('websocket', resolvedPorts.socket); - - io.on('connection', socket => { - _socket = socket; - socket.use((_packet, next) => { - const userEmail = socketMap.get(socket); - if (userEmail) { - timeMap[userEmail] = Date.now(); - } - 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]); - } - - socket.on('message', function (message, room) { - console.log('Client said: ', message); - socket.in(room).emit('message', message); - }); - - socket.on('create or join', function (room) { - console.log('Received request to create or join room ' + room); - - const clientsInRoom = socket.rooms.has(room); - const numClients = clientsInRoom ? Object.keys(room.sockets).length : 0; - console.log('Room ' + room + ' now has ' + numClients + ' client(s)'); - - if (numClients === 0) { - socket.join(room); - console.log('Client ID ' + socket.id + ' created room ' + room); - socket.emit('created', room, socket.id); - } else if (numClients === 1) { - console.log('Client ID ' + socket.id + ' joined room ' + room); - socket.in(room).emit('join', room); - socket.join(room); - socket.emit('joined', room, socket.id); - socket.in(room).emit('ready'); - } else { - // max two clients - socket.emit('full', room); - } - }); - - socket.on('ipaddr', function () { - const ifaces = networkInterfaces(); - for (const dev in ifaces) { - ifaces[dev]?.forEach(function (details) { - if (details.family === 'IPv4' && details.address !== '127.0.0.1') { - socket.emit('ipaddr', details.address); - } - }); - } - }); - - socket.on('bye', function () { - 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)); - Utils.AddServerHandler(socket, MessageStore.SetField, args => setField(socket, args)); - Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); - Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); - if (isRelease) { - Utils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); - } - - Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); - Utils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery); - Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); - Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); - Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); - Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); - Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); - Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); - Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); - - /** - * Whenever we receive the go-ahead, invoke the import script and pass in - * as an emitter and a terminator the functions that simply broadcast a result - * or indicate termination to the client via the web socket - */ - - disconnect = () => { - socket.broadcast.emit('connection_terminated', Date.now()); - 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) { socket.broadcast.emit('receiveGesturePoints', content); @@ -174,8 +48,11 @@ export namespace WebSocket { break; case YoutubeQueryTypes.SearchVideo: YoutubeApi.authorizedGetVideos(ProjectCredentials, query.userInput, callback); + break; case YoutubeQueryTypes.VideoDetails: YoutubeApi.authorizedGetVideoDetails(ProjectCredentials, query.videoIds, callback); + break; + default: } } @@ -189,6 +66,9 @@ export namespace WebSocket { initializeGuest(); } + function printActiveUsers() { + socketMap.forEach((user, socket) => !socket.disconnected && console.log(user)); + } function barReceived(socket: Socket, userEmail: string) { clients[userEmail] = new Client(userEmail.toString()); const currentdate = new Date(); @@ -203,7 +83,7 @@ export namespace WebSocket { } function getField([id, callback]: [string, (result?: Transferable) => void]) { - Database.Instance.getDocument(id, (result?: Transferable) => callback(result ? result : undefined)); + Database.Instance.getDocument(id, (result?: Transferable) => callback(result)); } function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) { @@ -248,27 +128,24 @@ export namespace WebSocket { list: [ '_l', list => { - const results = []; - for (const value of list.fields) { - const term = ToSearchTerm(value); - if (term) { - results.push(term.value); - } - } + const results: any[] = []; + // eslint-disable-next-line no-use-before-define + list.fields.forEach((value: any) => ToSearchTerm(value) && results.push(ToSearchTerm(value)!.value)); return results.length ? results : null; }, ], }; - function ToSearchTerm(val: any): { suffix: string; value: any } | undefined { + function ToSearchTerm(valIn: any): { suffix: string; value: any } | undefined { + let val = valIn; if (val === null || val === undefined) { - return; + return undefined; } const type = val.__type || typeof val; let suffix = suffixMap[type]; if (!suffix) { - return; + return undefined; } if (Array.isArray(suffix)) { const accessor = suffix[1]; @@ -277,7 +154,7 @@ export namespace WebSocket { } else { val = val[accessor]; } - suffix = suffix[0]; + [suffix] = suffix; } return { suffix, value: val }; } @@ -285,8 +162,28 @@ export namespace WebSocket { function getSuffix(value: string | [string, any]): string { return typeof value === 'string' ? value : value[0]; } + const pendingOps = new Map<string, { diff: Diff; socket: Socket }[]>(); - function addToListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { + function dispatchNextOp(id: string) { + const next = pendingOps.get(id)!.shift(); + if (next) { + const { diff, socket } = next; + if (diff.diff.$addToSet) { + // eslint-disable-next-line no-use-before-define + return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + } + if (diff.diff.$remFromSet) { + // eslint-disable-next-line no-use-before-define + return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own + } + // eslint-disable-next-line no-use-before-define + return SetField(socket, diff); + } + return !pendingOps.get(id)!.length && pendingOps.delete(id); + } + + function addToListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void { + const diff = diffIn; diff.diff.$set = diff.diff.$addToSet; delete diff.diff.$addToSet; // convert add to set to a query of the current fields, and then a set of the composition of the new fields with the old ones const updatefield = Array.from(Object.keys(diff.diff.$set))[0]; @@ -296,7 +193,7 @@ export namespace WebSocket { return; } const curList = (curListItems as any)?.fields?.[updatefield.replace('fields.', '')]?.fields.filter((item: any) => item !== undefined) || []; - diff.diff.$set[updatefield].fields = [...curList, ...newListItems]; //, ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; + diff.diff.$set[updatefield].fields = [...curList, ...newListItems]; // , ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))]; const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length; delete diff.diff.length; Database.Instance.update( @@ -305,11 +202,13 @@ export namespace WebSocket { () => { if (sendBack) { console.log('Warning: list modified during update. Composite list is being returned.'); - const id = socket.id; - (socket as any).id = ''; + const { id } = socket; + (socket as any).id = ''; // bcz: HACK. this prevents the update message from going back to the client that made the change. socket.broadcast.emit(MessageStore.UpdateField.Message, diff); (socket as any).id = id; - } else socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } else { + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } dispatchNextOp(diff.id); }, false @@ -352,28 +251,28 @@ export namespace WebSocket { * items to delete) * @param curListItems the server's current copy of the data */ - function remFromListField(socket: Socket, diff: Diff, curListItems?: Transferable): void { + function remFromListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void { + const diff = diffIn; 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) || []; - const hint = diff.diff.$set.hint; + const { hint } = diff.diff.$set; 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[] = []; + const 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'); + const 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'); + } } } @@ -398,45 +297,23 @@ export namespace WebSocket { if (sendBack) { // the two copies are different, so the server sends its copy. console.log('SEND BACK'); - const id = socket.id; - (socket as any).id = ''; + const { id } = socket; + (socket as any).id = ''; // bcz: HACK. this prevents the update message from going back to the client that made the change. socket.broadcast.emit(MessageStore.UpdateField.Message, diff); (socket as any).id = id; - } else socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } else { + socket.broadcast.emit(MessageStore.UpdateField.Message, diff); + } dispatchNextOp(diff.id); }, false ); } - const pendingOps = new Map<string, { diff: Diff; socket: Socket }[]>(); - - function dispatchNextOp(id: string) { - const next = pendingOps.get(id)!.shift(); - if (next) { - const { diff, socket } = next; - if (diff.diff.$addToSet) { - return GetRefFieldLocal([diff.id, (result?: Transferable) => addToListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own - } - if (diff.diff.$remFromSet) { - return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own - } - return GetRefFieldLocal([diff.id, (result?: Transferable) => SetField(socket, diff, result)]); - } - if (!pendingOps.get(id)!.length) pendingOps.delete(id); - } - - function printActiveUsers() { - socketMap.forEach((user, socket) => { - !socket.disconnected && console.log(user); - }); - } - var CurUser: string | undefined = undefined; - function UpdateField(socket: Socket, diff: Diff) { const curUser = socketMap.get(socket); - if (!curUser) return; - let currentUsername = curUser.split(' ')[0]; + if (!curUser) return false; + const currentUsername = curUser.split(' ')[0]; userOperations.set(currentUsername, userOperations.get(currentUsername) !== undefined ? userOperations.get(currentUsername)! + 1 : 0); if (CurUser !== socketMap.get(socket)) { @@ -454,15 +331,18 @@ export namespace WebSocket { if (diff.diff.$remFromSet) { return GetRefFieldLocal([diff.id, (result?: Transferable) => remFromListField(socket, diff, result)]); // would prefer to have Mongo handle list additions direclty, but for now handle it on our own } - return GetRefFieldLocal([diff.id, (result?: Transferable) => SetField(socket, diff, result)]); + // eslint-disable-next-line no-use-before-define + return SetField(socket, diff); } - function SetField(socket: Socket, diff: Diff, curListItems?: Transferable) { + function SetField(socket: Socket, diff: Diff /* , curListItems?: Transferable */) { Database.Instance.update(diff.id, diff.diff, () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); const docfield = diff.diff.$set || diff.diff.$unset; if (docfield) { const update: any = { id: diff.id }; let dynfield = false; + // eslint-disable-next-line no-restricted-syntax for (let key in docfield) { + // eslint-disable-next-line no-continue if (!key.startsWith('fields.')) continue; dynfield = true; const val = docfield[key]; @@ -504,4 +384,124 @@ export namespace WebSocket { function CreateField(newValue: any) { Database.Instance.insert(newValue); } + export async function initialize(isRelease: boolean, credentials: any) { + let io: Server; + if (isRelease) { + const { socketPort } = process.env; + if (socketPort) { + resolvedPorts.socket = Number(socketPort); + } + const httpsServer = createServer(credentials); + io = new Server(httpsServer, {}); + httpsServer.listen(resolvedPorts.socket); + } else { + io = new Server(); + io.listen(resolvedPorts.socket); + } + logPort('websocket', resolvedPorts.socket); + + io.on('connection', socket => { + _socket = socket; + socket.use((_packet, next) => { + const userEmail = socketMap.get(socket); + if (userEmail) { + timeMap[userEmail] = Date.now(); + } + next(); + }); + + socket.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); + + socket.on('message', (message, room) => { + console.log('Client said: ', message); + socket.in(room).emit('message', message); + }); + + socket.on('create or join', room => { + console.log('Received request to create or join room ' + room); + + const clientsInRoom = socket.rooms.has(room); + const numClients = clientsInRoom ? Object.keys(room.sockets).length : 0; + console.log('Room ' + room + ' now has ' + numClients + ' client(s)'); + + if (numClients === 0) { + socket.join(room); + console.log('Client ID ' + socket.id + ' created room ' + room); + socket.emit('created', room, socket.id); + } else if (numClients === 1) { + console.log('Client ID ' + socket.id + ' joined room ' + room); + socket.in(room).emit('join', room); + socket.join(room); + socket.emit('joined', room, socket.id); + socket.in(room).emit('ready'); + } else { + // max two clients + socket.emit('full', room); + } + }); + + socket.on('ipaddr', () => { + const ifaces = networkInterfaces(); + for (const dev in ifaces) { + ifaces[dev]?.forEach(details => { + if (details.family === 'IPv4' && details.address !== '127.0.0.1') { + socket.emit('ipaddr', details.address); + } + }); + } + }); + + socket.on('bye', () => { + console.log('received bye'); + }); + + socket.on('disconnect', () => { + const currentUser = socketMap.get(socket); + if (!(currentUser === undefined)) { + const currentUsername = currentUser.split(' ')[0]; + DashStats.logUserLogout(currentUsername, socket); + delete timeMap[currentUsername]; + } + }); + + ServerUtils.Emit(socket, MessageStore.Foo, 'handshooken'); + + ServerUtils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); + ServerUtils.AddServerHandler(socket, MessageStore.SetField, args => setField(socket, args)); + ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); + ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); + if (isRelease) { + ServerUtils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); + } + + ServerUtils.AddServerHandler(socket, MessageStore.CreateField, CreateField); + ServerUtils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery); + ServerUtils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); + ServerUtils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); + ServerUtils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); + ServerUtils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); + ServerUtils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); + ServerUtils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); + ServerUtils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); + ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); + ServerUtils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); + + /** + * Whenever we receive the go-ahead, invoke the import script and pass in + * as an emitter and a terminator the functions that simply broadcast a result + * or indicate termination to the client via the web socket + */ + + _disconnect = () => { + socket.broadcast.emit('connection_terminated', Date.now()); + socket.disconnect(true); + }; + }); + + setInterval(() => { + // Utils.Emit(socket, MessageStore.UpdateStats, DashStats.getUpdatedStatsBundle()); + + io.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); + }, DashStats.SAMPLING_INTERVAL); + } } |