aboutsummaryrefslogtreecommitdiff
path: root/src/client/DocServer.ts
blob: 1d73abd1f10e9e19c2fea05f517b666b27430b01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import * as OpenSocket from 'socket.io-client';
import { MessageStore } from "./../server/Message";
import { Opt } from '../new_fields/Doc';
import { Utils } from '../Utils';
import { SerializationHelper } from './util/SerializationHelper';
import { RefField, HandleUpdate } from '../new_fields/RefField';

export namespace DocServer {
    const _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
    const _socket = OpenSocket(`${window.location.protocol}//${window.location.hostname}:4321`);
    const GUID: string = Utils.GenerateGuid();

    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<Opt<RefField>> {
        let cached = _cache[id];
        if (cached === undefined) {
            const prom = Utils.EmitCallback(_socket, MessageStore.GetRefField, id).then(fieldJson => {
                const field = fieldJson === undefined ? fieldJson : SerializationHelper.Deserialize(fieldJson);
                if (field) {
                    _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<RefField> }> {
        const requestedIds: string[] = [];
        const waitingIds: string[] = [];
        const promises: Promise<Opt<RefField>>[] = [];
        const map: { [id: string]: Opt<RefField> } = {};
        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) {
                    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) {
                _cache[id] = field;
            } else {
                delete _cache[id];
            }
            map[id] = field;
        });
        const otherFields = await Promise.all(promises);
        waitingIds.forEach((id, index) => map[id] = otherFields[index]);
        return map;
    }

    export function UpdateField(id: string, diff: any) {
        if (id === updatingId) {
            return;
        }
        Utils.Emit(_socket, MessageStore.UpdateField, { id, diff });
    }

    export function CreateField(initialState: any) {
        if (!("id" in initialState)) {
            throw new Error("Can't create a field on the server without an id");
        }
        Utils.Emit(_socket, MessageStore.CreateField, initialState);
    }

    let updatingId: string | undefined;
    function respondToUpdate(diff: any) {
        const id = diff.id;
        if (id === undefined) {
            return;
        }
        const field = _cache[id];
        const update = (f: Opt<RefField>) => {
            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 connected() {
        _socket.emit(MessageStore.Bar.Message, GUID);
    }

    Utils.AddServerHandler(_socket, MessageStore.Foo, connected);
    Utils.AddServerHandler(_socket, MessageStore.UpdateField, respondToUpdate);
}