diff options
Diffstat (limited to 'src/client/DocServer.ts')
-rw-r--r-- | src/client/DocServer.ts | 122 |
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; |