import * as OpenSocket from 'socket.io-client'; import { MessageStore } from "./../server/Message"; import { Opt } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../new_fields/RefField'; import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; export namespace DocServer { const _cache: { [id: string]: RefField | Promise> } = {}; const _socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`); const GUID: string = Utils.GenerateGuid(); export function makeReadOnly() { _CreateField = field => { _cache[field[Id]] = field; }; _UpdateField = emptyFunction; _respondToUpdate = emptyFunction; } export function prepend(extension: string): string { return window.location.origin + extension; } export function DeleteDatabase() { Utils.Emit(_socket, MessageStore.DeleteAll, {}); } export async function GetRefField(id: string): Promise> { let cached = _cache[id]; if (cached === undefined) { const prom = Utils.EmitCallback(_socket, MessageStore.GetRefField, id).then(async fieldJson => { const field = SerializationHelper.Deserialize(fieldJson); if (field !== undefined) { await field.proto; _cache[id] = field; } else { delete _cache[id]; } return field; }); _cache[id] = prom; return prom; } else if (cached instanceof Promise) { return cached; } else { return cached; } } export async function GetRefFields(ids: string[]): Promise<{ [id: string]: Opt }> { const requestedIds: string[] = []; const waitingIds: string[] = []; const promises: Promise>[] = []; const map: { [id: string]: Opt } = {}; for (const id of ids) { const cached = _cache[id]; if (cached === undefined) { requestedIds.push(id); } else if (cached instanceof Promise) { promises.push(cached); waitingIds.push(id); } else { map[id] = cached; } } const prom = Utils.EmitCallback(_socket, MessageStore.GetRefFields, requestedIds).then(fields => { const fieldMap: { [id: string]: RefField } = {}; for (const field of fields) { if (field !== undefined) { fieldMap[field.id] = SerializationHelper.Deserialize(field); } } return fieldMap; }); requestedIds.forEach(id => _cache[id] = prom.then(fields => fields[id])); const fields = await prom; requestedIds.forEach(id => { const field = fields[id]; if (field !== undefined) { _cache[id] = field; } else { delete _cache[id]; } map[id] = field; }); await Promise.all(requestedIds.map(async id => { const field = fields[id]; if (field) { await (field as any).proto; } })); const otherFields = await Promise.all(promises); waitingIds.forEach((id, index) => map[id] = otherFields[index]); return map; } let _UpdateField = (id: string, diff: any) => { if (id === updatingId) { return; } Utils.Emit(_socket, MessageStore.UpdateField, { id, diff }); }; export function UpdateField(id: string, diff: any) { _UpdateField(id, diff); } let _CreateField = (field: RefField) => { _cache[field[Id]] = field; const initialState = SerializationHelper.Serialize(field); Utils.Emit(_socket, MessageStore.CreateField, initialState); }; export function CreateField(field: RefField) { _CreateField(field); } let updatingId: string | undefined; let _respondToUpdate = (diff: any) => { const id = diff.id; if (id === undefined) { return; } const field = _cache[id]; const update = (f: Opt) => { if (f === undefined) { return; } const handler = f[HandleUpdate]; if (handler) { updatingId = id; handler.call(f, diff.diff); updatingId = undefined; } }; if (field instanceof Promise) { field.then(update); } else { update(field); } }; function respondToUpdate(diff: any) { _respondToUpdate(diff); } function connected() { _socket.emit(MessageStore.Bar.Message, GUID); } Utils.AddServerHandler(_socket, MessageStore.Foo, connected); Utils.AddServerHandler(_socket, MessageStore.UpdateField, respondToUpdate); }