json-joy
Version:
Collection of libraries for building collaborative editing apps.
188 lines (187 loc) • 6.74 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Decoder = void 0;
const tslib_1 = require("tslib");
const nodes = tslib_1.__importStar(require("../../../nodes"));
const ClockDecoder_1 = require("../../../../json-crdt-patch/codec/clock/ClockDecoder");
const CrdtReader_1 = require("../../../../json-crdt-patch/util/binary/CrdtReader");
const clock_1 = require("../../../../json-crdt-patch/clock");
const Model_1 = require("../../../model/Model");
const CborDecoderBase_1 = require("@jsonjoy.com/json-pack/lib/cbor/CborDecoderBase");
const constants_1 = require("../../../../json-crdt-patch/constants");
const constants_2 = require("./constants");
class Decoder extends CborDecoderBase_1.CborDecoderBase {
constructor() {
super(new CrdtReader_1.CrdtReader());
this.clockDecoder = undefined;
this.time = -1;
this.cStrChunk = () => {
const id = this.ts();
const val = this.val();
if (typeof val === 'string')
return new nodes.StrChunk(id, val.length, val);
return new nodes.StrChunk(id, ~~val, '');
};
this.cBinChunk = () => {
const id = this.ts();
const reader = this.reader;
const [deleted, length] = reader.b1vu56();
if (deleted)
return new nodes.BinChunk(id, length, undefined);
return new nodes.BinChunk(id, length, reader.buf(length));
};
this.cArrChunk = () => {
const id = this.ts();
const [deleted, length] = this.reader.b1vu56();
if (deleted)
return new nodes.ArrChunk(id, length, undefined);
const ids = [];
for (let i = 0; i < length; i++)
ids.push(this.cNode().id);
return new nodes.ArrChunk(id, length, ids);
};
}
decode(data, model) {
this.clockDecoder = undefined;
this.time = -1;
const reader = this.reader;
reader.reset(data);
const isServerTime = reader.peak() & 0b10000000;
if (isServerTime) {
reader.x++;
const time = (this.time = reader.vu57());
if (!model)
model = Model_1.Model.withServerClock(time);
}
else {
this.decodeClockTable();
if (!model) {
const clock = this.clockDecoder.clock;
model = Model_1.Model.withLogicalClock(clock);
}
}
this.doc = model;
model.root = new nodes.RootNode(this.doc, this.cRoot().id);
this.clockDecoder = undefined;
return model;
}
decodeClockTable() {
const reader = this.reader;
const clockTableOffset = reader.u32();
const offset = reader.x;
reader.x += clockTableOffset;
const length = reader.vu57();
const sessionId = reader.vu57();
const time = reader.vu57();
this.clockDecoder = new ClockDecoder_1.ClockDecoder(sessionId, time);
for (let i = 1; i < length; i++) {
const sid = reader.vu57();
const time = reader.vu57();
this.clockDecoder.pushTuple(sid, time);
}
reader.x = offset;
}
ts() {
const decoderTime = this.time;
const isLogical = decoderTime < 0;
if (isLogical) {
const [sessionIndex, timeDiff] = this.reader.id();
return this.clockDecoder.decodeId(sessionIndex, timeDiff);
}
else {
return new clock_1.Timestamp(constants_1.SESSION.SERVER, this.reader.vu57());
}
}
cRoot() {
const reader = this.reader;
const peek = reader.uint8[reader.x];
return !peek ? Model_1.UNDEFINED : this.cNode();
}
cNode() {
const reader = this.reader;
const id = this.ts();
const octet = reader.u8();
const major = octet >> 5;
const minor = octet & 0b11111;
switch (major) {
case constants_2.CRDT_MAJOR.CON:
return this.cCon(id, minor);
case constants_2.CRDT_MAJOR.VAL:
return this.cVal(id);
case constants_2.CRDT_MAJOR.OBJ:
return this.cObj(id, minor !== 0b11111 ? minor : reader.vu57());
case constants_2.CRDT_MAJOR.VEC:
return this.cVec(id, minor !== 0b11111 ? minor : reader.vu57());
case constants_2.CRDT_MAJOR.STR:
return this.cStr(id, minor !== 0b11111 ? minor : reader.vu57());
case constants_2.CRDT_MAJOR.BIN:
return this.cBin(id, minor !== 0b11111 ? minor : reader.vu57());
case constants_2.CRDT_MAJOR.ARR:
return this.cArr(id, minor !== 0b11111 ? minor : reader.vu57());
}
throw new Error('UNKNOWN_NODE');
}
cCon(id, length) {
const doc = this.doc;
const data = !length ? this.val() : this.ts();
const node = new nodes.ConNode(id, data);
doc.index.set(id, node);
return node;
}
cVal(id) {
const child = this.cNode();
const doc = this.doc;
const node = new nodes.ValNode(doc, id, child.id);
doc.index.set(id, node);
return node;
}
cObj(id, length) {
const obj = new nodes.ObjNode(this.doc, id);
for (let i = 0; i < length; i++)
this.cObjChunk(obj);
this.doc.index.set(id, obj);
return obj;
}
cObjChunk(obj) {
const key = this.key();
obj.keys.set(key, this.cNode().id);
}
cVec(id, length) {
const reader = this.reader;
const obj = new nodes.VecNode(this.doc, id);
const elements = obj.elements;
for (let i = 0; i < length; i++) {
const octet = reader.peak();
if (!octet) {
reader.x++;
elements.push(undefined);
}
else
elements.push(this.cNode().id);
}
this.doc.index.set(id, obj);
return obj;
}
cStr(id, length) {
const node = new nodes.StrNode(id);
if (length)
node.ingest(length, this.cStrChunk);
this.doc.index.set(id, node);
return node;
}
cBin(id, length) {
const node = new nodes.BinNode(id);
if (length)
node.ingest(length, this.cBinChunk);
this.doc.index.set(id, node);
return node;
}
cArr(id, length) {
const obj = new nodes.ArrNode(this.doc, id);
if (length)
obj.ingest(length, this.cArrChunk);
this.doc.index.set(id, obj);
return obj;
}
}
exports.Decoder = Decoder;