@dstanesc/o-o-o-o-o-o-o
Version:
O-O-O-O-O-O-O is a collection of content addressed persistent data structures
455 lines • 20.5 kB
JavaScript
import { blockIndexFactory } from './block-index';
import { memoryBlockStoreFactory, } from './block-store';
import { Graph } from './graph';
import { graphPackerFactory } from './graph-packer';
import { graphStoreFactory } from './graph-store';
import { versionStoreFactory } from './version-store';
import axios from 'axios';
const relayClientBasicFactory = ({ chunk, chunkSize, linkCodec, valueCodec, blockStore, incremental = false, }, config) => {
const plumbing = relayClientPlumbingFactory(config);
const { packVersionStore, restoreSingleIndex: restoreVersionStore, packGraphVersion, packRootIndex, packRandomBlocks, restoreGraphVersion, restoreRootIndex, restoreRandomBlocks, } = graphPackerFactory(linkCodec);
const push = async (versionStoreRoot, versionRoot) => {
var _a;
let localVersionRoot;
const localVersionStore = await versionStoreFactory({
storeRoot: versionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const localVersionStoreBundle = await packVersionStore(versionStoreRoot, blockStore, chunk, valueCodec);
if (versionRoot === undefined) {
localVersionRoot = localVersionStore.currentRoot();
}
else {
localVersionRoot = versionRoot;
}
const graphVersionBundles = [];
let remoteVersionStoreBytes;
if (incremental) {
try {
remoteVersionStoreBytes = await plumbing.storePull(chunkSize, localVersionStore.id());
}
catch (error) {
if (axios.isAxiosError(error)) {
const axiosError = error;
if (((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status) !== 404) {
throw error;
}
}
}
}
if (remoteVersionStoreBytes !== undefined) {
const diffStore = memoryBlockStoreFactory();
const { root: remoteVersionStoreRoot } = await restoreVersionStore(remoteVersionStoreBytes, diffStore);
const remoteVersionStore = await versionStoreFactory({
storeRoot: remoteVersionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore: diffStore,
});
const remoteVersionRoot = remoteVersionStore.currentRoot();
const remoteVersionRoots = remoteVersionStore
.log()
.map((version) => version.root);
if (remoteVersionRoots
.map((root) => linkCodec.encodeString(root))
.includes(linkCodec.encodeString(localVersionRoot))) {
return {
storeRoot: versionStoreRoot,
versionRoot: localVersionRoot,
};
}
else {
const remoteRootIndexBytes = await plumbing.indexPull(linkCodec.encodeString(remoteVersionRoot));
const { blocks: remoteRootIndexBlocks } = await restoreRootIndex(remoteRootIndexBytes, diffStore);
const localRootIndexBundle = await packRootIndex(localVersionRoot, blockStore);
const { blocks: localRootIndexBlocks } = await restoreRootIndex(localRootIndexBundle.bytes, diffStore);
const selectedBlocks = [];
for (const block of localRootIndexBlocks) {
const linkString = linkCodec.encodeString(block.cid);
if (!remoteRootIndexBlocks
.map((block) => linkCodec.encodeString(block.cid))
.includes(linkString)) {
selectedBlocks.push(block);
}
}
const blockIndexBuilder = blockIndexFactory({
linkCodec,
blockStore: diffStore,
});
const contentDiff = await blockIndexBuilder.diffRootIndex({
currentRoot: remoteVersionRoot,
otherRoot: localVersionRoot,
});
for (const link of contentDiff.added) {
const bytes = await blockStore.get(link);
const block = { cid: link, bytes };
selectedBlocks.push(block);
}
const diffBundle = await packRandomBlocks(selectedBlocks);
const blocksPushResponse = await plumbing.blocksPush(diffBundle.bytes);
if (blocksPushResponse.blockCount !== selectedBlocks.length) {
throw new Error(`Failed to push all blocks pushed: ${selectedBlocks.length}, confirmed: ${blocksPushResponse.blockCount}`);
}
const storePushResponse = await plumbing.storePush(chunkSize, localVersionStoreBundle.bytes);
return {
storeRoot: linkCodec.parseString(storePushResponse.storeRoot),
versionRoot: linkCodec.parseString(storePushResponse.versionRoot),
};
}
}
else {
const graphVersionBundle = await packGraphVersion(localVersionRoot, blockStore);
const graphPushResponse = await plumbing.graphPush(graphVersionBundle.bytes);
const storePushResponse = await plumbing.storePush(chunkSize, localVersionStoreBundle.bytes);
return {
storeRoot: linkCodec.parseString(storePushResponse.storeRoot),
versionRoot: linkCodec.parseString(storePushResponse.versionRoot),
};
}
};
const pull = async (versionStoreId, localVersionStoreRoot) => {
var _a, _b;
let remoteVersionStoreBytes;
if (incremental && localVersionStoreRoot !== undefined) {
try {
remoteVersionStoreBytes = await plumbing.storePull(chunkSize, versionStoreId);
}
catch (error) {
if (axios.isAxiosError(error)) {
const axiosError = error;
if (((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.status) !== 404) {
throw error;
}
}
}
if (remoteVersionStoreBytes !== undefined) {
const diffStore = memoryBlockStoreFactory();
const { root: remoteVersionStoreRoot } = await restoreVersionStore(remoteVersionStoreBytes, diffStore);
const remoteVersionStore = await versionStoreFactory({
storeRoot: remoteVersionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore: diffStore,
});
const remoteVersionRoot = remoteVersionStore.currentRoot();
const localVersionStore = await versionStoreFactory({
storeRoot: localVersionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const localVersionRoot = localVersionStore.currentRoot();
if (linkCodec.encodeString(localVersionRoot) !==
linkCodec.encodeString(remoteVersionRoot)) {
const remoteRootIndexBytes = await plumbing.indexPull(linkCodec.encodeString(remoteVersionRoot));
const { blocks: remoteRootIndexBlocks } = await restoreRootIndex(remoteRootIndexBytes, diffStore);
const localRootIndexBundle = await packRootIndex(localVersionRoot, blockStore);
const { blocks: localRootIndexBlocks } = await restoreRootIndex(localRootIndexBundle.bytes, diffStore);
const requiredBlockIdentifiers = [];
for (const block of remoteRootIndexBlocks) {
const linkString = linkCodec.encodeString(block.cid);
if (!localRootIndexBlocks
.map((block) => linkCodec.encodeString(block.cid))
.includes(linkString)) {
requiredBlockIdentifiers.push(linkString);
}
}
const blockIndexBuilder = blockIndexFactory({
linkCodec,
blockStore: diffStore,
});
const contentDiff = await blockIndexBuilder.diffRootIndex({
currentRoot: localVersionRoot,
otherRoot: remoteVersionRoot,
});
for (const link of contentDiff.added) {
requiredBlockIdentifiers.push(linkCodec.encodeString(link));
}
const randomBlocksBundle = await plumbing.blocksPull(requiredBlockIdentifiers);
if (randomBlocksBundle !== undefined) {
const selectedBlocks = await restoreRandomBlocks(randomBlocksBundle, diffStore);
const localVersionStoreBundle = await packVersionStore(localVersionStoreRoot, blockStore, chunk, valueCodec);
const { root: storeRootExisting } = await restoreVersionStore(localVersionStoreBundle.bytes, diffStore);
const graphStoreBundleExisting = await packGraphVersion(localVersionRoot, blockStore);
const { root: versionRootExisting } = await restoreGraphVersion(graphStoreBundleExisting.bytes, diffStore);
const versionStoreExisting = await versionStoreFactory({
storeRoot: localVersionStoreRoot,
versionRoot: localVersionRoot,
chunk,
linkCodec,
valueCodec,
blockStore: diffStore,
});
const { root: mergedRoot, index: mergedIndex, blocks: mergedBlocks, } = await versionStoreExisting.mergeVersions(remoteVersionStore);
await diffStore.push(blockStore);
const mergedVersionRoot = versionStoreExisting.currentRoot();
const mergedVersionStoreRoot = versionStoreExisting.versionStoreRoot();
const versionStore = await versionStoreFactory({
storeRoot: mergedVersionStoreRoot,
versionRoot: mergedVersionRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graphStore = graphStoreFactory({
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graph = new Graph(versionStore, graphStore);
return {
versionStore,
graphStore,
graph,
};
}
else {
throw new Error(`Failed to pull selected blocks: ${JSON.stringify(requiredBlockIdentifiers)}`);
}
}
else {
const versionStore = await versionStoreFactory({
storeRoot: localVersionStoreRoot,
versionRoot: localVersionRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graphStore = graphStoreFactory({
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graph = new Graph(versionStore, graphStore);
return {
versionStore,
graphStore,
graph,
};
}
}
else {
return undefined;
}
}
else {
try {
remoteVersionStoreBytes = await plumbing.storePull(chunkSize, versionStoreId);
}
catch (error) {
if (axios.isAxiosError(error)) {
const axiosError = error;
if (((_b = axiosError.response) === null || _b === void 0 ? void 0 : _b.status) !== 404) {
throw error;
}
}
}
if (remoteVersionStoreBytes !== undefined) {
const transientStore = memoryBlockStoreFactory();
const { root: versionStoreRoot, index: versionStoreIndex, blocks: versionStoreBlocks, } = await restoreVersionStore(remoteVersionStoreBytes, transientStore);
const versionStoreRemote = await versionStoreFactory({
storeRoot: versionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore: transientStore,
});
const remoteVersions = versionStoreRemote.log();
for (const version of remoteVersions) {
try {
await blockStore.get(version.root);
}
catch (e) {
const graphVersionBytes = await plumbing.graphPull(version.root.toString());
if (graphVersionBytes !== undefined) {
await restoreGraphVersion(graphVersionBytes, transientStore);
}
}
}
if (localVersionStoreRoot !== undefined) {
const localVersionStoreBundle = await packVersionStore(localVersionStoreRoot, blockStore, chunk, valueCodec);
const { root: storeRootExisting } = await restoreVersionStore(localVersionStoreBundle.bytes, transientStore);
const versionStoreLocal = await versionStoreFactory({
storeRoot: localVersionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore: transientStore,
});
const localVersions = versionStoreLocal.log();
for (const version of localVersions) {
const localGraphVersionBundle = await packGraphVersion(version.root, blockStore);
await restoreGraphVersion(localGraphVersionBundle.bytes, transientStore);
}
const { root: mergedRoot, index: mergedIndex, blocks: mergedBlocks, } = await versionStoreLocal.mergeVersions(versionStoreRemote);
await transientStore.push(blockStore);
const mergedVersionRoot = versionStoreLocal.currentRoot();
const mergedVersionStoreRoot = versionStoreLocal.versionStoreRoot();
const versionStore = await versionStoreFactory({
storeRoot: mergedVersionStoreRoot,
versionRoot: mergedVersionRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graphStore = graphStoreFactory({
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graph = new Graph(versionStore, graphStore);
return {
versionStore,
graphStore,
graph,
};
}
else {
await transientStore.push(blockStore);
const versionStore = await versionStoreFactory({
storeRoot: versionStoreRoot,
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graphStore = graphStoreFactory({
chunk,
linkCodec,
valueCodec,
blockStore,
});
const graph = new Graph(versionStore, graphStore);
return {
versionStore,
graphStore,
graph,
};
}
}
else {
return undefined;
}
}
};
return { push, pull };
};
const relayClientPlumbingFactory = (config) => {
const httpClient = axios.create(config);
const storePush = async (chunkSize, bytes) => {
const response = await httpClient.put('/store/push', bytes.buffer, {
params: {
chunkSize: chunkSize,
},
headers: {
'Content-Type': 'application/octet-stream',
},
});
return response.data;
};
const storePull = async (chunkSize, versionStoreId) => {
const response = await httpClient.get('/store/pull', {
responseType: 'arraybuffer',
params: {
chunkSize: chunkSize,
id: versionStoreId,
},
});
if (response.data) {
const bytes = new Uint8Array(response.data);
return bytes;
}
else
return undefined;
};
const storeResolve = async (versionStoreId) => {
const response = await httpClient.get('/store/resolve', {
params: {
id: versionStoreId,
},
});
return response.data;
};
const graphPush = async (bytes) => {
const response = await httpClient.put('/graph/version/push', bytes.buffer, {
headers: {
'Content-Type': 'application/octet-stream',
},
});
return response.data;
};
const graphPull = async (versionRoot) => {
const response = await httpClient.get('/graph/version/pull', {
responseType: 'arraybuffer',
params: {
id: versionRoot,
},
});
if (response.data) {
const bytes = new Uint8Array(response.data);
return bytes;
}
else
return undefined;
};
const indexPull = async (versionRoot) => {
const response = await httpClient.get('/graph/index/pull', {
responseType: 'arraybuffer',
params: {
id: versionRoot,
},
});
if (response.data) {
const bytes = new Uint8Array(response.data);
return bytes;
}
else
return undefined;
};
const blocksPush = async (bytes) => {
const response = await httpClient.put('/blocks/push', bytes.buffer, {
headers: {
'Content-Type': 'application/octet-stream',
},
});
return response.data;
};
const blocksPull = async (links) => {
const response = await httpClient.put('/blocks/pull', { links }, {
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json',
},
});
if (response.data) {
const bytes = new Uint8Array(response.data);
return bytes;
}
else
return undefined;
};
return {
storePush,
storePull,
storeResolve,
graphPush,
graphPull,
indexPull,
blocksPush,
blocksPull,
};
};
export { relayClientPlumbingFactory, relayClientBasicFactory, };
//# sourceMappingURL=relay-client.js.map