UNPKG

@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
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