From cccf19958241e6065c0c12ff91bb0cbaf1fd735c Mon Sep 17 00:00:00 2001 From: Erin Rivas Date: Wed, 16 Oct 2024 14:50:37 -0500 Subject: [PATCH] adding checkIfUpcycle() tweaks rounding out directoryLeaves creating exception for root folder trying to clean up errors set conversion tweak to upcycleFile adding file unavailable bypass wrong parent circular reference more flexible folder parents ref compatibility adding id restriction --- src/classes/filetreeReader.ts | 123 ++++++++++++++++------ src/classes/storageHandler.ts | 66 ++++++++---- src/interfaces/classes/IStorageHandler.ts | 2 + src/utils/converters.ts | 2 +- 4 files changed, 139 insertions(+), 54 deletions(-) diff --git a/src/classes/filetreeReader.ts b/src/classes/filetreeReader.ts index b7f08ff..09ed242 100644 --- a/src/classes/filetreeReader.ts +++ b/src/classes/filetreeReader.ts @@ -53,6 +53,7 @@ export class FiletreeReader implements IFiletreeReader { protected ulidLeaves: Record> protected directoryLeaves: Record> + protected directoriesByUlid: Record> protected yellowpages: Record> protected legacyMetaLeaves: Record protected refCounts: Record @@ -76,6 +77,8 @@ export class FiletreeReader implements IFiletreeReader { this.ulidLeaves[ownerAddress] = {} this.directoryLeaves = {} this.directoryLeaves[ownerAddress] = {} + this.directoriesByUlid = {} + this.directoriesByUlid[ownerAddress] = {} this.yellowpages = {} this.yellowpages[ownerAddress] = {} this.legacyMetaLeaves = {} @@ -139,11 +142,14 @@ export class FiletreeReader implements IFiletreeReader { try { const final: TConversionPair[] = [] for (let ulid of this.conversionQueue) { + if (ulid === '-1') { + continue + } const meta = await this.loadMetaByUlid(ulid) if (meta.metaDataType === 'file') { const parent = meta.location.split('/').slice(-1)[0] - const files = this.directoryLeaves[this.clientAddress][parent].files + const { files } = this.readDirectoryLeafByUlid(parent) for (let index of Object.keys(files)) { if (files[Number(index)].fileMeta.name === meta.fileMeta.name) { const refIndex = Number(index) @@ -163,7 +169,7 @@ export class FiletreeReader implements IFiletreeReader { final.push([meta.metaDataType, handler]) } else { this.nullConversions.push(parent) - const nulls = this.directoryLeaves[this.clientAddress][parent].nulls + const { nulls } = this.readDirectoryLeafByUlid(parent) for (let index of Object.keys(nulls)) { const handler = await NullMetaHandler.create({ location: parent, @@ -175,28 +181,41 @@ export class FiletreeReader implements IFiletreeReader { } } else if (meta.metaDataType === 'folder') { const parent = meta.location.split('/').slice(-1)[0] - const folders = this.directoryLeaves[this.clientAddress][parent].folders - for (let index of Object.keys(folders)) { - if (folders[Number(index)].whoAmI === meta.whoAmI) { - const refIndex = Number(index) - const handler = await FolderMetaHandler.create({ - count: hexToInt(meta.count), - description: meta.description, - location: parent, - name: meta.whoAmI, - refIndex, - ulid, - }) - final.push([meta.metaDataType, handler]) - break + if (parent.length < 26) { + const handler = await FolderMetaHandler.create({ + count: hexToInt(meta.count), + description: meta.description, + location: meta.whoAmI, + name: meta.whoAmI, + refIndex: 0, + ulid, + }) + final.push([meta.metaDataType, handler]) + } else { + const { folders } = this.readDirectoryLeafByUlid(parent) + for (let index of Object.keys(folders)) { + if (folders[Number(index)].whoAmI === meta.whoAmI) { + const refIndex = Number(index) + const handler = await FolderMetaHandler.create({ + count: hexToInt(meta.count), + description: meta.description, + location: parent, + name: meta.whoAmI, + refIndex, + ulid, + }) + final.push([meta.metaDataType, handler]) + break + } } } + } else if (meta.metaDataType === 'rootlookup') { const handler = await FolderMetaHandler.create({ count: 0, location: 'ulid', name: 'Home', - ulid, + ulid: meta.ulid, }) final.push([meta.metaDataType, handler]) } @@ -233,7 +252,7 @@ export class FiletreeReader implements IFiletreeReader { const segments = path.split('/') const parentPath = segments.slice(0, -1).join('/') const target = segments.slice(-1)[0] - const details = this.directoryLeaves[this.clientAddress][parentPath] + const details = this.readDirectoryLeafByPath(parentPath) for (let index of Object.keys(details.folders)) { const ref = Number(index) @@ -270,10 +289,10 @@ export class FiletreeReader implements IFiletreeReader { try { if (this.directoryLeaves[owner][path] && !refresh) { - return this.directoryLeaves[owner][path] + return this.readDirectoryLeafByPath(path, owner) } else { await this.pathToLookupPostProcess(path, owner, this.yellowpages[owner][path]) - return this.directoryLeaves[owner][path] + return this.readDirectoryLeafByPath(path, owner) } } catch (err) { throw warnError('filetreeReader readFolderContents()', err) @@ -440,7 +459,7 @@ export class FiletreeReader implements IFiletreeReader { ownerAddress: await hashAndHexOwner(hexAddress, this.clientAddress), } const { file } = await this.jackalSigner.queries.fileTree.file(lookup) - const meta = await this.loadMeta(file, ulid) + const meta = await this.loadMeta(file, '-1') return (meta.metaDataType === 'ref') ? meta as IRefMetaData : meta as INullRefMetaData } catch (err) { throw warnError('filetreeReader loadRefMeta()', err) @@ -501,7 +520,11 @@ export class FiletreeReader implements IFiletreeReader { * @returns {Promise} */ async loadMetaByPath (path: string): Promise { - return await this.loadMetaByExternalPath(path, this.clientAddress) + try { + return await this.loadMetaByExternalPath(path, this.clientAddress) + } catch (err) { + throw warnError('filetreeReader loadMetaByPath()', err) + } } /** @@ -932,9 +955,9 @@ export class FiletreeReader implements IFiletreeReader { const isCleartext = contents.includes('metaDataType') const access = await this.checkViewAuthorization(file, isCleartext) if (access) { + const id = this.ulidLookup(path, ownerAddress) let parsed if (!isCleartext) { - const id = this.ulidLookup(path, ownerAddress) parsed = await this.decryptAndParseContents(file, id) } else { parsed = JSON.parse(contents) as TMetaDataSets @@ -944,7 +967,7 @@ export class FiletreeReader implements IFiletreeReader { if (ownerAddress === this.clientAddress) { this.refCountSet(path, count) } - this.directoryLeaves[ownerAddress][path] = this.basicFolderShell() + this.startDirectoryLeaf(path, id, ownerAddress) const post = [] for (let i = 0; i < count; i++) { post.push(this.singleLoadMeta(path, ownerAddress, i)) @@ -979,7 +1002,7 @@ export class FiletreeReader implements IFiletreeReader { if (refMeta.metaDataType === 'nullref') { return } - const leaf = this.directoryLeaves[ownerAddress][path] + const leaf = this.readDirectoryLeafByPath(path, ownerAddress) const meta = await this.loadMetaByUlid(refMeta.pointsTo) if (meta.metaDataType === 'folder') { const loopPath = `${path}/${meta.whoAmI}` @@ -1011,6 +1034,44 @@ export class FiletreeReader implements IFiletreeReader { } } + /** + * + * @param {string} path + * @param {string} ulid + * @param {string} [ownerAddress] + * @protected + */ + protected startDirectoryLeaf (path: string, ulid: string, ownerAddress?: string): void { + const owner = ownerAddress || this.clientAddress + const shell = this.basicFolderShell() + this.directoryLeaves[owner][path] = shell + this.directoriesByUlid[owner][ulid] = shell + } + + /** + * + * @param {string} path + * @param {string} [ownerAddress] + * @returns {IChildMetaDataMap} + * @protected + */ + protected readDirectoryLeafByPath (path: string, ownerAddress?: string): IChildMetaDataMap { + const owner = ownerAddress || this.clientAddress + return this.directoryLeaves[owner][path] + } + + /** + * + * @param {string} ulid + * @param {string} [ownerAddress] + * @returns {IChildMetaDataMap} + * @protected + */ + protected readDirectoryLeafByUlid (ulid: string, ownerAddress?: string): IChildMetaDataMap { + const owner = ownerAddress || this.clientAddress + return this.directoriesByUlid[owner][ulid] + } + /** * * @param {string} path @@ -1212,10 +1273,12 @@ export class FiletreeReader implements IFiletreeReader { return [await genAesBundle(), false] } else { try { - return [await stringToAes(this.keyPair, parsedAccess[user]), false] - } catch (_) { + const parsed = await stringToAes(this.keyPair, parsedAccess[user]) + return [parsed, false] + } catch { try { - return [await stringToAes(this.defaultKeyPair, parsedAccess[user]), true] + const parsed = await stringToAes(this.defaultKeyPair, parsedAccess[user]) + return [parsed, true] } catch (err) { throw err } @@ -1292,8 +1355,8 @@ export class FiletreeReader implements IFiletreeReader { try { const safe = prepDecompressionForAmino(data.contents) const aes = await this.extractViewAccess(data) - if (aes[1]) { - this.conversionQueue.push(id) + if (id !== '-1' && aes[1]) { + this.conversionQueue = [...new Set([...this.conversionQueue, id])] } let decrypted = await cryptString(safe, aes[0], 'decrypt') if (decrypted.startsWith('jklpc1')) { diff --git a/src/classes/storageHandler.ts b/src/classes/storageHandler.ts index 1ab5ab2..9d07daa 100644 --- a/src/classes/storageHandler.ts +++ b/src/classes/storageHandler.ts @@ -192,32 +192,36 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { const hostAddress = client.getHostAddress() const chainId = client.getHostChainId() - let signatureAsHex = '' + let signed, signatureAsHex switch (selectedWallet) { case 'keplr': if (!window.keplr) { throw 'Missing wallet extension' } else { - const { signature } = await window.keplr.signArbitrary( + signed = await window.keplr.signArbitrary( chainId, hostAddress, signatureSeed, ) - signatureAsHex = await stringToShaHex(signature) + signatureAsHex = await stringToShaHex(signed.signature) } break case 'leap': if (!window.leap) { throw 'Missing wallet extension' } else { - const { signature } = await window.leap.signArbitrary( + signed = await window.leap.signArbitrary( chainId, hostAddress, signatureSeed, ) - signatureAsHex = await stringToShaHex(signature) + signatureAsHex = await stringToShaHex(signed.signature) } break + default: + throw new Error( + 'No wallet selected but one is required to init StorageHandler', + ) } return [PrivateKey.fromHex(signatureAsHex), true] } catch (err) { @@ -360,10 +364,12 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { */ async upgradeSigner (): Promise { try { - ;[this.keyPair, this.fullSigner] = await StorageHandler.enableFullSigner( + const [pair, signer] = await StorageHandler.enableFullSigner( this.jackalClient, ) - await this.resetReader(this.keyPair) + this.keyPair = pair + this.fullSigner = signer + await this.resetReader(pair) } catch (err) { throw warnError('storageHandler upgradeSigner()', err) } @@ -1234,6 +1240,16 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { } } + /** + * + * @returns {boolean} + */ + checkIfUpcycle (): boolean { + const len = this.reader.getConversionQueueLength() + console.log('ConversionQueueLength:', len) + return len > 0 + } + /** * * @param {IBroadcastOptions} [options] @@ -1250,19 +1266,23 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { let upcycleMsgs switch (one[0]) { case 'file': - const pkg = await this.upcycleFile(one[1]) - const { files } = - await this.jackalSigner.queries.storage.allFilesByMerkle({ - merkle: one[1].export().merkleRoot, + try { + const pkg = await this.upcycleFile(one[1]) + const { files } = + await this.jackalSigner.queries.storage.allFilesByMerkle({ + merkle: one[1].export().merkleRoot, + }) + const [details] = files + const sourceMsgs = this.fileDeleteToMsgs({ + creator: this.jklAddress, + merkle: details.merkle, + start: details.start, }) - const [details] = files - const sourceMsgs = this.fileDeleteToMsgs({ - creator: this.jklAddress, - merkle: details.merkle, - start: details.start, - }) - upcycleMsgs = await this.pkgToMsgs(pkg, blockheight) - msgs.push(...sourceMsgs, ...upcycleMsgs) + upcycleMsgs = await this.pkgToMsgs(pkg, blockheight) + msgs.push(...sourceMsgs, ...upcycleMsgs) + } catch { + console.log(`Skipping ${one[1].export().fileMeta.name}`) + } break case 'null': upcycleMsgs = await this.filetreeDeleteToMsgs({ meta: one[1], aes: await genAesBundle() }) @@ -1278,7 +1298,7 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { break } } - const ready = prompt('Ready to Upcycle?') + const ready = confirm('Are you ready to Upcycle?') this.upcycleQueue = msgs if (ready) { await this.runUpcycleQueue(options) @@ -1336,10 +1356,10 @@ export class StorageHandler extends EncodingHandler implements IStorageHandler { const { providerIps } = await this.jackalSigner.queries.storage.findFile({ merkle: sourceMeta.merkleRoot, }) + console.log('providerIps:', providerIps) let baseFile - for (const _ of providerIps) { - const provider = - providerIps[Math.floor(Math.random() * providerIps.length)] + for (let i = 0; i < providerIps.length; i++) { + const provider = providerIps[0] const url = `${provider}/download/${sourceMeta.merkleHex}` try { const resp = await fetch(url, { method: 'GET' }) diff --git a/src/interfaces/classes/IStorageHandler.ts b/src/interfaces/classes/IStorageHandler.ts index 668dbd6..e8e0bb1 100644 --- a/src/interfaces/classes/IStorageHandler.ts +++ b/src/interfaces/classes/IStorageHandler.ts @@ -102,6 +102,8 @@ export interface IStorageHandler { convert (options?: IBroadcastOrChainOptions): Promise + checkIfUpcycle (): boolean + checkAndUpcycle (options?: IBroadcastOptions): Promise runUpcycleQueue (options?: IBroadcastOptions): Promise diff --git a/src/utils/converters.ts b/src/utils/converters.ts index d766056..74a0297 100644 --- a/src/utils/converters.ts +++ b/src/utils/converters.ts @@ -370,7 +370,7 @@ export function safeStringifyFileTree (source: TMetaDataSets): string { export function safeParseFileTree (source: string): TMetaDataSets { try { const base = JSON.parse(source) - if (base.merkleRoot) { + if ('merkleRoot' in base) { if (Array.isArray(base.merkleRoot)) { base.merkleRoot = new Uint8Array(base.merkleRoot) } else {