aboutsummaryrefslogtreecommitdiff
path: root/src/client/DocServer.ts
diff options
context:
space:
mode:
authorAndy Rickert <andrew_rickert@brown.edu>2020-07-31 19:04:32 -0400
committerAndy Rickert <andrew_rickert@brown.edu>2020-07-31 19:04:32 -0400
commitcfa39673564b6cd12d61ebbf3778cea8c3d0eff2 (patch)
treefd43d10a62c5d8f15057af7f1d788f263194ee0d /src/client/DocServer.ts
parenta1950ec49c56f5f9e2612da7e60a1e2615209386 (diff)
parentc71d7fa4f84149bcb62246d50e06bfd1481365bc (diff)
merge
Diffstat (limited to 'src/client/DocServer.ts')
-rw-r--r--src/client/DocServer.ts122
1 files changed, 71 insertions, 51 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 2a7a7c59a..f5ee6da3c 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -1,13 +1,15 @@
import * as io from 'socket.io-client';
import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message";
-import { Opt, Doc, fetchProto } from '../fields/Doc';
+import { Opt, Doc, fetchProto, FieldsSym, UpdatingFromServer } from '../fields/Doc';
import { Utils, emptyFunction } from '../Utils';
import { SerializationHelper } from './util/SerializationHelper';
import { RefField } from '../fields/RefField';
-import { Id, HandleUpdate } from '../fields/FieldSymbols';
+import { Id, HandleUpdate, Parent } from '../fields/FieldSymbols';
import GestureOverlay from './views/GestureOverlay';
import MobileInkOverlay from '../mobile/MobileInkOverlay';
import { runInAction } from 'mobx';
+import { ObjectField } from '../fields/ObjectField';
+import { getPlaygroundMode } from '../fields/util';
/**
* This class encapsulates the transfer and cross-client synchronization of
@@ -31,7 +33,7 @@ export namespace DocServer {
export enum WriteMode {
Default = 0, //Anything goes
- Playground = 1, //Playground (write own/no read)
+ Playground = 1, //Playground (write own/no read other updates)
LiveReadonly = 2,//Live Readonly (no write/read others)
LivePlayground = 3,//Live Playground (write own/read others)
}
@@ -39,9 +41,9 @@ export namespace DocServer {
const docsWithUpdates: { [field: string]: Set<Doc> } = {};
export var PlaygroundFields: string[];
- export function setPlaygroundFields(livePlayougroundFields: string[]) {
- DocServer.PlaygroundFields = livePlayougroundFields;
- livePlayougroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.LivePlayground));
+ export function setPlaygroundFields(livePlaygroundFields: string[]) {
+ DocServer.PlaygroundFields = livePlaygroundFields;
+ livePlaygroundFields.forEach(f => DocServer.setFieldWriteMode(f, DocServer.WriteMode.LivePlayground));
}
export function setFieldWriteMode(field: string, writeMode: WriteMode) {
@@ -155,23 +157,23 @@ export namespace DocServer {
let _isReadOnly = false;
export function makeReadOnly() {
- if (_isReadOnly) return;
- _isReadOnly = true;
- _CreateField = field => {
- _cache[field[Id]] = field;
- };
- _UpdateField = emptyFunction;
- _RespondToUpdate = emptyFunction;
+ if (!_isReadOnly) {
+ _isReadOnly = true;
+ _CreateField = field => _cache[field[Id]] = field;
+ _UpdateField = emptyFunction;
+ _RespondToUpdate = emptyFunction;
+ }
}
export function makeEditable() {
- if (!_isReadOnly) return;
- location.reload();
- // _isReadOnly = false;
- // _CreateField = _CreateFieldImpl;
- // _UpdateField = _UpdateFieldImpl;
- // _respondToUpdate = _respondToUpdateImpl;
- // _cache = {};
+ if (_isReadOnly) {
+ location.reload();
+ // _isReadOnly = false;
+ // _CreateField = _CreateFieldImpl;
+ // _UpdateField = _UpdateFieldImpl;
+ // _respondToUpdate = _respondToUpdateImpl;
+ // _cache = {};
+ }
}
export function isReadOnly() { return _isReadOnly; }
@@ -207,12 +209,12 @@ export namespace DocServer {
* the server if the document has not been cached.
* @param id the id of the requested document
*/
- const _GetRefFieldImpl = (id: string): Promise<Opt<RefField>> => {
+ const _GetRefFieldImpl = (id: string, force: boolean = false): Promise<Opt<RefField>> => {
// an initial pass through the cache to determine whether the document needs to be fetched,
// is already in the process of being fetched or already exists in the
// cache
const cached = _cache[id];
- if (cached === undefined) {
+ if (cached === undefined || force) {
// NOT CACHED => we'll have to send a request to the server
// synchronously, we emit a single callback to the server requesting the serialized (i.e. represented by a string)
@@ -226,7 +228,19 @@ export namespace DocServer {
const deserializeField = getSerializedField.then(async fieldJson => {
// deserialize
const field = await SerializationHelper.Deserialize(fieldJson);
- if (field !== undefined) {
+ if (force && field instanceof Doc && cached instanceof Doc) {
+ cached[UpdatingFromServer] = true;
+ Array.from(Object.keys(field)).forEach(key => {
+ const fieldval = field[key];
+ if (fieldval instanceof ObjectField) {
+ fieldval[Parent] = undefined;
+ }
+ cached[key] = field[key];
+ });
+ cached[UpdatingFromServer] = false;
+ return cached;
+ }
+ else if (field !== undefined) {
_cache[id] = field;
} else {
delete _cache[id];
@@ -238,8 +252,8 @@ export namespace DocServer {
});
// here, indicate that the document associated with this id is currently
// being retrieved and cached
- _cache[id] = deserializeField;
- return deserializeField;
+ !force && (_cache[id] = deserializeField);
+ return force ? cached as any : deserializeField;
} else if (cached instanceof Promise) {
// BEING RETRIEVED AND CACHED => some other caller previously (likely recently) called GetRefField(s),
// and requested the document I'm looking for. Shouldn't fetch again, just
@@ -260,11 +274,11 @@ export namespace DocServer {
}
};
- let _GetRefField: (id: string) => Promise<Opt<RefField>> = errorFunc;
+ let _GetRefField: (id: string, force: boolean) => Promise<Opt<RefField>> = errorFunc;
let _GetCachedRefField: (id: string) => Opt<RefField> = errorFunc;
- export function GetRefField(id: string): Promise<Opt<RefField>> {
- return _GetRefField(id);
+ export function GetRefField(id: string, force = false): Promise<Opt<RefField>> {
+ return _GetRefField(id, force);
}
export function GetCachedRefField(id: string): Opt<RefField> {
return _GetCachedRefField(id);
@@ -330,29 +344,35 @@ export namespace DocServer {
const proms: Promise<void>[] = [];
runInAction(() => {
for (const field of fields) {
- if (field !== undefined && field !== null) {
+ if (field !== undefined && field !== null && !_cache[field.id]) {
// deserialize
- const prom = SerializationHelper.Deserialize(field).then(deserialized => {
- fieldMap[field.id] = deserialized;
-
- //overwrite or delete any promises (that we inserted as flags
- // to indicate that the field was in the process of being fetched). Now everything
- // should be an actual value within or entirely absent from the cache.
- if (deserialized !== undefined) {
- _cache[field.id] = deserialized;
- } else {
- delete _cache[field.id];
- }
- return deserialized;
- });
- // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
- // we set the value at the field's id to a promise that will resolve to the field.
- // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
- // The mapping in the .then call ensures that when other callers await these promises, they'll
- // get the resolved field
- _cache[field.id] = prom;
- // adds to a list of promises that will be awaited asynchronously
- proms.push(prom);
+ const cached = _cache[field.id];
+ if (!cached) {
+ const prom = SerializationHelper.Deserialize(field).then(deserialized => {
+ fieldMap[field.id] = deserialized;
+
+ //overwrite or delete any promises (that we inserted as flags
+ // to indicate that the field was in the process of being fetched). Now everything
+ // should be an actual value within or entirely absent from the cache.
+ if (deserialized !== undefined) {
+ _cache[field.id] = deserialized;
+ } else {
+ delete _cache[field.id];
+ }
+ return deserialized;
+ });
+ // 4) here, for each of the documents we've requested *ourselves* (i.e. weren't promises or found in the cache)
+ // we set the value at the field's id to a promise that will resolve to the field.
+ // When we find that promises exist at keys in the cache, THIS is where they were set, just by some other caller (method).
+ // The mapping in the .then call ensures that when other callers await these promises, they'll
+ // get the resolved field
+ _cache[field.id] = prom;
+
+ // adds to a list of promises that will be awaited asynchronously
+ proms.push(prom);
+ } else if (cached instanceof Promise) {
+ proms.push(cached as any);
+ }
}
}
});
@@ -432,7 +452,7 @@ export namespace DocServer {
}
function _UpdateFieldImpl(id: string, diff: any) {
- Utils.Emit(_socket, MessageStore.UpdateField, { id, diff });
+ (!getPlaygroundMode()) && Utils.Emit(_socket, MessageStore.UpdateField, { id, diff });
}
let _UpdateField: (id: string, diff: any) => void = errorFunc;