aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/DocServer.ts21
-rw-r--r--src/client/views/GestureOverlay.tsx5
-rw-r--r--src/fields/Doc.ts3
-rw-r--r--src/fields/ObjectField.ts15
-rw-r--r--src/fields/util.ts20
-rw-r--r--src/server/IDatabase.ts8
-rw-r--r--src/server/MemoryDatabase.ts6
-rw-r--r--src/server/Message.ts54
-rw-r--r--src/server/apis/google/GoogleApiServerUtils.ts1
-rw-r--r--src/server/database.ts12
-rw-r--r--src/server/server_Initialization.ts7
-rw-r--r--src/server/websocket.ts244
12 files changed, 133 insertions, 263 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 2bf3a6f9f..33fa928f2 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -8,7 +8,7 @@ import { UpdatingFromServer } from '../fields/DocSymbols';
import { FieldLoader } from '../fields/FieldLoader';
import { HandleUpdate, Id, Parent } from '../fields/FieldSymbols';
import { ObjectField, serverOpType } from '../fields/ObjectField';
-import { GestureContent, Message, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from '../server/Message';
+import { Message, MessageStore } from '../server/Message';
import { SerializationHelper } from './util/SerializationHelper';
/**
@@ -109,25 +109,6 @@ export namespace DocServer {
}
}
- export namespace Mobile {
- export function dispatchGesturePoints(content: GestureContent) {
- DocServer.Emit(_socket, MessageStore.GesturePoints, content);
- }
-
- export function dispatchOverlayTrigger(content: MobileInkOverlayContent) {
- // _socket.emit("dispatchBoxTrigger");
- DocServer.Emit(_socket, MessageStore.MobileInkOverlayTrigger, content);
- }
-
- export function dispatchOverlayPositionUpdate(content: UpdateMobileInkOverlayPositionContent) {
- DocServer.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content);
- }
-
- export function dispatchMobileDocumentUpload(content: MobileDocumentUploadContent) {
- DocServer.Emit(_socket, MessageStore.MobileDocumentUpload, content);
- }
- }
-
const instructions = 'This page will automatically refresh after this alert is closed. Expect to reconnect after about 30 seconds.';
function alertUser(connectionTerminationReason: string) {
switch (connectionTerminationReason) {
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index bcd4d1ee5..3a2738c3b 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -21,10 +21,8 @@ import {
SetActiveInkColor,
SetActiveInkWidth,
} from './nodes/DocumentView';
-// import MobileInkOverlay from '../../mobile/MobileInkOverlay';
import { Gestures } from '../../pen-gestures/GestureTypes';
import { GestureUtils } from '../../pen-gestures/GestureUtils';
-// import { MobileInkOverlayContent } from '../../server/Message';
import { InteractionUtils } from '../util/InteractionUtils';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { Transform } from '../util/Transform';
@@ -71,8 +69,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
return this.Tool !== ToolglassTools.None;
}
- // @observable private showMobileInkOverlay: boolean = false;
-
private _overlayRef = React.createRef<HTMLDivElement>();
private _d1: Doc | undefined;
private _inkToTextDoc: Doc | undefined;
@@ -485,7 +481,6 @@ export class GestureOverlay extends ObservableReactComponent<React.PropsWithChil
render() {
return (
<div className="gestureOverlay-cont" style={{ pointerEvents: this._props.isActive ? 'all' : 'none' }} ref={this._overlayRef} onPointerDown={this.onPointerDown}>
- {/* {this.showMobileInkOverlay ? <MobileInkOverlay /> : null} */}
{this.elements}
<div
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index 7e7c319bf..ad7609895 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -191,7 +191,6 @@ export class Doc extends RefField {
@observable public static RecordingEvent = 0;
@observable public static GuestDashboard: Doc | undefined = undefined;
@observable public static GuestTarget: Doc | undefined = undefined;
- @observable public static GuestMobile: Doc | undefined = undefined;
@observable.shallow public static CurrentlyLoading: Doc[] = observable([]);
// DocServer api
public static FindDocByTitle(title: string) {
@@ -379,7 +378,7 @@ export class Doc extends RefField {
private [CachedUpdates]: { [key: string]: () => void | Promise<void> } = {};
public [Initializing]: boolean = false;
- public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: unknown } | undefined, serverOp: serverOpType) => {
+ public [FieldChanged] = (diff: { op: '$addToSet' | '$remFromSet' | '$set'; items: FieldType[] | undefined; length: number | undefined; hint?: { start: number; deleteCount: number } } | undefined, serverOp: serverOpType) => {
if (!this[UpdatingFromServer] || this[ForceServerWrite]) {
DocServer.UpdateField(this[Id], serverOp);
}
diff --git a/src/fields/ObjectField.ts b/src/fields/ObjectField.ts
index 21c4af608..5f31208eb 100644
--- a/src/fields/ObjectField.ts
+++ b/src/fields/ObjectField.ts
@@ -2,11 +2,18 @@ import { ScriptingGlobals } from '../client/util/ScriptingGlobals';
import { Copy, FieldChanged, Parent, ToJavascriptString, ToScriptString, ToString } from './FieldSymbols';
import { RefField } from './RefField';
+export type serializedFieldType = { fieldId: string; heading?: string; __type: string };
+export type serializedFieldsType = { [key: string]: { fields: serializedFieldType[] } };
+export interface serializedDoctype {
+ readonly id: string;
+ readonly fields?: serializedFieldsType;
+}
+
export type serverOpType = {
- $set?: { [key: string]: unknown }; //
+ $set?: serializedFieldsType; //
$unset?: { [key: string]: unknown };
- $remFromSet?: { [key: string]: unknown };
- $addToSet?: { [key: string]: unknown };
+ $remFromSet?: { [key: string]: { fields: serializedFieldType[] } | { deleteCount: number; start: number } | undefined; hint?: { deleteCount: number; start: number } };
+ $addToSet?: serializedFieldsType;
length?: number;
};
export abstract class ObjectField {
@@ -15,7 +22,7 @@ export abstract class ObjectField {
// eslint-disable-next-line no-use-before-define
items: FieldType[] | undefined;
length: number | undefined;
- hint?: unknown },
+ hint?: { deleteCount: number, start: number} },
serverOp?: serverOpType) => void;
// eslint-disable-next-line no-use-before-define
public [Parent]?: RefField | ObjectField;
diff --git a/src/fields/util.ts b/src/fields/util.ts
index 69ece82a2..a5c56607c 100644
--- a/src/fields/util.ts
+++ b/src/fields/util.ts
@@ -8,7 +8,7 @@ import { Doc, DocListCast, FieldType, FieldResult, HierarchyMapping, ReverseHier
import { AclAdmin, AclAugment, AclEdit, AclPrivate, DirectLinks, DocAcl, DocData, DocLayout, FieldKeys, ForceServerWrite, Height, Initializing, SelfProxy, UpdatingFromServer, Width } from './DocSymbols';
import { FieldChanged, Id, Parent, ToValue } from './FieldSymbols';
import { List, ListImpl } from './List';
-import { ObjectField } from './ObjectField';
+import { ObjectField, serializedFieldType, serverOpType } from './ObjectField';
import { PrefetchProxy, ProxyField } from './Proxy';
import { RefField } from './RefField';
import { RichTextField } from './RichTextField';
@@ -112,9 +112,9 @@ const _setterImpl = action((target: Doc | ListImpl<FieldType>, prop: string | sy
if (writeToServer) {
// prettier-ignore
- if (value === undefined)
+ if (value === undefined || value === null)
(target as Doc|ObjectField)[FieldChanged]?.(undefined, { $unset: { ['fields.' + prop]: '' } });
- else (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $set: { ['fields.' + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) :value}});
+ else (target as Doc|ObjectField)[FieldChanged]?.(undefined, { $set: { ['fields.' + prop]: (value instanceof ObjectField ? SerializationHelper.Serialize(value) :value) as { fields: serializedFieldType[]}}});
if (prop === 'author' || prop.toString().startsWith('acl_')) updateCachedAcls(target);
} else if (receiver instanceof Doc) {
DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue);
@@ -393,15 +393,15 @@ export function deleteProperty(target: Doc | ListImpl<FieldType>, prop: string |
// able to undo and redo the partial change.
//
export function containedFieldChangedHandler(container: ListImpl<FieldType> | Doc, prop: string | number, liveContainedField: ObjectField) {
- let lastValue: FieldResult = liveContainedField instanceof ObjectField ? ObjectField.MakeCopy(liveContainedField) : liveContainedField;
- return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: (FieldType & { value?: FieldType })[] | undefined; length: number | undefined; hint?: unknown } /* , dummyServerOp?: any */) => {
- const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item)) });
+ let lastValue = ObjectField.MakeCopy(liveContainedField);
+ return (diff?: { op: '$addToSet' | '$remFromSet' | '$set'; items: (FieldType & { value?: FieldType })[] | undefined; length: number | undefined; hint?: { start: number; deleteCount: number } } /* , dummyServerOp?: any */) => {
+ const serializeItems = () => ({ __type: 'list', fields: diff?.items?.map((item: FieldType) => SerializationHelper.Serialize(item) as serializedFieldType) ?? [] });
// prettier-ignore
- const serverOp = diff?.op === '$addToSet'
+ const serverOp: serverOpType = diff?.op === '$addToSet'
? { $addToSet: { ['fields.' + prop]: serializeItems() }, length: diff.length }
: diff?.op === '$remFromSet'
? { $remFromSet: { ['fields.' + prop]: serializeItems(), hint: diff.hint}, length: diff.length }
- : { $set: { ['fields.' + prop]: liveContainedField ? SerializationHelper.Serialize(liveContainedField) as FieldType : undefined } };
+ : { $set: { ['fields.' + prop]: SerializationHelper.Serialize(liveContainedField) as {fields: serializedFieldType[]}} };
if (!(container instanceof Doc) || !container[UpdatingFromServer]) {
const cont = container as { [key: string | number]: FieldType };
@@ -477,13 +477,13 @@ export function containedFieldChangedHandler(container: ListImpl<FieldType> | Do
// console.log('redo list: ' + prop, fieldVal()); // bcz: uncomment to log undo
setFieldVal(ObjectField.MakeCopy(newValue));
const containerProp = cont[prop];
- lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp);
+ if (containerProp instanceof ObjectField) lastValue = ObjectField.MakeCopy(containerProp);
},
undo: () => {
// console.log('undo list: ' + prop, fieldVal()); // bcz: uncomment to log undo
setFieldVal(ObjectField.MakeCopy(prevValue));
const containerProp = cont[prop];
- lastValue = containerProp instanceof ObjectField && ObjectField.MakeCopy(containerProp);
+ if (containerProp instanceof ObjectField) lastValue = ObjectField.MakeCopy(containerProp);
},
prop: 'set list field',
},
diff --git a/src/server/IDatabase.ts b/src/server/IDatabase.ts
index 2274792b3..481b64d4a 100644
--- a/src/server/IDatabase.ts
+++ b/src/server/IDatabase.ts
@@ -1,5 +1,5 @@
import * as mongodb from 'mongodb';
-import { Transferable } from './Message';
+import { serializedDoctype } from '../fields/ObjectField';
export const DocumentsCollection = 'documents';
export interface IDatabase {
@@ -13,10 +13,10 @@ export interface IDatabase {
dropSchema(...schemaNames: string[]): Promise<any>;
- insert(value: any, collectionName?: string): Promise<void>;
+ insert(value: { _id: string }, collectionName?: string): Promise<void>;
- getDocument(id: string, fn: (result?: Transferable) => void, collectionName?: string): void;
- getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName?: string): void;
+ getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName?: string): void;
+ getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName?: string): void;
getCollectionNames(): Promise<string[]>;
visit(ids: string[], fn: (result: any) => string[] | Promise<string[]>, collectionName?: string): Promise<void>;
diff --git a/src/server/MemoryDatabase.ts b/src/server/MemoryDatabase.ts
index 1432d91c4..b838cb61b 100644
--- a/src/server/MemoryDatabase.ts
+++ b/src/server/MemoryDatabase.ts
@@ -1,6 +1,6 @@
import * as mongodb from 'mongodb';
+import { serializedDoctype } from '../fields/ObjectField';
import { DocumentsCollection, IDatabase } from './IDatabase';
-import { Transferable } from './Message';
export class MemoryDatabase implements IDatabase {
private db: { [collectionName: string]: { [id: string]: any } } = {};
@@ -81,10 +81,10 @@ export class MemoryDatabase implements IDatabase {
return Promise.resolve();
}
- public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection): void {
+ public getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName = DocumentsCollection): void {
fn(this.getCollection(collectionName)[id]);
}
- public getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection): void {
+ public getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName = DocumentsCollection): void {
fn(ids.map(id => this.getCollection(collectionName)[id]));
}
diff --git a/src/server/Message.ts b/src/server/Message.ts
index 8e30cd6df..4599708c9 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -1,5 +1,6 @@
import * as uuid from 'uuid';
import { Point } from '../pen-gestures/ndollar';
+import { serverOpType } from '../fields/ObjectField';
function GenerateDeterministicGuid(seed: string): string {
return uuid.v5(seed, uuid.v5.URL);
@@ -22,40 +23,12 @@ export class Message<T> {
}
}
-export enum Types {
- Number,
- List,
- Key,
- Image,
- Web,
- Document,
- Text,
- Icon,
- RichText,
- DocumentReference,
- Html,
- Video,
- Audio,
- Ink,
- PDF,
- Tuple,
- Boolean,
- Script,
- Templates,
-}
-
-export interface Transferable {
- readonly id: string;
- readonly type: Types;
- readonly data?: unknown;
-}
-
export interface Reference {
readonly id: string;
}
export interface Diff extends Reference {
- readonly diff: any;
+ readonly diff: serverOpType;
}
export interface GestureContent {
@@ -65,23 +38,6 @@ export interface GestureContent {
readonly color?: string;
}
-export interface MobileInkOverlayContent {
- readonly enableOverlay: boolean;
- readonly width?: number;
- readonly height?: number;
- readonly text?: string;
-}
-
-export interface UpdateMobileInkOverlayPositionContent {
- readonly dx?: number;
- readonly dy?: number;
- readonly dsize?: number;
-}
-
-export interface MobileDocumentUploadContent {
- readonly docId: string;
-}
-
export interface RoomMessage {
readonly message: string;
readonly room: string;
@@ -91,17 +47,11 @@ export interface RoomMessage {
export namespace MessageStore {
export const Foo = new Message<string>('Foo');
export const Bar = new Message<string>('Bar');
- export const SetField = new Message<Transferable>('Set Field'); // send Transferable (no reply)
- export const GetField = new Message<string>('Get Field'); // send string 'id' get Transferable back
- export const GetFields = new Message<string[]>('Get Fields'); // send string[] of 'id' get Transferable[] back
export const GetDocument = new Message<string>('Get Document');
export const DeleteAll = new Message<unknown>('Delete All');
export const ConnectionTerminated = new Message<string>('Connection Terminated');
export const GesturePoints = new Message<GestureContent>('Gesture Points');
- export const MobileInkOverlayTrigger = new Message<MobileInkOverlayContent>('Trigger Mobile Ink Overlay');
- export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPositionContent>('Update Mobile Ink Overlay Position');
- export const MobileDocumentUpload = new Message<MobileDocumentUploadContent>('Upload Document From Mobile');
export const GetRefField = new Message<string>('Get Ref Field');
export const GetRefFields = new Message<string[]>('Get Ref Fields');
diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts
index d3acc968b..47206f415 100644
--- a/src/server/apis/google/GoogleApiServerUtils.ts
+++ b/src/server/apis/google/GoogleApiServerUtils.ts
@@ -21,6 +21,7 @@ const scope = ['documents.readonly', 'documents', 'presentations', 'presentation
* This namespace manages server side authentication for Google API queries, either
* from the standard v1 APIs or the Google Photos REST API.
*/
+// eslint-disable-next-line @typescript-eslint/no-namespace
export namespace GoogleApiServerUtils {
/**
* As we expand out to more Google APIs that are accessible from
diff --git a/src/server/database.ts b/src/server/database.ts
index ff8584cd7..a93117349 100644
--- a/src/server/database.ts
+++ b/src/server/database.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-namespace */
import * as mongodb from 'mongodb';
import * as mongoose from 'mongoose';
import { Opt } from '../fields/Doc';
@@ -5,11 +6,11 @@ import { emptyFunction, Utils } from '../Utils';
import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils';
import { DocumentsCollection, IDatabase } from './IDatabase';
import { MemoryDatabase } from './MemoryDatabase';
-import { Transferable } from './Message';
import { Upload } from './SharedMediaTypes';
+import { serializedDoctype } from '../fields/ObjectField';
export namespace Database {
- export let disconnect: Function;
+ export let disconnect: () => void;
class DocSchema implements mongodb.BSON.Document {
_id!: string;
@@ -84,6 +85,7 @@ export namespace Database {
if (this.db) {
const collection = this.db.collection<DocSchema>(collectionName);
const prom = this.currentWrites[id];
+ // eslint-disable-next-line prefer-const
let newProm: Promise<void>;
const run = (): Promise<void> =>
new Promise<void>(resolve => {
@@ -112,6 +114,7 @@ export namespace Database {
if (this.db) {
const collection = this.db.collection<DocSchema>(collectionName);
const prom = this.currentWrites[id];
+ // eslint-disable-next-line prefer-const
let newProm: Promise<void>;
const run = (): Promise<void> =>
new Promise<void>(resolve => {
@@ -196,6 +199,7 @@ export namespace Database {
const id = value._id;
const collection = this.db.collection<DocSchema>(collectionName);
const prom = this.currentWrites[id];
+ // eslint-disable-next-line prefer-const
let newProm: Promise<void>;
const run = (): Promise<void> =>
new Promise<void>(resolve => {
@@ -219,7 +223,7 @@ export namespace Database {
return undefined;
}
- public getDocument(id: string, fn: (result?: Transferable) => void, collectionName = DocumentsCollection) {
+ public getDocument(id: string, fn: (result?: serializedDoctype) => void, collectionName = DocumentsCollection) {
if (this.db) {
const collection = this.db.collection<DocSchema>(collectionName);
collection.findOne({ _id: id }).then(resultIn => {
@@ -237,7 +241,7 @@ export namespace Database {
}
}
- public async getDocuments(ids: string[], fn: (result: Transferable[]) => void, collectionName = DocumentsCollection) {
+ public async getDocuments(ids: string[], fn: (result: serializedDoctype[]) => void, collectionName = DocumentsCollection) {
if (this.db) {
const found = await this.db
.collection<DocSchema>(collectionName)
diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts
index 9183688c6..2190e27c7 100644
--- a/src/server/server_Initialization.ts
+++ b/src/server/server_Initialization.ts
@@ -29,7 +29,6 @@ import { WebSocket } from './websocket';
export type RouteSetter = (server: RouteManager) => void;
// export let disconnect: Function;
-// eslint-disable-next-line import/no-mutable-exports
export let resolvedServerUrl: string;
const week = 7 * 24 * 60 * 60 * 1000;
@@ -115,12 +114,12 @@ function registerEmbeddedBrowseRelativePathHandler(server: express.Express) {
}
function proxyServe(req: any, requrl: string, response: any) {
- // eslint-disable-next-line global-require
+ // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
const htmlBodyMemoryStream = new (require('memorystream'))();
let wasinBrFormat = false;
const sendModifiedBody = () => {
const header = response.headers['content-encoding'];
- const refToCors = (match: any, tag: string, sym: string, href: string) => `${tag}=${sym + resolvedServerUrl}/corsProxy/${href + sym}`;
+ const refToCors = (match: string, tag: string, sym: string, href: string) => `${tag}=${sym + resolvedServerUrl}/corsProxy/${href + sym}`;
// const relpathToCors = (match: any, href: string, offset: any, string: any) => `="${resolvedServerUrl + '/corsProxy/' + decodeURIComponent(req.originalUrl.split('/corsProxy/')[1].match(/https?:\/\/[^\/]*/)?.[0] ?? '') + '/' + href}"`;
if (header) {
try {
@@ -238,7 +237,7 @@ function registerAuthenticationRoutes(server: express.Express) {
export default async function InitializeServer(routeSetter: RouteSetter) {
const isRelease = determineEnvironment();
const app = buildWithMiddleware(express());
- const compiler = webpack(config as any);
+ const compiler = webpack(config as webpack.Configuration);
// route table managed by express. routes are tested sequentially against each of these map rules. when a match is found, the handler is called to process the request
app.use(wdm(compiler, { publicPath: config.output.publicPath }));
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 905dbcf57..f10455680 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -3,13 +3,14 @@ import { createServer } from 'https';
import * as _ from 'lodash';
import { networkInterfaces } from 'os';
import { Server, Socket } from 'socket.io';
+import { SecureContextOptions } from 'tls';
import { ServerUtils } from '../ServerUtils';
+import { serializedDoctype, serializedFieldsType } from '../fields/ObjectField';
import { logPort } from './ActionUtilities';
import { Client } from './Client';
import { DashStats } from './DashStats';
import { DocumentsCollection } from './IDatabase';
-import { Diff, GestureContent, MessageStore, MobileDocumentUploadContent, MobileInkOverlayContent, Transferable, Types, UpdateMobileInkOverlayPositionContent } from './Message';
-import { Search } from './Search';
+import { Diff, GestureContent, MessageStore } from './Message';
import { resolvedPorts, socketMap, timeMap, userOperations } from './SocketData';
import { initializeGuest } from './authentication/DashUserModel';
import { Database } from './database';
@@ -25,25 +26,10 @@ export namespace WebSocket {
socket.broadcast.emit('receiveGesturePoints', content);
}
- function processOverlayTrigger(socket: Socket, content: MobileInkOverlayContent) {
- socket.broadcast.emit('receiveOverlayTrigger', content);
- }
-
- function processUpdateOverlayPosition(socket: Socket, content: UpdateMobileInkOverlayPositionContent) {
- socket.broadcast.emit('receiveUpdateOverlayPosition', content);
- }
-
- function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) {
- socket.broadcast.emit('receiveMobileDocumentUpload', content);
- }
-
export async function doDelete(onlyFields = true) {
const target: string[] = [];
onlyFields && target.push(DocumentsCollection);
await Database.Instance.dropSchema(...target);
- if (process.env.DISABLE_SEARCH !== 'true') {
- await Search.clear();
- }
initializeGuest();
}
@@ -63,31 +49,15 @@ export namespace WebSocket {
DashStats.logUserLogin(userEmail);
}
- function getField([id, callback]: [string, (result?: Transferable) => void]) {
- Database.Instance.getDocument(id, (result?: Transferable) => callback(result));
- }
-
- function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) {
- Database.Instance.getDocuments(ids, callback);
- }
-
- function setField(socket: Socket, newValue: Transferable) {
- Database.Instance.update(newValue.id, newValue, () => socket.broadcast.emit(MessageStore.SetField.Message, newValue)); // broadcast set value to all other clients
- if (newValue.type === Types.Text) {
- // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR
- Search.updateDocument({ id: newValue.id, data: { set: newValue.data } });
- }
- }
-
- function GetRefFieldLocal([id, callback]: [string, (result?: Transferable) => void]) {
+ function GetRefFieldLocal([id, callback]: [string, (result?: serializedDoctype) => void]) {
return Database.Instance.getDocument(id, callback);
}
- function GetRefField([id, callback]: [string, (result?: Transferable) => void]) {
+ function GetRefField([id, callback]: [string, (result?: serializedDoctype) => void]) {
process.stdout.write(`+`);
GetRefFieldLocal([id, callback]);
}
- function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) {
+ function GetRefFields([ids, callback]: [string[], (result?: serializedDoctype[]) => void]) {
process.stdout.write(`${ids.length}…`);
Database.Instance.getDocuments(ids, callback);
}
@@ -151,11 +121,11 @@ export namespace WebSocket {
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
+ return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => 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
+ return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => 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);
@@ -163,37 +133,41 @@ export namespace WebSocket {
return !pendingOps.get(id)!.length && pendingOps.delete(id);
}
- function addToListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void {
+ function addToListField(socket: Socket, diffIn: Diff, listDoc?: serializedDoctype): 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];
- const newListItems = diff.diff.$set[updatefield]?.fields;
+ const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0];
+ const newListItems = diff.diff.$set?.[updatefield]?.fields;
if (!newListItems) {
console.log('Error: addToListField - no new list items');
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))];
- const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length;
- delete diff.diff.length;
- Database.Instance.update(
- diff.id,
- diff.diff,
- () => {
- if (sendBack) {
- console.log('Warning: list modified during update. Composite list is being returned.');
- 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);
- }
- dispatchNextOp(diff.id);
- },
- false
- );
+ const listItems = listDoc?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(item => item !== undefined) ?? [];
+ if (diff.diff.$set?.[updatefield]?.fields !== undefined) {
+ diff.diff.$set[updatefield]!.fields = [...listItems, ...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(
+ diff.id,
+ diff.diff,
+ () => {
+ if (sendBack) {
+ console.log('Warning: list modified during update. Composite list is being returned.');
+ const { id } = socket;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (socket as any).id = ''; // bcz: HACK to reference private variable. this allows the update message to go back to the client that made the change.
+ socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (socket as any).id = id;
+ } else {
+ socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ }
+ dispatchNextOp(diff.id);
+ },
+ false
+ );
+ }
}
/**
@@ -208,7 +182,7 @@ export namespace WebSocket {
* 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) {
+ function findClosestIndex(list: { fieldId: string; __type: string }[], indexesToDelete: number[], value: { fieldId: string; __type: string }, hintIndex: number) {
let closestIndex = -1;
for (let i = 0; i < list.length; i++) {
if (list[i] === value && !indexesToDelete.includes(i)) {
@@ -232,63 +206,63 @@ export namespace WebSocket {
* items to delete)
* @param curListItems the server's current copy of the data
*/
- function remFromListField(socket: Socket, diffIn: Diff, curListItems?: Transferable): void {
+ function remFromListField(socket: Socket, diffIn: Diff, curListItems?: serializedDoctype): void {
const diff = diffIn;
- diff.diff.$set = diff.diff.$remFromSet;
+ diff.diff.$set = diff.diff.$remFromSet as serializedFieldsType;
+ const hint = diff.diff.$remFromSet?.hint;
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;
-
- if (hint) {
- // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements)
- 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);
- } else {
- const closestIndex = findClosestIndex(curList, indexesToRemove, remListItems[i], i + hint.start);
- if (closestIndex !== -1) {
- indexesToRemove.push(closestIndex);
+ const updatefield = Array.from(Object.keys(diff.diff.$set ?? {}))[0];
+ const remListItems = diff.diff.$set[updatefield]?.fields;
+ if (diff.diff.$set[updatefield] !== undefined && remListItems) {
+ const curList = curListItems?.fields?.[updatefield.replace('fields.', '')]?.fields.filter(f => f !== null) || [];
+
+ if (hint) {
+ // indexesToRemove stores the indexes that we mark for deletion, which is later used to filter the list (delete the elements)
+ 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);
} 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');
+ }
}
}
+ diff.diff.$set[updatefield]!.fields = curList.filter((curItem, index) => !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 => !remListItems.some(remItem => (remItem.fieldId ? remItem.fieldId === curItem.fieldId : remItem.heading ? remItem.heading === curItem.heading : remItem === curItem)));
}
-
- 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 !== remListItems.length;
+ delete diff.diff.length;
+ Database.Instance.update(
+ diff.id,
+ diff.diff,
+ () => {
+ if (sendBack) {
+ // the two copies are different, so the server sends its copy.
+ console.log('SEND BACK');
+ const { id } = socket;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (socket as any).id = ''; // bcz: HACK to access private variable this allows the update message to go back to the client that made the change.
+ socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (socket as any).id = id;
+ } else {
+ socket.broadcast.emit(MessageStore.UpdateField.Message, diff);
+ }
+ dispatchNextOp(diff.id);
+ },
+ false
);
}
-
- // 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(
- diff.id,
- diff.diff,
- () => {
- if (sendBack) {
- // the two copies are different, so the server sends its copy.
- console.log('SEND BACK');
- 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);
- }
- dispatchNextOp(diff.id);
- },
- false
- );
}
function UpdateField(socket: Socket, diff: Diff) {
@@ -307,43 +281,16 @@ export namespace WebSocket {
}
pendingOps.set(diff.id, [{ diff, socket }]);
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
+ return GetRefFieldLocal([diff.id, (result?: serializedDoctype) => 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?: serializedDoctype) => 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);
}
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];
- key = key.substring(7);
- Object.values(suffixMap).forEach(suf => {
- update[key + getSuffix(suf)] = { set: null };
- });
- const term = ToSearchTerm(val);
- if (term !== undefined) {
- const { suffix, value } = term;
- update[key + suffix] = { set: value };
- if (key.endsWith('modificationDate')) {
- update['modificationDate' + suffix] = value;
- }
- }
- }
- if (dynfield) {
- Search.updateDocument(update);
- }
- }
dispatchNextOp(diff.id);
}
@@ -351,21 +298,15 @@ export namespace WebSocket {
Database.Instance.delete({ _id: id }).then(() => {
socket.broadcast.emit(MessageStore.DeleteField.Message, id);
});
-
- Search.deleteDocuments([id]);
}
function DeleteFields(socket: Socket, ids: string[]) {
Database.Instance.delete({ _id: { $in: ids } }).then(() => {
socket.broadcast.emit(MessageStore.DeleteFields.Message, ids);
});
- Search.deleteDocuments(ids);
}
- function CreateField(newValue: any) {
- Database.Instance.insert(newValue);
- }
- export async function initialize(isRelease: boolean, credentials: any) {
+ export async function initialize(isRelease: boolean, credentials: SecureContextOptions) {
let io: Server;
if (isRelease) {
const { socketPort } = process.env;
@@ -422,21 +363,14 @@ export namespace WebSocket {
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.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);