mirror of
https://github.com/dolthub/dolt.git
synced 2026-01-31 12:19:08 -06:00
(js2) Add HttpStore & more decode/encode support
This commit is contained in:
2
js2/link.sh
Executable file
2
js2/link.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
# nothing to link
|
||||
npm link
|
||||
@@ -4,7 +4,8 @@
|
||||
"dependencies": {
|
||||
"rusha": "^0.8.3",
|
||||
"flow-bin": "^0.18.1",
|
||||
"text-encoding": "^0.5.2"
|
||||
"text-encoding": "^0.5.2",
|
||||
"isomorphic-fetch": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "^5.6.23",
|
||||
|
||||
@@ -11,15 +11,14 @@ const chunkHeaderSize = sha1Size + chunkLengthSize;
|
||||
|
||||
export function serialize(chunks: Array<Chunk>): ArrayBuffer {
|
||||
let totalSize = 0;
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
totalSize += chunkHeaderSize + chunks[i].data.length;
|
||||
for (let chunk of chunks) {
|
||||
totalSize += chunkHeaderSize + chunk.data.length;
|
||||
}
|
||||
|
||||
let buffer = new ArrayBuffer(totalSize);
|
||||
let offset = 0;
|
||||
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
let chunk = chunks[i];
|
||||
for (let chunk of chunks) {
|
||||
let refArray = new Uint8Array(buffer, offset, sha1Size);
|
||||
refArray.set(chunk.ref.digest);
|
||||
offset += sha1Size;
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
'use strict';
|
||||
|
||||
import Chunk from './chunk.js';
|
||||
import MemoryStore from './memory_store.js';
|
||||
import Ref from './ref.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {lookupPackage, Package} from './package.js';
|
||||
import {makeCompoundTypeRef, makePrimitiveTypeRef, makeTypeRef, StructDesc, TypeRef} from './type_ref.js';
|
||||
import {lookupPackage, Package, readPackage} from './package.js';
|
||||
import {Field, makeCompoundTypeRef, makePrimitiveTypeRef, makeStructTypeRef, makeTypeRef, makeUnresolvedTypeRef, StructDesc, TypeRef} from './type_ref.js';
|
||||
|
||||
const typedTag = 't ';
|
||||
|
||||
@@ -113,46 +112,62 @@ class JsonArrayReader {
|
||||
throw new Error('Unreachable');
|
||||
}
|
||||
|
||||
readList(t: TypeRef, pkg: ?Package): Array<any> {
|
||||
async readList(t: TypeRef, pkg: ?Package): Promise<Array<any>> {
|
||||
let elemType = t.elemTypes[0];
|
||||
let list = [];
|
||||
while (!this.atEnd()) {
|
||||
let v = this.readValueWithoutTag(elemType, pkg);
|
||||
list.push(v);
|
||||
}
|
||||
return list;
|
||||
|
||||
return Promise.all(list);
|
||||
}
|
||||
|
||||
readSet(t: TypeRef, pkg: ?Package): Set {
|
||||
let elemType = t.elemTypes[0];
|
||||
let s = new Set();
|
||||
while (!this.atEnd()) {
|
||||
let v = this.readValueWithoutTag(elemType, pkg);
|
||||
s.add(v);
|
||||
}
|
||||
|
||||
return s;
|
||||
async readSet(t: TypeRef, pkg: ?Package): Promise<Set> {
|
||||
let seq = await this.readList(t, pkg);
|
||||
return new Set(seq);
|
||||
}
|
||||
|
||||
readMap(t: TypeRef, pkg: ?Package): Map {
|
||||
async readMap(t: TypeRef, pkg: ?Package): Promise<Map> {
|
||||
let keyType = t.elemTypes[0];
|
||||
let valueType = t.elemTypes[1];
|
||||
let m = new Map();
|
||||
let kv = [];
|
||||
while (!this.atEnd()) {
|
||||
let k = this.readValueWithoutTag(keyType, pkg);
|
||||
let v = this.readValueWithoutTag(valueType, pkg);
|
||||
m.set(k, v);
|
||||
kv.push(this.readValueWithoutTag(keyType, pkg));
|
||||
kv.push(this.readValueWithoutTag(valueType, pkg));
|
||||
}
|
||||
|
||||
kv = await Promise.all(kv);
|
||||
let m = new Map();
|
||||
for (let i = 0; i < kv.length; i += 2) {
|
||||
m.set(kv[i], kv[i + 1]);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
readTopLevelValue(): any {
|
||||
readPackage(t: TypeRef, pkg: ?Package): Package {
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
let types = [];
|
||||
while (!r2.atEnd()) {
|
||||
types.push(r2.readTypeRefAsValue(pkg));
|
||||
}
|
||||
|
||||
let r3 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
let deps = [];
|
||||
while (!r3.atEnd()) {
|
||||
deps.push(r3.readRef());
|
||||
}
|
||||
|
||||
return new Package(types, deps);
|
||||
}
|
||||
|
||||
async readTopLevelValue(): Promise<any> {
|
||||
let t = this.readTypeRefAsTag();
|
||||
return this.readValueWithoutTag(t);
|
||||
}
|
||||
|
||||
readValueWithoutTag(t: TypeRef, pkg: ?Package = null): any {
|
||||
async readValueWithoutTag(t: TypeRef, pkg: ?Package = null): Promise<any> {
|
||||
// TODO: Verify read values match tagged kinds.
|
||||
switch (t.kind) {
|
||||
case Kind.Blob:
|
||||
@@ -185,9 +200,9 @@ class JsonArrayReader {
|
||||
return r2.readMap(t, pkg);
|
||||
}
|
||||
case Kind.Package:
|
||||
throw new Error('Not implemented');
|
||||
return this.readPackage(t, pkg);
|
||||
case Kind.Ref:
|
||||
throw new Error('Not implemented');
|
||||
return this.readRef();
|
||||
case Kind.Set: {
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
return r2.readSet(t, pkg);
|
||||
@@ -196,6 +211,7 @@ class JsonArrayReader {
|
||||
case Kind.Struct:
|
||||
throw new Error('Not allowed');
|
||||
case Kind.TypeRef:
|
||||
return this.readTypeRefAsValue(pkg);
|
||||
case Kind.Unresolved:
|
||||
return this.readUnresolvedKindToValue(t, pkg);
|
||||
}
|
||||
@@ -203,13 +219,13 @@ class JsonArrayReader {
|
||||
throw new Error('Unreached');
|
||||
}
|
||||
|
||||
readUnresolvedKindToValue(t: TypeRef, pkg: ?Package = null): any {
|
||||
async readUnresolvedKindToValue(t: TypeRef, pkg: ?Package = null): Promise<any> {
|
||||
let pkgRef = t.packageRef;
|
||||
let ordinal = t.ordinal;
|
||||
if (!pkgRef.isEmpty()) {
|
||||
let pkg2 = lookupPackage(pkgRef);
|
||||
if (!pkg2) {
|
||||
throw new Error('Not implemented');
|
||||
pkg = await readPackage(pkgRef, this._cs);
|
||||
} else {
|
||||
pkg = pkg2;
|
||||
}
|
||||
@@ -231,23 +247,83 @@ class JsonArrayReader {
|
||||
}
|
||||
}
|
||||
|
||||
readStruct(typeDef: TypeRef, typeRef: TypeRef, pkg: Package): any {
|
||||
readTypeRefAsValue(pkg: ?Package): TypeRef {
|
||||
let k = this.readKind();
|
||||
|
||||
switch (k) {
|
||||
case Kind.Enum:
|
||||
throw new Error('Not implemented');
|
||||
case Kind.List:
|
||||
case Kind.Map:
|
||||
case Kind.Ref:
|
||||
case Kind.Set: {
|
||||
let r2 = new JsonArrayReader(this.readArray(), this._cs);
|
||||
let elemTypes: Array<TypeRef> = [];
|
||||
while (!r2.atEnd()) {
|
||||
elemTypes.push(r2.readTypeRefAsValue());
|
||||
}
|
||||
|
||||
return makeCompoundTypeRef(k, ...elemTypes);
|
||||
}
|
||||
case Kind.Struct: {
|
||||
let name = this.readString();
|
||||
let readFields = () => {
|
||||
let fields: Array<Field> = [];
|
||||
let fieldReader = new JsonArrayReader(this.readArray(), this._cs);
|
||||
while (!fieldReader.atEnd()) {
|
||||
let fieldName = fieldReader.readString();
|
||||
let fieldType = fieldReader.readTypeRefAsValue(pkg);
|
||||
let optional = fieldReader.readBool();
|
||||
fields.push(new Field(fieldName, fieldType, optional));
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
|
||||
let fields = readFields();
|
||||
let choices = readFields();
|
||||
return makeStructTypeRef(name, fields, choices);
|
||||
}
|
||||
case Kind.Unresolved: {
|
||||
let pkgRef = this.readRef();
|
||||
let ordinal = this.readOrdinal();
|
||||
if (ordinal === -1) {
|
||||
let namespace = this.readString();
|
||||
let name = this.readString();
|
||||
if (!pkgRef.isEmpty()) {
|
||||
throw new Error('Unresolved TypeRefs may not have a package ref');
|
||||
}
|
||||
|
||||
return makeUnresolvedTypeRef(namespace, name);
|
||||
}
|
||||
|
||||
return makeTypeRef(pkgRef, ordinal);
|
||||
}
|
||||
default: {
|
||||
if (!isPrimitiveKind(k)) {
|
||||
throw new Error('Not implemented: ' + k);
|
||||
}
|
||||
return makePrimitiveTypeRef(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async readStruct(typeDef: TypeRef, typeRef: TypeRef, pkg: Package): Promise<any> {
|
||||
// TODO FixupTypeRef?
|
||||
// TODO Make read of sub-values parallel.
|
||||
let desc = typeDef.desc;
|
||||
if (desc instanceof StructDesc) {
|
||||
let s = Object.create(null);
|
||||
|
||||
for (let i = 0; i < desc.fields.length; i++) {
|
||||
let field = desc.fields[i];
|
||||
let s: { [key: string]: any } = Object.create(null);
|
||||
s._typeRef = typeDef; // TODO: Need a better way to add typeRef
|
||||
|
||||
for (let field of desc.fields) {
|
||||
if (field.optional) {
|
||||
let b = this.readBool();
|
||||
if (b) {
|
||||
let v = this.readValueWithoutTag(field.t, pkg);
|
||||
let v = await this.readValueWithoutTag(field.t, pkg);
|
||||
s[field.name] = v;
|
||||
}
|
||||
} else {
|
||||
let v = this.readValueWithoutTag(field.t, pkg);
|
||||
let v = await this.readValueWithoutTag(field.t, pkg);
|
||||
s[field.name] = v;
|
||||
}
|
||||
}
|
||||
@@ -263,14 +339,13 @@ class JsonArrayReader {
|
||||
}
|
||||
}
|
||||
|
||||
function decodeNomsValue(chunk: Chunk): any {
|
||||
function decodeNomsValue(chunk: Chunk, cs: ChunkStore): Promise<any> {
|
||||
let tag = new Chunk(new Uint8Array(chunk.data.buffer, 0, 2)).toString();
|
||||
|
||||
switch (tag) {
|
||||
case typedTag: {
|
||||
let ms = new MemoryStore(); // This needs to be handed in.
|
||||
let payload = JSON.parse(new Chunk(new Uint8Array(chunk.data.buffer, 2)).toString());
|
||||
let reader = new JsonArrayReader(payload, ms);
|
||||
let reader = new JsonArrayReader(payload, cs);
|
||||
return reader.readTopLevelValue();
|
||||
}
|
||||
default:
|
||||
@@ -278,4 +353,13 @@ function decodeNomsValue(chunk: Chunk): any {
|
||||
}
|
||||
}
|
||||
|
||||
export {decodeNomsValue, JsonArrayReader};
|
||||
export async function readValue(r: Ref, cs: ChunkStore): Promise<any> {
|
||||
let chunk = await cs.get(r);
|
||||
if (chunk.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return decodeNomsValue(chunk, cs);
|
||||
}
|
||||
|
||||
export {decodeNomsValue, JsonArrayReader, readValue};
|
||||
|
||||
@@ -7,7 +7,7 @@ import MemoryStore from './memory_store.js';
|
||||
import Ref from './ref.js';
|
||||
import test from './async_test.js';
|
||||
import {assert} from 'chai';
|
||||
import {decodeNomsValue, JsonArrayReader} from './decode.js';
|
||||
import {decodeNomsValue, JsonArrayReader, readValue} from './decode.js';
|
||||
import {Field, makeCompoundTypeRef, makePrimitiveTypeRef, makeStructTypeRef, makeTypeRef, TypeRef} from './type_ref.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {registerPackage, Package} from './package.js';
|
||||
@@ -51,9 +51,9 @@ suite('Decode', () => {
|
||||
test('read primitives', async () => {
|
||||
let ms = new MemoryStore();
|
||||
|
||||
function doTest(expected: any, a: Array<any>) {
|
||||
async function doTest(expected: any, a: Array<any>): Promise<void> {
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
assert.strictEqual(expected, v);
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.List, Kind.Int32, [0, 1, 2, 3]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
assert.deepEqual([0, 1, 2, 3], v);
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.List, Kind.Value, [Kind.Int32, 1, Kind.String, 'hi', Kind.Bool, true]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
assert.deepEqual([1, 'hi', true], v);
|
||||
});
|
||||
|
||||
@@ -95,7 +95,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Value, Kind.List, Kind.Int8, [0, 1, 2]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
assert.deepEqual([0, 1, 2], v);
|
||||
});
|
||||
|
||||
@@ -111,7 +111,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Map, Kind.Int64, Kind.Float64, [0, 1, 2, 3]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
|
||||
let m = new Map();
|
||||
m.set(0, 1);
|
||||
@@ -124,7 +124,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Value, Kind.Map, Kind.UInt64, Kind.UInt32, [0, 1, 2, 3]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
|
||||
let m = new Map();
|
||||
m.set(0, 1);
|
||||
@@ -144,7 +144,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Set, Kind.UInt8, [0, 1, 2, 3]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
|
||||
let s = new Set();
|
||||
s.add(0);
|
||||
@@ -159,7 +159,7 @@ suite('Decode', () => {
|
||||
let ms = new MemoryStore();
|
||||
let a = [Kind.Value, Kind.Set, Kind.UInt16, [0, 1, 2, 3]];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
let v = await r.readTopLevelValue();
|
||||
|
||||
let s = new Set([0, 1, 2, 3]);
|
||||
assertSetsEqual(s, v);
|
||||
@@ -178,14 +178,27 @@ suite('Decode', () => {
|
||||
|
||||
let a = [Kind.Unresolved, pkg.ref.toString(), 0, 42, 'hi', true];
|
||||
let r = new JsonArrayReader(a, ms);
|
||||
let v = r.readTopLevelValue();
|
||||
assert.deepEqual({x: 42, s: 'hi', b: true}, v);
|
||||
let v = await r.readTopLevelValue();
|
||||
assert.deepEqual({x: 42, s: 'hi', b: true, _typeRef: tr}, v);
|
||||
});
|
||||
|
||||
test('decodeNomsValue', async () => {
|
||||
let chunk = Chunk.fromString(`t [${Kind.Value}, ${Kind.Set}, ${Kind.UInt16}, [0, 1, 2, 3]]`);
|
||||
let v = decodeNomsValue(chunk);
|
||||
let v = await decodeNomsValue(chunk, new MemoryStore());
|
||||
let s = new Set([0, 1, 2, 3]);
|
||||
assertSetsEqual(s, v);
|
||||
});
|
||||
|
||||
test('decodeNomsValue: counter with one commit', async () => {
|
||||
let ms = new MemoryStore();
|
||||
let root = Ref.parse('sha1-a53578b3f9f39646df642f010fc9924aec0b4b2f');
|
||||
ms.put(Chunk.fromString('t [15,11,16,21,"sha1-7546d804d845125bc42669c7a4c3f3fb909eca29",0,["counter","sha1-d796f8295b4ffa0a0711bfb844f07827012923d3"]]')); // root
|
||||
ms.put(Chunk.fromString('t [22,[19,"Commit",["value",13,false,"parents",17,[16,[21,"sha1-0000000000000000000000000000000000000000",0]],false],[]],[]]')); // datas package
|
||||
ms.put(Chunk.fromString('t [21,"sha1-7546d804d845125bc42669c7a4c3f3fb909eca29",0,4,1,[]]')); // commit
|
||||
|
||||
let rootMap = await readValue(root, ms);
|
||||
let counterRef = rootMap.get('counter');
|
||||
let commit = await readValue(counterRef, ms);
|
||||
assert.strictEqual(commit.value, 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {ChunkStore} from './chunk_store.js';
|
||||
import type {NomsKind} from './noms_kind.js';
|
||||
import {isPrimitiveKind, Kind} from './noms_kind.js';
|
||||
import {makePrimitiveTypeRef, StructDesc, TypeRef} from './type_ref.js';
|
||||
import {Package} from './package.js';
|
||||
import {lookupPackage, Package} from './package.js';
|
||||
|
||||
const typedTag = 't ';
|
||||
|
||||
@@ -45,10 +45,7 @@ class JsonArrayWriter {
|
||||
case Kind.Map:
|
||||
case Kind.Ref:
|
||||
case Kind.Set: {
|
||||
let elemTypes = t.elemTypes;
|
||||
for (let i = 0; i < elemTypes.length; i++) {
|
||||
this.writeTypeRefAsTag(elemTypes[i]);
|
||||
}
|
||||
t.elemTypes.forEach(elemType => this.writeTypeRefAsTag(elemType));
|
||||
break;
|
||||
}
|
||||
case Kind.Unresolved:
|
||||
@@ -83,9 +80,7 @@ class JsonArrayWriter {
|
||||
if (v instanceof Array) {
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
let elemType = t.elemTypes[0];
|
||||
for (let i = 0; i < v.length; i++) {
|
||||
w2.writeValue(v[i], elemType);
|
||||
}
|
||||
v.forEach(sv => w2.writeValue(sv, elemType));
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-list as list');
|
||||
@@ -103,10 +98,10 @@ class JsonArrayWriter {
|
||||
elems.push(k);
|
||||
});
|
||||
elems = orderValuesByRef(keyType, elems);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
w2.writeValue(elems[i], keyType);
|
||||
w2.writeValue(v.get(elems[i]), valueType);
|
||||
}
|
||||
elems.forEach(elem => {
|
||||
w2.writeValue(elem, keyType);
|
||||
w2.writeValue(v.get(elem), valueType);
|
||||
});
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-map as maps');
|
||||
@@ -118,14 +113,10 @@ class JsonArrayWriter {
|
||||
if (v instanceof Package) {
|
||||
let ptr = makePrimitiveTypeRef(Kind.TypeRef);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < v.types.length; i++) {
|
||||
w2.writeValue(v.types[i], ptr);
|
||||
}
|
||||
v.types.forEach(type => w2.writeValue(type, ptr));
|
||||
this.write(w2.array);
|
||||
let w3 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < v.dependencies.length; i++) {
|
||||
w3.writeRef(v.dependencies[i]);
|
||||
}
|
||||
v.dependencies.forEach(ref => w3.writeRef(ref));
|
||||
this.write(w3.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-package as package');
|
||||
@@ -142,9 +133,7 @@ class JsonArrayWriter {
|
||||
elems.push(v);
|
||||
});
|
||||
elems = orderValuesByRef(elemType, elems);
|
||||
for (let i = 0; i < elems.length; i++) {
|
||||
w2.writeValue(elems[i], elemType);
|
||||
}
|
||||
elems.forEach(elem => w2.writeValue(elem, elemType));
|
||||
this.write(w2.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-set as set');
|
||||
@@ -176,9 +165,7 @@ class JsonArrayWriter {
|
||||
case Kind.Set: {
|
||||
this.write(t.name);
|
||||
let w2 = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; t.elemTypes.length; i++) {
|
||||
w2.writeTypeRefAsValue(t.elemTypes[i]);
|
||||
}
|
||||
t.elemTypes.forEach(elem => w2.writeTypeRefAsValue(elem));
|
||||
this.write(w2.array);
|
||||
break;
|
||||
}
|
||||
@@ -187,20 +174,18 @@ class JsonArrayWriter {
|
||||
if (desc instanceof StructDesc) {
|
||||
this.write(t.name);
|
||||
let fieldWriter = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < desc.fields.length; i++) {
|
||||
let field = desc.fields[i];
|
||||
desc.fields.forEach(field => {
|
||||
fieldWriter.write(field.name);
|
||||
fieldWriter.writeTypeRefAsValue(field.t);
|
||||
fieldWriter.write(field.optional);
|
||||
}
|
||||
});
|
||||
this.write(fieldWriter.array);
|
||||
let choiceWriter = new JsonArrayWriter(this._cs);
|
||||
for (let i = 0; i < desc.union.length; i++) {
|
||||
let choice = desc.union[i];
|
||||
desc.union.forEach(choice => {
|
||||
choiceWriter.write(choice.name);
|
||||
choiceWriter.writeTypeRefAsValue(choice.t);
|
||||
choiceWriter.write(choice.optional);
|
||||
}
|
||||
});
|
||||
this.write(choiceWriter.array);
|
||||
} else {
|
||||
throw new Error('Attempt to serialize non-struct typeref as struct type-ref');
|
||||
@@ -208,8 +193,23 @@ class JsonArrayWriter {
|
||||
|
||||
break;
|
||||
}
|
||||
case Kind.Unresolved:
|
||||
throw new Error('Not implemented');
|
||||
case Kind.Unresolved: {
|
||||
let pkgRef = t.packageRef;
|
||||
this.writeRef(pkgRef);
|
||||
let ordinal = t.ordinal;
|
||||
this.write(ordinal);
|
||||
if (ordinal === -1) {
|
||||
this.write(t.namespace);
|
||||
this.write(t.name);
|
||||
}
|
||||
|
||||
let pkg = lookupPackage(pkgRef);
|
||||
if (pkg) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (!isPrimitiveKind(k)) {
|
||||
throw new Error('Not implemented.');
|
||||
|
||||
136
js2/src/http_store.js
Normal file
136
js2/src/http_store.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/* @flow */
|
||||
|
||||
'use strict';
|
||||
|
||||
import Chunk from './chunk.js';
|
||||
import fetch from 'isomorphic-fetch';
|
||||
import Ref from './ref.js';
|
||||
import {deserialize} from './chunk_serializer.js';
|
||||
|
||||
type ReadRequest = {
|
||||
resolve: (c: Chunk) => void,
|
||||
reject: (e: Error) => void
|
||||
};
|
||||
|
||||
function blobToBuffer(blob: Blob): Promise<ArrayBuffer> {
|
||||
return new Promise((resolve) => {
|
||||
let reader = new FileReader();
|
||||
reader.addEventListener('loadend', () => {
|
||||
resolve(reader.result);
|
||||
});
|
||||
reader.readAsArrayBuffer(blob);
|
||||
});
|
||||
}
|
||||
|
||||
export default class HttpStore {
|
||||
_rpc: {
|
||||
getRefs: string,
|
||||
ref: string,
|
||||
root: string
|
||||
};
|
||||
_readQueue: { [key: string]: Array<ReadRequest> };
|
||||
_anyPending: boolean;
|
||||
_fetchScheduled: boolean;
|
||||
_activeReads: number;
|
||||
_maxReads: number;
|
||||
|
||||
constructor(url: string, maxReads: number = 3) {
|
||||
this._rpc = {
|
||||
getRefs: url + '/getRefs/',
|
||||
ref: url + '/ref',
|
||||
root: url + '/root'
|
||||
};
|
||||
this._readQueue = Object.create(null);
|
||||
this._anyPending = false;
|
||||
this._fetchScheduled = false;
|
||||
this._activeReads = 0;
|
||||
this._maxReads = maxReads;
|
||||
}
|
||||
|
||||
async getRoot(): Promise<Ref> {
|
||||
let r = await fetch(this._rpc.root);
|
||||
let refStr = await r.text();
|
||||
return Ref.parse(refStr);
|
||||
}
|
||||
|
||||
async get(ref: Ref): Promise<Chunk> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let refStr = ref.toString();
|
||||
|
||||
if (!this._readQueue[refStr]) {
|
||||
this._readQueue[refStr] = [];
|
||||
}
|
||||
|
||||
this._readQueue[refStr].push({resolve, reject});
|
||||
this._anyPending = true;
|
||||
this._pumpFetchQueue();
|
||||
});
|
||||
}
|
||||
|
||||
_pumpFetchQueue() {
|
||||
if (!this._fetchScheduled && this._anyPending && this._activeReads < this._maxReads) {
|
||||
this._fetchScheduled = true;
|
||||
setTimeout(() => {
|
||||
this._beginFetch();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
async _beginFetch(): Promise<void> {
|
||||
this._activeReads++;
|
||||
let reqs = this._readQueue;
|
||||
this._readQueue = Object.create(null);
|
||||
this._anyPending = false;
|
||||
this._fetchScheduled = false;
|
||||
let refStrs = Object.keys(reqs);
|
||||
let body = refStrs.map(r => 'ref=' + r).join('&');
|
||||
|
||||
try {
|
||||
let response = await fetch(this._rpc.getRefs, {
|
||||
method: 'post',
|
||||
body: body,
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
});
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error('Buffered read failed: ' + response.status);
|
||||
}
|
||||
|
||||
let blob = await response.blob();
|
||||
let buffer = await blobToBuffer(blob);
|
||||
let chunks = deserialize(buffer);
|
||||
|
||||
// Return success
|
||||
chunks.forEach(chunk => {
|
||||
let refStr = chunk.ref.toString();
|
||||
let callers = reqs[refStr];
|
||||
delete reqs[refStr];
|
||||
callers.forEach(caller => {
|
||||
caller.resolve(chunk);
|
||||
});
|
||||
});
|
||||
|
||||
// Report failure
|
||||
Object.keys(reqs).forEach(r => {
|
||||
let callers = reqs[r];
|
||||
callers.forEach(c => {
|
||||
c.reject(new Chunk());
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
// TODO: This is fatal.
|
||||
throw err;
|
||||
} finally {
|
||||
this._endFetch();
|
||||
}
|
||||
}
|
||||
|
||||
_endFetch() {
|
||||
this._activeReads--;
|
||||
this._pumpFetchQueue();
|
||||
}
|
||||
|
||||
close() {}
|
||||
}
|
||||
@@ -3,16 +3,18 @@
|
||||
'use strict';
|
||||
|
||||
import Chunk from './chunk.js';
|
||||
import HttpStore from './http_store.js';
|
||||
import MemoryStore from './memory_store.js';
|
||||
import Ref from './ref.js';
|
||||
import {decodeNomsValue} from './decode.js';
|
||||
import {readValue} from './decode.js';
|
||||
import {encodeNomsValue} from './encode.js';
|
||||
import {TypeRef} from './type_ref.js';
|
||||
|
||||
export {
|
||||
Chunk,
|
||||
decodeNomsValue,
|
||||
readValue,
|
||||
encodeNomsValue,
|
||||
HttpStore,
|
||||
MemoryStore,
|
||||
Ref,
|
||||
TypeRef
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import {readValue} from './decode.js';
|
||||
import Ref from './ref.js';
|
||||
import type {ChunkStore} from './chunk_store.js';
|
||||
import {encodeNomsValue} from './encode.js';
|
||||
import {Kind} from './noms_kind.js';
|
||||
import {makePrimitiveTypeRef, TypeRef} from './type_ref.js';
|
||||
import {encodeNomsValue} from './encode.js';
|
||||
|
||||
const packageTypeRef = makePrimitiveTypeRef(Kind.Package);
|
||||
|
||||
@@ -42,4 +44,14 @@ function registerPackage(p: Package) {
|
||||
packageRegistry[p.ref.toString()] = p;
|
||||
}
|
||||
|
||||
export {lookupPackage, Package, registerPackage};
|
||||
async function readPackage(r: Ref, cs: ChunkStore): Promise<Package> {
|
||||
let p = await readValue(r, cs);
|
||||
if (p instanceof Package) {
|
||||
registerPackage(p);
|
||||
return p;
|
||||
} else {
|
||||
throw new Error('Non-package found where package expected.');
|
||||
}
|
||||
}
|
||||
|
||||
export {lookupPackage, Package, readPackage, registerPackage};
|
||||
|
||||
@@ -255,4 +255,18 @@ function makeTypeRef(pkgRef: Ref, ordinal: number): TypeRef {
|
||||
return new TypeRef('', '', new UnresolvedDesc(pkgRef, ordinal));
|
||||
}
|
||||
|
||||
export {CompoundDesc, Field, makeCompoundTypeRef, makePrimitiveTypeRef, makeStructTypeRef, makeTypeRef, StructDesc, TypeRef};
|
||||
function makeUnresolvedTypeRef(namespace: string, name: string): TypeRef {
|
||||
return new TypeRef(name, namespace, new UnresolvedDesc(new Ref(), -1));
|
||||
}
|
||||
|
||||
export {
|
||||
CompoundDesc,
|
||||
Field,
|
||||
makeCompoundTypeRef,
|
||||
makePrimitiveTypeRef,
|
||||
makeStructTypeRef,
|
||||
makeTypeRef,
|
||||
makeUnresolvedTypeRef,
|
||||
StructDesc,
|
||||
TypeRef
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user