diff options
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/ApiManagers/SearchManager.ts | 151 | ||||
| -rw-r--r-- | src/server/ApiManagers/UploadManager.ts | 42 | ||||
| -rw-r--r-- | src/server/DashUploadUtils.ts | 20 | ||||
| -rw-r--r-- | src/server/server_Initialization.ts | 29 | ||||
| -rw-r--r-- | src/server/updateProtos.ts | 24 | ||||
| -rw-r--r-- | src/server/websocket.ts | 97 |
6 files changed, 220 insertions, 143 deletions
diff --git a/src/server/ApiManagers/SearchManager.ts b/src/server/ApiManagers/SearchManager.ts index a74e13a62..186f0bcd3 100644 --- a/src/server/ApiManagers/SearchManager.ts +++ b/src/server/ApiManagers/SearchManager.ts @@ -1,94 +1,89 @@ -import { exec } from "child_process"; -import { cyan, green, red, yellow } from "colors"; +import { exec } from 'child_process'; +import { cyan, green, red, yellow } from 'colors'; import * as path from 'path'; -import { log_execution } from "../ActionUtilities"; -import { Database } from "../database"; -import { Method } from "../RouteManager"; -import RouteSubscriber from "../RouteSubscriber"; -import { Search } from "../Search"; -import ApiManager, { Registration } from "./ApiManager"; -import { Directory, pathToDirectory } from "./UploadManager"; +import { log_execution } from '../ActionUtilities'; +import { Database } from '../database'; +import { Method } from '../RouteManager'; +import RouteSubscriber from '../RouteSubscriber'; +import { Search } from '../Search'; +import ApiManager, { Registration } from './ApiManager'; +import { Directory, pathToDirectory } from './UploadManager'; const findInFiles = require('find-in-files'); export class SearchManager extends ApiManager { - protected initialize(register: Registration): void { - register({ method: Method.GET, - subscription: new RouteSubscriber("solr").add("action"), + subscription: new RouteSubscriber('solr').add('action'), secureHandler: async ({ req, res }) => { const { action } = req.params; switch (action) { - case "start": - case "stop": - const status = req.params.action === "start"; + case 'start': + case 'stop': + const status = req.params.action === 'start'; SolrManager.SetRunning(status); break; - case "update": + case 'update': await SolrManager.update(); break; default: console.log(yellow(`${action} is an unknown solr operation.`)); } - res.redirect("/home"); - } + res.redirect('/home'); + }, }); register({ method: Method.GET, - subscription: "/textsearch", + subscription: '/textsearch', secureHandler: async ({ req, res }) => { const q = req.query.q; if (q === undefined) { res.send([]); return; } - const resObj: { ids: string[], numFound: number, lines: string[] } = { ids: [], numFound: 0, lines: [] }; + const resObj: { ids: string[]; numFound: number; lines: string[] } = { ids: [], numFound: 0, lines: [] }; let results: any; const dir = pathToDirectory(Directory.text); try { const regex = new RegExp(q.toString()); - results = await findInFiles.find({ 'term': q, 'flags': 'ig' }, dir, ".txt$"); + results = await findInFiles.find({ term: q, flags: 'ig' }, dir, '.txt$'); for (const result in results) { - resObj.ids.push(path.basename(result, ".txt").replace(/upload_/, "")); + resObj.ids.push(path.basename(result, '.txt').replace(/upload_/, '')); resObj.lines.push(results[result].line); resObj.numFound++; } res.send(resObj); } catch (e) { - console.log(red("textsearch:bad RegExp" + q.toString())); + console.log(red('textsearch:bad RegExp' + q.toString())); res.send([]); return; } - } + }, }); register({ method: Method.GET, - subscription: "/dashsearch", + subscription: '/dashsearch', secureHandler: async ({ req, res }) => { const solrQuery: any = {}; - ["q", "fq", "start", "rows", "sort", "hl.maxAnalyzedChars", "hl", "hl.fl"].forEach(key => solrQuery[key] = req.query[key]); + ['q', 'fq', 'start', 'rows', 'sort', 'hl.maxAnalyzedChars', 'hl', 'hl.fl'].forEach(key => (solrQuery[key] = req.query[key])); if (solrQuery.q === undefined) { res.send([]); return; } const results = await Search.search(solrQuery); res.send(results); - } + }, }); - } - } export namespace SolrManager { - export function SetRunning(status: boolean) { - const args = status ? "start" : "stop -p 8983"; + const args = status ? 'start' : 'stop -p 8983'; console.log(`solr management: trying to ${args}`); - exec(`solr ${args}`, { cwd: "./solr-8.3.1/bin" }, (error, stdout, stderr) => { + exec(`solr ${args}`, { cwd: './solr-8.3.1/bin' }, (error, stdout, stderr) => { if (error) { console.log(red(`solr management error: unable to ${args} server`)); console.log(red(error.message)); @@ -97,39 +92,39 @@ export namespace SolrManager { console.log(yellow(stderr)); }); if (status) { - console.log(cyan("Start script is executing: please allow 15 seconds for solr to start on port 8983.")); + console.log(cyan('Start script is executing: please allow 15 seconds for solr to start on port 8983.')); } } export async function update() { - console.log(green("Beginning update...")); + console.log(green('Beginning update...')); await log_execution<void>({ - startMessage: "Clearing existing Solr information...", - endMessage: "Solr information successfully cleared", + startMessage: 'Clearing existing Solr information...', + endMessage: 'Solr information successfully cleared', action: Search.clear, - color: cyan + color: cyan, }); const cursor = await log_execution({ - startMessage: "Connecting to and querying for all documents from database...", + startMessage: 'Connecting to and querying for all documents from database...', endMessage: ({ result, error }) => { const success = error === null && result !== undefined; if (!success) { - console.log(red("Unable to connect to the database.")); + console.log(red('Unable to connect to the database.')); process.exit(0); } - return "Connection successful and query complete"; + return 'Connection successful and query complete'; }, action: () => Database.Instance.query({}), - color: yellow + color: yellow, }); const updates: any[] = []; let numDocs = 0; function updateDoc(doc: any) { numDocs++; - if ((numDocs % 50) === 0) { + if (numDocs % 50 === 0) { console.log(`Batch of 50 complete, total of ${numDocs}`); } - if (doc.__type !== "Doc") { + if (doc.__type !== 'Doc') { return; } const fields = doc.fields; @@ -143,8 +138,8 @@ export namespace SolrManager { const term = ToSearchTerm(value); if (term !== undefined) { const { suffix, value } = term; - if (key.endsWith('lastModified')) { - update["lastModified" + suffix] = value; + if (key.endsWith('modificationDate')) { + update['modificationDate' + suffix] = value; } update[key + suffix] = value; dynfield = true; @@ -157,51 +152,54 @@ export namespace SolrManager { await cursor?.forEach(updateDoc); const result = await log_execution({ startMessage: `Dispatching updates for ${updates.length} documents`, - endMessage: "Dispatched updates complete", + endMessage: 'Dispatched updates complete', action: () => Search.updateDocuments(updates), - color: cyan + color: cyan, }); try { if (result) { const { status } = JSON.parse(result).responseHeader; - console.log(status ? red(`Failed with status code (${status})`) : green("Success!")); + console.log(status ? red(`Failed with status code (${status})`) : green('Success!')); } else { - console.log(red("Solr is likely not running!")); + console.log(red('Solr is likely not running!')); } } catch (e) { - console.log(red("Error:")); + console.log(red('Error:')); console.log(e); - console.log("\n"); + console.log('\n'); } await cursor?.close(); } - const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = { - "number": "_n", - "string": "_t", - "boolean": "_b", - "image": ["_t", "url"], - "video": ["_t", "url"], - "pdf": ["_t", "url"], - "audio": ["_t", "url"], - "web": ["_t", "url"], - "map": ["_t", "url"], - "date": ["_d", value => new Date(value.date).toISOString()], - "proxy": ["_i", "fieldId"], - "prefetch_proxy": ["_i", "fieldId"], - "list": ["_l", list => { - const results = []; - for (const value of list.fields) { - const term = ToSearchTerm(value); - if (term) { - results.push(term.value); + const suffixMap: { [type: string]: string | [string, string | ((json: any) => any)] } = { + number: '_n', + string: '_t', + boolean: '_b', + image: ['_t', 'url'], + video: ['_t', 'url'], + pdf: ['_t', 'url'], + audio: ['_t', 'url'], + web: ['_t', 'url'], + map: ['_t', 'url'], + date: ['_d', value => new Date(value.date).toISOString()], + proxy: ['_i', 'fieldId'], + prefetch_proxy: ['_i', 'fieldId'], + list: [ + '_l', + list => { + const results = []; + for (const value of list.fields) { + const term = ToSearchTerm(value); + if (term) { + results.push(term.value); + } } - } - return results.length ? results : null; - }] + return results.length ? results : null; + }, + ], }; - function ToSearchTerm(val: any): { suffix: string, value: any } | undefined { + function ToSearchTerm(val: any): { suffix: string; value: any } | undefined { if (val === null || val === undefined) { return; } @@ -213,7 +211,7 @@ export namespace SolrManager { if (Array.isArray(suffix)) { const accessor = suffix[1]; - if (typeof accessor === "function") { + if (typeof accessor === 'function') { val = accessor(val); } else { val = val[accessor]; @@ -223,5 +221,4 @@ export namespace SolrManager { return { suffix, value: val }; } - -}
\ No newline at end of file +} diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 6e28268a9..ba6d7acfe 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -75,7 +75,7 @@ export default class UploadManager extends ApiManager { for (const key in files) { const f = files[key]; if (!Array.isArray(f)) { - const result = await DashUploadUtils.upload(f); + const result = await DashUploadUtils.upload(f, key); // key is the guid used by the client to track upload progress. result && !(result.result instanceof Error) && results.push(result); } } @@ -180,13 +180,9 @@ export default class UploadManager extends ApiManager { const ids: { [id: string]: string } = {}; let remap = true; const getId = (id: string): string => { - if (!remap) return id; - if (id.endsWith('Proto')) return id; - if (id in ids) { - return ids[id]; - } else { - return (ids[id] = v4()); - } + if (!remap || id.endsWith('Proto')) return id; + if (id in ids) return ids[id]; + return (ids[id] = v4()); }; const mapFn = (doc: any) => { if (doc.id) { @@ -229,6 +225,7 @@ export default class UploadManager extends ApiManager { remap = fields.remap !== 'false'; let id: string = ''; let docids: string[] = []; + let linkids: string[] = []; try { for (const name in files) { const f = files[name]; @@ -255,27 +252,22 @@ export default class UploadManager extends ApiManager { console.log(e); } }); - const json = zip.getEntry('doc.json'); + const json = zip.getEntry('docs.json'); try { const data = JSON.parse(json.getData().toString('utf8'), retrocycle()); - const datadocs = data.docs; + const { docs, links } = data; id = getId(data.id); - const docs = Object.keys(datadocs).map(key => datadocs[key]); - docs.forEach(mapFn); - docids = docs.map(doc => doc.id); + const rdocs = Object.keys(docs).map(key => docs[key]); + const ldocs = Object.keys(links).map(key => links[key]); + [...rdocs, ...ldocs].forEach(mapFn); + docids = rdocs.map(doc => doc.id); + linkids = ldocs.map(link => link.id); await Promise.all( - docs.map( - (doc: any) => + [...rdocs, ...ldocs].map( + doc => new Promise<void>(res => { - Database.Instance.replace( - doc.id, - doc, - (err, r) => { - err && console.log(err); - res(); - }, - true - ); + // overwrite mongo doc with json doc contents + Database.Instance.replace(doc.id, doc, (err, r) => res(err && console.log(err)), true); }) ) ); @@ -285,7 +277,7 @@ export default class UploadManager extends ApiManager { unlink(path_2, () => {}); } SolrManager.update(); - res.send(JSON.stringify({ id, docids } || 'error')); + res.send(JSON.stringify({ id, docids, linkids } || 'error')); } catch (e) { console.log(e); } diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index f461cf3fa..eaaac4e6d 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -70,7 +70,14 @@ export namespace DashUploadUtils { // make a list of paths to create the ordered text file for ffmpeg const filePathsText = filePaths.map(filePath => `file '${filePath}'`).join('\n'); // write the text file to the file system - writeFile(textFilePath, filePathsText, err => console.log(err)); + await new Promise<void>((res, reject) => + writeFile(textFilePath, filePathsText, err => { + if (err) { + reject(); + console.log(err); + } else res(); + }) + ); // make output file name based on timestamp const outputFileName = `output-${Utils.GenerateGuid()}.mp4`; @@ -86,7 +93,10 @@ export namespace DashUploadUtils { .outputOptions('-c copy') //.videoCodec("copy") .save(outputFilePath) - .on('error', reject) + .on('error', (err: any) => { + console.log(err); + reject(); + }) .on('end', resolve); }); @@ -171,9 +181,10 @@ export namespace DashUploadUtils { }); } - export async function upload(file: File): Promise<Upload.FileResponse> { + export async function upload(file: File, overwriteGuid?: string): Promise<Upload.FileResponse> { const { type, path, name } = file; const types = type?.split('/') ?? []; + uploadProgress.set(overwriteGuid ?? name, 'uploading'); // If the client sent a guid it uses to track upload progress, use that guid. Otherwise, use the file's name. const category = types[0]; let format = `.${types[1]}`; @@ -195,6 +206,7 @@ export namespace DashUploadUtils { .videoCodec('copy') // this will copy the data instead of reencode it .save(file.path.replace('.mkv', '.mp4')) .on('end', res) + .on('error', (e: any) => console.log(e)) ); file.path = file.path.replace('.mkv', '.mp4'); format = '.mp4'; @@ -224,7 +236,7 @@ export namespace DashUploadUtils { return { source: file, result: { name: 'Unsupported video format', message: `Could not upload unsupported file (${name}). Please convert to an .mp4` } }; } } - if (videoFormats.includes(format)) { + if (videoFormats.includes(format) || format.includes('.webm')) { return MoveParsedFile(file, Directory.videos); } fs.unlink(path, () => {}); diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index b0db71f9c..805da1d43 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -22,6 +22,7 @@ import { Database } from './database'; import RouteManager from './RouteManager'; import RouteSubscriber from './RouteSubscriber'; import { WebSocket } from './websocket'; +import brotli = require('brotli'); import expressFlash = require('express-flash'); import flash = require('connect-flash'); const MongoStore = require('connect-mongo')(session); @@ -171,31 +172,29 @@ function registerCorsProxy(server: express.Express) { function proxyServe(req: any, requrl: string, response: any) { const htmlBodyMemoryStream = new (require('memorystream'))(); var retrieveHTTPBody: any; + var wasinBrFormat = false; const sendModifiedBody = () => { const header = response.headers['content-encoding']; + const httpsToCors = (match: any, href: string, offset: any, string: any) => `href="${resolvedServerUrl + '/corsProxy/http' + href}"`; if (header?.includes('gzip')) { try { - const replacer = (match: any, href: string, offset: any, string: any) => { - return `href="${resolvedServerUrl + '/corsProxy/http' + href}"`; - }; - const zipToStringDecoder = new (require('string_decoder').StringDecoder)('utf8'); const bodyStream = htmlBodyMemoryStream.read(); if (bodyStream) { - const htmlText = zipToStringDecoder.write( - zlib - .gunzipSync(bodyStream) - .toString('utf8') - .replace('<head>', '<head> <style>[id ^= "google"] { display: none; } </style>') - .replace(/href="https?([^"]*)"/g, replacer) - .replace(/target="_blank"/g, '') - ); + const htmlInputText = wasinBrFormat ? Buffer.from(brotli.decompress(bodyStream)) : zlib.gunzipSync(bodyStream); + const htmlText = htmlInputText + .toString('utf8') + .replace('<head>', '<head> <style>[id ^= "google"] { display: none; } </style>') + .replace(/href="https?([^"]*)"/g, httpsToCors) + .replace(/data-srcset="[^"]*"/g, '') + .replace(/srcset="[^"]*"/g, '') + .replace(/target="_blank"/g, ''); response.send(zlib.gzipSync(htmlText)); } else { req.pipe(request(requrl)).pipe(response); console.log('EMPTY body:' + req.url); } } catch (e) { - console.log('EROR?: ', e); + console.log('ERROR?: ', e); } } else { req.pipe(htmlBodyMemoryStream).pipe(response); @@ -216,6 +215,10 @@ function proxyServe(req: any, requrl: string, response: any) { } else if (headerCharRegex.test(header || '')) { delete res.headers[headerName]; } else res.headers[headerName] = header; + if (headerName === 'content-encoding') { + wasinBrFormat = res.headers[headerName] === 'br'; + res.headers[headerName] = 'gzip'; + } }); res.headers['x-permitted-cross-domain-policies'] = 'all'; res.headers['x-frame-options'] = ''; diff --git a/src/server/updateProtos.ts b/src/server/updateProtos.ts index c5552f6bf..2f3772a77 100644 --- a/src/server/updateProtos.ts +++ b/src/server/updateProtos.ts @@ -1,14 +1,22 @@ -import { Database } from "./database"; +import { Database } from './database'; -const protos = - ["text", "image", "web", "collection", "kvp", "video", "audio", "pdf", "icon", "import", "linkdoc", "map"]; +const protos = ['text', 'image', 'web', 'collection', 'kvp', 'video', 'audio', 'pdf', 'icon', 'import', 'linkdoc', 'map']; (async function () { await Promise.all( - protos.map(protoId => new Promise(res => Database.Instance.update(protoId, { - $set: { "fields.baseProto": true } - }, res))) + protos.map( + protoId => + new Promise(res => + Database.Instance.update( + protoId, + { + $set: { 'fields.isBaseProto': true }, + }, + res + ) + ) + ) ); - console.log("done"); -})();
\ No newline at end of file + console.log('done'); +})(); diff --git a/src/server/websocket.ts b/src/server/websocket.ts index a11d20cfa..be5cdb202 100644 --- a/src/server/websocket.ts +++ b/src/server/websocket.ts @@ -18,6 +18,7 @@ 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; @@ -51,7 +52,7 @@ export namespace WebSocket { next(); }); - socket.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()) + socket.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); // convenience function to log server messages on the client function log(message?: any, ...optionalParams: any[]) { @@ -104,14 +105,12 @@ export namespace WebSocket { socket.on('disconnect', function () { let currentUser = socketMap.get(socket); if (!(currentUser === undefined)) { - let currentUsername = currentUser.split(' ')[0] + let currentUsername = currentUser.split(' ')[0]; DashStats.logUserLogout(currentUsername, socket); - delete timeMap[currentUsername] + delete timeMap[currentUsername]; } }); - - Utils.Emit(socket, MessageStore.Foo, 'handshooken'); Utils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); @@ -146,10 +145,10 @@ export namespace WebSocket { }; }); - setInterval(function() { + setInterval(function () { // Utils.Emit(socket, MessageStore.UpdateStats, DashStats.getUpdatedStatsBundle()); - io.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()) + io.emit(MessageStore.UpdateStats.Message, DashStats.getUpdatedStatsBundle()); }, DashStats.SAMPLING_INTERVAL); } @@ -193,7 +192,7 @@ export namespace WebSocket { } function barReceived(socket: SocketIO.Socket, userEmail: string) { - clients[userEmail] = new Client(userEmail.toString()); + clients[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}`)); @@ -319,16 +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( @@ -336,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 = ''; @@ -373,9 +436,11 @@ export namespace WebSocket { var CurUser: string | undefined = undefined; function UpdateField(socket: Socket, diff: Diff) { - let currentUsername = socketMap.get(socket)!.split(' ')[0]; + 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); @@ -411,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; } } } |
