Starting on one-way sync
This commit is contained in:
177
src/com/commit.ts
Normal file
177
src/com/commit.ts
Normal file
@ -0,0 +1,177 @@
|
||||
export default interface Commit {
|
||||
id: string;
|
||||
root: string;
|
||||
before: string;
|
||||
merge: string;
|
||||
date: number;
|
||||
}
|
||||
export function serialize_Commit (data: Commit): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["id"] !== null && data["id"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["id"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 0, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["root"] !== null && data["root"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["root"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 1, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["before"] !== null && data["before"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["before"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 2, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["merge"] !== null && data["merge"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["merge"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 3, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["date"] !== null && data["date"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const f = makeField(8, 4, 8);
|
||||
f.setBigUint64(0, BigInt(data["date"]));
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_Commit (data: Uint8Array): Commit {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["id"] = str;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["root"] = str;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["before"] = str;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["merge"] = str;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
result["date"] = Number(view.getBigUint64(idx)); idx += 8;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
126
src/com/pullgetlogrequest.ts
Normal file
126
src/com/pullgetlogrequest.ts
Normal file
@ -0,0 +1,126 @@
|
||||
export default interface PullGetLogRequest {
|
||||
limit: number;
|
||||
start: string;
|
||||
}
|
||||
export function serialize_PullGetLogRequest (data: PullGetLogRequest): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["limit"] !== null && data["limit"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const f = makeField(4, 0, 7);
|
||||
f.setUint32(0, data["limit"]);
|
||||
}
|
||||
|
||||
if(data["start"] !== null && data["start"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["start"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 1, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_PullGetLogRequest (data: Uint8Array): PullGetLogRequest {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
result["limit"] = view.getUint32(idx); idx += 4;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["start"] = str;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
125
src/com/pullgetlogresponse.ts
Normal file
125
src/com/pullgetlogresponse.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import Commit, { serialize_Commit, deserialize_Commit} from "./commit";
|
||||
export default interface PullGetLogResponse {
|
||||
commits: Commit[];
|
||||
}
|
||||
export function serialize_PullGetLogResponse (data: PullGetLogResponse): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["commits"] !== null && data["commits"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
makeField(0, 0, 40)
|
||||
const len = data["commits"].length
|
||||
addBuffer(getAutoGrowLength(len))
|
||||
for(let i = 0; i < len ; i++) {
|
||||
const subFieldData = serialize_Commit(data["commits"][i]);
|
||||
const lengthBytes = getAutoGrowLength(subFieldData.byteLength);
|
||||
const f = makeArrayBuffer(subFieldData.byteLength + lengthBytes.byteLength)
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(subFieldData), lengthBytes.byteLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_PullGetLogResponse (data: Uint8Array): PullGetLogResponse {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
const arrayLength = readAutoGrowLength();
|
||||
const values: any[] = []
|
||||
for(let i = 0; i < arrayLength; i++) {
|
||||
const subFieldLength = readAutoGrowLength();
|
||||
const subFieldData = data.slice(idx, idx + subFieldLength); idx += subFieldLength;
|
||||
values[i] = deserialize_Commit(subFieldData);
|
||||
}
|
||||
result["commits"] = values;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
132
src/com/pullobjectrequest.ts
Normal file
132
src/com/pullobjectrequest.ts
Normal file
@ -0,0 +1,132 @@
|
||||
export default interface PullObjectRequest {
|
||||
id: string;
|
||||
type: string;
|
||||
}
|
||||
export function serialize_PullObjectRequest (data: PullObjectRequest): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["id"] !== null && data["id"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["id"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 0, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["type"] !== null && data["type"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["type"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 1, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_PullObjectRequest (data: Uint8Array): PullObjectRequest {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["id"] = str;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["type"] = str;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
125
src/com/pullobjectresponse.ts
Normal file
125
src/com/pullobjectresponse.ts
Normal file
@ -0,0 +1,125 @@
|
||||
export default interface PullObjectResponse {
|
||||
found: boolean;
|
||||
data: Uint8Array;
|
||||
}
|
||||
export function serialize_PullObjectResponse (data: PullObjectResponse): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["found"] !== null && data["found"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const f = makeField(1, 0, 5);
|
||||
f.setUint8(0, Number(data["found"]));
|
||||
}
|
||||
|
||||
if(data["data"] !== null && data["data"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new Uint8Array(data["data"])
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 1, 20);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_PullObjectResponse (data: Uint8Array): PullObjectResponse {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
result["found"] = view.getUint8(idx); idx += 1;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
result["data"] = fieldDataUint8;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
48
src/com/service_base.ts
Normal file
48
src/com/service_base.ts
Normal file
@ -0,0 +1,48 @@
|
||||
export type IStreamCallback<T> = (
|
||||
msg: T | undefined,
|
||||
error: Error | undefined,
|
||||
end: boolean
|
||||
) => void;
|
||||
|
||||
export interface IStream<T> {
|
||||
subscribe(callback: IStreamCallback<T>): void;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
export class Stream<T> implements IStream<T> {
|
||||
buffer: [T | undefined, Error | undefined, boolean][] = [];
|
||||
closed = false;
|
||||
subscriber: IStreamCallback<T>[] = [];
|
||||
|
||||
subscribe(cb: IStreamCallback<T>) {
|
||||
if (this.buffer.length > 0) {
|
||||
this.buffer.forEach((e) => cb(...e));
|
||||
this.buffer = [];
|
||||
}
|
||||
if (!this.closed) this.subscriber.push(cb);
|
||||
}
|
||||
|
||||
send(msg: T) {
|
||||
if (this.subscriber.length <= 0) {
|
||||
this.buffer.push([msg, undefined, false]);
|
||||
}
|
||||
|
||||
this.subscriber.forEach((s) => s(msg, undefined, false));
|
||||
}
|
||||
|
||||
error(error: Error) {
|
||||
if (this.subscriber.length <= 0) {
|
||||
this.buffer.push([undefined, error, false]);
|
||||
}
|
||||
this.subscriber.forEach((s) => s(undefined, error, false));
|
||||
}
|
||||
|
||||
close() {
|
||||
this.closed = true;
|
||||
if (this.subscriber.length <= 0) {
|
||||
this.buffer.push([undefined, undefined, true]);
|
||||
}
|
||||
this.subscriber.forEach((s) => s(undefined, undefined, true));
|
||||
this.subscriber = []; // Clear after close
|
||||
}
|
||||
}
|
83
src/com/service_client.ts
Normal file
83
src/com/service_client.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import ServiceMessage, { deserialize_ServiceMessage, serialize_ServiceMessage} from "./servicemessage";
|
||||
import { IStream, IStreamCallback, Stream } from "./service_base";
|
||||
|
||||
|
||||
|
||||
|
||||
export type { IStream, IStreamCallback };
|
||||
export { Stream };
|
||||
|
||||
interface IServiceFunction {
|
||||
istream: boolean;
|
||||
input: (data: Uint8Array) => any;
|
||||
|
||||
rstream: boolean;
|
||||
ret: (data: any) => Uint8Array;
|
||||
}
|
||||
|
||||
export type IMessageCallback = (packet: Uint8Array) => void;
|
||||
|
||||
export class Service {
|
||||
public name: string = null as any;
|
||||
protected functions = new Map<string, IServiceFunction>();
|
||||
|
||||
protected calls = new Map<string, (msg: ServiceMessage) => void>();
|
||||
|
||||
constructor(private provider: ServiceProvider, name: string) {
|
||||
this.name = name;
|
||||
this.provider.services.set(name, this);
|
||||
}
|
||||
|
||||
onMessage(msg: ServiceMessage) {
|
||||
const msgid = msg.id;
|
||||
const call = this.calls.get(msgid);
|
||||
if (call) {
|
||||
call(msg);
|
||||
}
|
||||
}
|
||||
|
||||
protected sendMessage(msg: ServiceMessage) {
|
||||
this.provider.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export class ServiceProvider {
|
||||
services = new Map<string, Service>();
|
||||
constructor(private sendPacket: IMessageCallback) {}
|
||||
|
||||
onPacket(msg: Uint8Array) {
|
||||
const decoded = deserialize_ServiceMessage(msg);
|
||||
const serv = this.services.get(decoded.service);
|
||||
if (serv) {
|
||||
serv.onMessage(decoded);
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage(msg: ServiceMessage) {
|
||||
this.sendPacket(serialize_ServiceMessage(msg));
|
||||
}
|
||||
}
|
||||
|
||||
declare var require: any;
|
||||
export const getRandomBytes = (typeof self !== "undefined" &&
|
||||
(self.crypto || (self as any).msCrypto)
|
||||
? function () {
|
||||
// Browsers
|
||||
var crypto = self.crypto || (self as any).msCrypto;
|
||||
var QUOTA = 65536;
|
||||
return function (n: number) {
|
||||
var a = new Uint8Array(n);
|
||||
for (var i = 0; i < n; i += QUOTA) {
|
||||
crypto.getRandomValues(a.subarray(i, i + Math.min(n - i, QUOTA)));
|
||||
}
|
||||
return a;
|
||||
};
|
||||
}
|
||||
: function () {
|
||||
// Node
|
||||
return require("crypto").randomBytes;
|
||||
})() as (cnt: number) => Uint8Array;
|
||||
|
||||
export const getRandomID = (length: number) => {
|
||||
return btoa(String.fromCharCode.apply(null, getRandomBytes(length) as any));
|
||||
};
|
159
src/com/service_server.ts
Normal file
159
src/com/service_server.ts
Normal file
@ -0,0 +1,159 @@
|
||||
import ServiceMessage, { deserialize_ServiceMessage, serialize_ServiceMessage} from "./servicemessage";
|
||||
import { IStream, IStreamCallback, Stream } from "./service_base";
|
||||
|
||||
|
||||
|
||||
|
||||
export type { IStream, IStreamCallback };
|
||||
export { Stream };
|
||||
|
||||
interface IServiceFunction {
|
||||
istream: boolean;
|
||||
input: (data: Uint8Array) => any;
|
||||
|
||||
rstream: boolean;
|
||||
ret: (data: any) => Uint8Array;
|
||||
}
|
||||
|
||||
export class Service<T> {
|
||||
public name: string = null as any;
|
||||
protected functions = new Map<string, IServiceFunction>();
|
||||
|
||||
constructor() {}
|
||||
|
||||
handleRequest(msg: ServiceMessage): IServiceFunction {
|
||||
const fnc = this.functions.get(msg.function);
|
||||
if (!fnc) throw new Error("Invalid function!");
|
||||
return fnc;
|
||||
}
|
||||
}
|
||||
|
||||
type ISendMessageCB = (data: Uint8Array) => void;
|
||||
|
||||
export class ServiceProvider<T = any> {
|
||||
services = new Map<string, Service<T>>();
|
||||
addService(service: Service<T>) {
|
||||
this.services.set(service.name, service);
|
||||
}
|
||||
|
||||
getSession(send: ISendMessageCB): Session<T> {
|
||||
return new Session(this, send);
|
||||
}
|
||||
}
|
||||
|
||||
class Session<T> {
|
||||
ctx: Partial<T> = {};
|
||||
|
||||
calls = new Map<
|
||||
string,
|
||||
{
|
||||
def: IServiceFunction;
|
||||
istream: Stream<any>;
|
||||
}
|
||||
>();
|
||||
constructor(
|
||||
private provider: ServiceProvider,
|
||||
private send: ISendMessageCB
|
||||
) {}
|
||||
|
||||
async close() {
|
||||
this.calls.forEach((call) => {
|
||||
call.istream.close();
|
||||
//TODO: Close rstreams or so...
|
||||
});
|
||||
}
|
||||
|
||||
async onMessage(data: Uint8Array) {
|
||||
const msg = deserialize_ServiceMessage(data);
|
||||
try {
|
||||
if (this.calls.has(msg.id)) {
|
||||
const call = this.calls.get(msg.id);
|
||||
if (!call) throw new Error("This call does not exist anymore!");
|
||||
|
||||
if (!msg.payload) {
|
||||
call.istream.close();
|
||||
} else {
|
||||
call.istream.send(call.def.input(msg.payload));
|
||||
}
|
||||
} else {
|
||||
const service = this.provider.services.get(msg.service);
|
||||
if (!service) throw new Error("Invalid Service!");
|
||||
|
||||
const functionDefinition = service.handleRequest(msg);
|
||||
let input: any;
|
||||
if (functionDefinition.istream) {
|
||||
// Input is a stream
|
||||
const istream = new Stream<any>();
|
||||
input = istream;
|
||||
this.calls.set(msg.id, {
|
||||
def: functionDefinition,
|
||||
istream,
|
||||
});
|
||||
if (msg.payload) {
|
||||
istream.send(functionDefinition.input(msg.payload));
|
||||
} else {
|
||||
istream.close();
|
||||
}
|
||||
} else {
|
||||
input = functionDefinition.input(msg.payload);
|
||||
}
|
||||
|
||||
const result: any = await (service as any)[msg.function](
|
||||
input,
|
||||
this.ctx
|
||||
);
|
||||
if (functionDefinition.rstream) {
|
||||
// Result is a stream
|
||||
(result as IStream<any>).subscribe((value, error, end) => {
|
||||
if (!end) {
|
||||
this.send(
|
||||
serialize_ServiceMessage({
|
||||
id: msg.id,
|
||||
function: msg.function,
|
||||
service: msg.service,
|
||||
payload: error
|
||||
? undefined
|
||||
: (functionDefinition.ret(value) as any),
|
||||
error: error?.message as any,
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.send(
|
||||
serialize_ServiceMessage({
|
||||
id: msg.id,
|
||||
function: msg.function,
|
||||
service: msg.service,
|
||||
payload: undefined as any,
|
||||
error: undefined as any,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.send(
|
||||
serialize_ServiceMessage({
|
||||
id: msg.id,
|
||||
function: msg.function,
|
||||
service: msg.service,
|
||||
payload: functionDefinition.ret(result),
|
||||
error: undefined as any,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
if (this.calls.has(msg.id)) {
|
||||
this.calls.get(msg.id)?.istream.close();
|
||||
}
|
||||
this.send(
|
||||
serialize_ServiceMessage({
|
||||
id: msg.id,
|
||||
function: msg.function,
|
||||
service: msg.service,
|
||||
payload: undefined as any,
|
||||
error: err.message,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
182
src/com/servicemessage.ts
Normal file
182
src/com/servicemessage.ts
Normal file
@ -0,0 +1,182 @@
|
||||
export default interface ServiceMessage {
|
||||
service: string;
|
||||
function: string;
|
||||
id: string;
|
||||
payload: Uint8Array;
|
||||
error: string;
|
||||
}
|
||||
export function serialize_ServiceMessage (data: ServiceMessage): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["service"] !== null && data["service"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["service"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 1, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["function"] !== null && data["function"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["function"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 2, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["id"] !== null && data["id"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["id"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 3, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["payload"] !== null && data["payload"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new Uint8Array(data["payload"])
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 4, 20);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["error"] !== null && data["error"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["error"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 5, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_ServiceMessage (data: Uint8Array): ServiceMessage {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 1: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["service"] = str;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["function"] = str;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["id"] = str;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
result["payload"] = fieldDataUint8;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["error"] = str;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
91
src/com/sync_client.ts
Normal file
91
src/com/sync_client.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import SyncInitRequest, { serialize_SyncInitRequest, deserialize_SyncInitRequest} from "./syncinitrequest";
|
||||
import SyncInitResponse, { serialize_SyncInitResponse, deserialize_SyncInitResponse} from "./syncinitresponse";
|
||||
import PullGetLogRequest, { serialize_PullGetLogRequest, deserialize_PullGetLogRequest} from "./pullgetlogrequest";
|
||||
import PullGetLogResponse, { serialize_PullGetLogResponse, deserialize_PullGetLogResponse} from "./pullgetlogresponse";
|
||||
import PullObjectRequest, { serialize_PullObjectRequest, deserialize_PullObjectRequest} from "./pullobjectrequest";
|
||||
import PullObjectResponse, { serialize_PullObjectResponse, deserialize_PullObjectResponse} from "./pullobjectresponse";
|
||||
import ServiceMessage, { serialize_ServiceMessage, deserialize_ServiceMessage} from "./servicemessage";
|
||||
export type {
|
||||
SyncInitRequest,
|
||||
SyncInitResponse,
|
||||
PullGetLogRequest,
|
||||
PullGetLogResponse,
|
||||
PullObjectRequest,
|
||||
PullObjectResponse,
|
||||
ServiceMessage,
|
||||
}
|
||||
import { IStream, Stream, Service, ServiceProvider, getRandomID } from "./service_client";
|
||||
export class Sync extends Service {
|
||||
constructor(provider: ServiceProvider){
|
||||
super(provider, "Sync");
|
||||
this.functions.set("SyncInit", {
|
||||
istream: false, input: deserialize_SyncInitRequest,
|
||||
rstream: false, ret: serialize_SyncInitResponse
|
||||
});
|
||||
this.functions.set("PullGetLog", {
|
||||
istream: false, input: deserialize_PullGetLogRequest,
|
||||
rstream: false, ret: serialize_PullGetLogResponse
|
||||
});
|
||||
this.functions.set("PullObject", {
|
||||
istream: false, input: deserialize_PullObjectRequest,
|
||||
rstream: false, ret: serialize_PullObjectResponse
|
||||
});
|
||||
}
|
||||
|
||||
SyncInit(data: SyncInitRequest): Promise<SyncInitResponse> {
|
||||
const msgid = getRandomID(16);
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.calls.set(msgid, (msg)=>{
|
||||
this.calls.delete(msgid);
|
||||
if(msg.error) reject(new Error(msg.error))
|
||||
else resolve(deserialize_SyncInitResponse(msg.payload))
|
||||
})
|
||||
this.sendMessage({
|
||||
service: "Sync",
|
||||
function: "SyncInit",
|
||||
id: msgid,
|
||||
payload: (serialize_SyncInitRequest(data)) as any,
|
||||
error: undefined as any
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
PullGetLog(data: PullGetLogRequest): Promise<PullGetLogResponse> {
|
||||
const msgid = getRandomID(16);
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.calls.set(msgid, (msg)=>{
|
||||
this.calls.delete(msgid);
|
||||
if(msg.error) reject(new Error(msg.error))
|
||||
else resolve(deserialize_PullGetLogResponse(msg.payload))
|
||||
})
|
||||
this.sendMessage({
|
||||
service: "Sync",
|
||||
function: "PullGetLog",
|
||||
id: msgid,
|
||||
payload: (serialize_PullGetLogRequest(data)) as any,
|
||||
error: undefined as any
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
PullObject(data: PullObjectRequest): Promise<PullObjectResponse> {
|
||||
const msgid = getRandomID(16);
|
||||
return new Promise((resolve, reject)=>{
|
||||
this.calls.set(msgid, (msg)=>{
|
||||
this.calls.delete(msgid);
|
||||
if(msg.error) reject(new Error(msg.error))
|
||||
else resolve(deserialize_PullObjectResponse(msg.payload))
|
||||
})
|
||||
this.sendMessage({
|
||||
service: "Sync",
|
||||
function: "PullObject",
|
||||
id: msgid,
|
||||
payload: (serialize_PullObjectRequest(data)) as any,
|
||||
error: undefined as any
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
}
|
41
src/com/sync_server.ts
Normal file
41
src/com/sync_server.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import SyncInitRequest, { serialize_SyncInitRequest, deserialize_SyncInitRequest} from "./syncinitrequest";
|
||||
import SyncInitResponse, { serialize_SyncInitResponse, deserialize_SyncInitResponse} from "./syncinitresponse";
|
||||
import PullGetLogRequest, { serialize_PullGetLogRequest, deserialize_PullGetLogRequest} from "./pullgetlogrequest";
|
||||
import PullGetLogResponse, { serialize_PullGetLogResponse, deserialize_PullGetLogResponse} from "./pullgetlogresponse";
|
||||
import PullObjectRequest, { serialize_PullObjectRequest, deserialize_PullObjectRequest} from "./pullobjectrequest";
|
||||
import PullObjectResponse, { serialize_PullObjectResponse, deserialize_PullObjectResponse} from "./pullobjectresponse";
|
||||
import ServiceMessage, { serialize_ServiceMessage, deserialize_ServiceMessage} from "./servicemessage";
|
||||
export type {
|
||||
SyncInitRequest,
|
||||
SyncInitResponse,
|
||||
PullGetLogRequest,
|
||||
PullGetLogResponse,
|
||||
PullObjectRequest,
|
||||
PullObjectResponse,
|
||||
ServiceMessage,
|
||||
}
|
||||
import { IStream, Service } from "./service_server";
|
||||
export abstract class Sync<T> extends Service<T> {
|
||||
public name = "Sync";
|
||||
constructor(){
|
||||
super();
|
||||
this.functions.set("SyncInit", {
|
||||
istream: false, input: deserialize_SyncInitRequest,
|
||||
rstream: false, ret: serialize_SyncInitResponse
|
||||
});
|
||||
this.functions.set("PullGetLog", {
|
||||
istream: false, input: deserialize_PullGetLogRequest,
|
||||
rstream: false, ret: serialize_PullGetLogResponse
|
||||
});
|
||||
this.functions.set("PullObject", {
|
||||
istream: false, input: deserialize_PullObjectRequest,
|
||||
rstream: false, ret: serialize_PullObjectResponse
|
||||
});
|
||||
}
|
||||
|
||||
abstract SyncInit(data: SyncInitRequest, ctx: T): Promise<SyncInitResponse>;
|
||||
|
||||
abstract PullGetLog(data: PullGetLogRequest, ctx: T): Promise<PullGetLogResponse>;
|
||||
|
||||
abstract PullObject(data: PullObjectRequest, ctx: T): Promise<PullObjectResponse>;
|
||||
}
|
115
src/com/syncinitrequest.ts
Normal file
115
src/com/syncinitrequest.ts
Normal file
@ -0,0 +1,115 @@
|
||||
export default interface SyncInitRequest {
|
||||
clientCommit: string;
|
||||
}
|
||||
export function serialize_SyncInitRequest (data: SyncInitRequest): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["clientCommit"] !== null && data["clientCommit"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["clientCommit"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 0, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_SyncInitRequest (data: Uint8Array): SyncInitRequest {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["clientCommit"] = str;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
137
src/com/syncinitresponse.ts
Normal file
137
src/com/syncinitresponse.ts
Normal file
@ -0,0 +1,137 @@
|
||||
export default interface SyncInitResponse {
|
||||
remoteCommit: string;
|
||||
needPull: boolean;
|
||||
needPush: boolean;
|
||||
}
|
||||
export function serialize_SyncInitResponse (data: SyncInitResponse): Uint8Array {
|
||||
let fields: ArrayBuffer[] = [];
|
||||
const addBuffer = (buffer:ArrayBuffer) => fields.push(buffer);
|
||||
const makeField = (payload_length: number, label: number, type: number) => {
|
||||
let b = new ArrayBuffer(3 + payload_length);
|
||||
new DataView(b).setUint16(0, label);
|
||||
new DataView(b).setUint8(2, type);
|
||||
fields.push(b);
|
||||
return new DataView(b, 3);
|
||||
}
|
||||
|
||||
const makeArrayBuffer = (payload_length: number) => {
|
||||
let b = new ArrayBuffer(payload_length);
|
||||
fields.push(b)
|
||||
return new DataView(b)
|
||||
}
|
||||
|
||||
const getAutoGrowLength = (length: number | bigint) => {
|
||||
if (typeof length === "number") length = BigInt(length);
|
||||
const lt1 = length >= BigInt(Math.pow(2, 15)) ? 0x8000 : 0;
|
||||
const lt2 = length >= BigInt(Math.pow(2, 30)) ? 0x8000 : 0;
|
||||
const lt3 = length >= BigInt(Math.pow(2, 45)) ? 0x8000 : 0;
|
||||
const lt4 = length >= BigInt(Math.pow(2, 61));
|
||||
if (lt4) throw new Error("Payload to large!");
|
||||
let blen = BigInt(length);
|
||||
const u16_1 = (Number(blen >> BigInt(0)) & 0x7fff) | lt1;
|
||||
const u16_2 = (Number(blen >> BigInt(15)) & 0x7fff) | lt2;
|
||||
const u16_3 = (Number(blen >> BigInt(30)) & 0x7fff) | lt3;
|
||||
const u16_4 = Number(blen >> BigInt(45)) & 0xffff;
|
||||
const ld: number[] = [u16_1];
|
||||
if (lt1 != 0) ld.push(u16_2);
|
||||
if (lt2 != 0) ld.push(u16_3);
|
||||
if (lt3 != 0) ld.push(u16_4);
|
||||
const dv = new DataView(new ArrayBuffer(ld.length * 2))
|
||||
for(let i = 0; i < ld.length; i++) {
|
||||
dv.setUint16(i * 2, ld[i])
|
||||
}
|
||||
return dv.buffer;
|
||||
}
|
||||
|
||||
let nrOfFields = 0;
|
||||
if(data["remoteCommit"] !== null && data["remoteCommit"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const str = new TextEncoder().encode(data["remoteCommit"]);
|
||||
const lengthBytes = getAutoGrowLength(str.byteLength);
|
||||
const f = makeField(str.byteLength + lengthBytes.byteLength, 0, 21);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(new Uint8Array(lengthBytes), 0);
|
||||
new Uint8Array(f.buffer, f.byteOffset).set(str, lengthBytes.byteLength);
|
||||
}
|
||||
|
||||
if(data["needPull"] !== null && data["needPull"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const f = makeField(1, 1, 5);
|
||||
f.setUint8(0, Number(data["needPull"]));
|
||||
}
|
||||
|
||||
if(data["needPush"] !== null && data["needPush"] !== undefined ) {
|
||||
nrOfFields++;
|
||||
const f = makeField(1, 2, 5);
|
||||
f.setUint8(0, Number(data["needPush"]));
|
||||
}
|
||||
|
||||
|
||||
const fieldsLength = fields.reduce((a, b) => b.byteLength + a, 0);
|
||||
|
||||
|
||||
const result = new ArrayBuffer(fieldsLength + 2);
|
||||
const resultC = new Uint8Array(result);
|
||||
new DataView(result).setUint16(0, nrOfFields);
|
||||
|
||||
let offset = 2;
|
||||
for (const buf of fields) {
|
||||
resultC.set(new Uint8Array(buf), offset);
|
||||
offset += buf.byteLength;
|
||||
}
|
||||
|
||||
return new Uint8Array(result);
|
||||
}
|
||||
|
||||
export function deserialize_SyncInitResponse (data: Uint8Array): SyncInitResponse {
|
||||
const view = new DataView(data.buffer, data.byteOffset)
|
||||
let idx = 0;
|
||||
const readAutoGrowLength = () => {
|
||||
let result = BigInt(0);
|
||||
const v1 = view.getUint16(idx); idx += 2;
|
||||
const u16_1 = v1 & 0x7fff;
|
||||
result = result | (BigInt(u16_1) << BigInt(0));
|
||||
if ((v1 & 0x8000) > 0) {
|
||||
const v2 = view.getUint16(idx); idx += 2;
|
||||
const u16_2 = v2 & 0x7fff;
|
||||
result = result | (BigInt(u16_2) << BigInt(15));
|
||||
if ((v2 & 0x8000) > 0) {
|
||||
const v3 = view.getUint16(idx); idx += 2;
|
||||
const u16_3 = v3 & 0x7fff;
|
||||
result = result | (BigInt(u16_3) << BigInt(30));
|
||||
if ((v3 & 0x8000) > 0) {
|
||||
const v4 = view.getUint16(idx); idx += 2;
|
||||
const u16_4 = v4;
|
||||
result = result | (BigInt(u16_4) << BigInt(45));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Number(result);
|
||||
}
|
||||
let result: any = {}
|
||||
const nrOfFields = view.getUint16(idx); idx += 2;
|
||||
for(let i = 0; i < nrOfFields; i++) {
|
||||
const fieldLabel = view.getUint16(idx); idx += 2;
|
||||
const fieldType = view.getUint8(idx); idx += 1;
|
||||
switch(fieldLabel) {
|
||||
case 0: {
|
||||
const fieldDataLength = readAutoGrowLength()
|
||||
const fieldDataUint8 = data.slice(idx, idx + fieldDataLength); idx += fieldDataLength;
|
||||
const str = new TextDecoder().decode(fieldDataUint8);
|
||||
result["remoteCommit"] = str;
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
result["needPull"] = view.getUint8(idx); idx += 1;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
result["needPush"] = view.getUint8(idx); idx += 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error("Invalid label found: " + fieldLabel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
Reference in New Issue
Block a user