// package imports import type { IPFS } from "ipfs-core" import { CID } from "multiformats" // webnative imports import * as webnative from "webnative-0.30" import * as ipfsConfig from "webnative-0.30/ipfs/config.js" import * as setup from "webnative-0.30/setup.js" import * as identifiers from "webnative-0.30/common/identifiers.js" import * as path from "webnative-0.30/path.js" import { isBlob } from "webnative-0.30/common/index.js" import { isSoftLink } from "webnative-0.30/fs/types/check.js" import FileSystem from "webnative-0.30/fs/filesystem.js" // relative imports import { nodeImplementation } from "../utils/setup-node-keystore.js" import { Entry } from "../common.js" setup.setDependencies(nodeImplementation) export async function* traverseFileSystem(ipfs: IPFS, rootWNFSCID: CID, readKey: string): AsyncGenerator { ipfsConfig.set(ipfs) await webnative.crypto.keystore.importSymmKey(readKey, await identifiers.readKey({ path: path.directory("private") })) const filesystem = await FileSystem.fromCID(rootWNFSCID, { localOnly: true, permissions: { fs: { public: [path.root()], private: [path.root()] } } }) if (filesystem == null) throw "Couldn't load WNFS" yield* traverseEntries(["public"], filesystem) yield* traverseEntries(["private"], filesystem) } async function* traverseEntries(pathSoFar: string[], fs: FileSystem): AsyncGenerator { for (const [name, entry] of Object.entries(await fs.ls(path.directory(...pathSoFar)))) { // not sure why this happens if (name == null || name.length == null || name.length == 0) continue const entryPath = [...pathSoFar, name] if (isSoftLink(entry)) { continue // FIXME for future migrations from 0.30 upwards. } if (entry.isFile) { const content = await fs.read(path.file(...entryPath)) if (content == null) { console.warn(`Missing file content at ${entryPath}`) } else if (isBlob(content)) { console.warn(`Retrieved file as Blob. We can't handle that. At ${entryPath}`) } else yield { path: entryPath, isFile: true, content } } else { yield { path: entryPath, isFile: false, } try { yield* traverseEntries(entryPath, fs) } catch (e) { console.error(`Skipping some paths in ${path.toPosix(path.directory(...entryPath))} due to errors` + (e instanceof Error ? ` ("${e.message}").` : ",")) } } } } export async function filesystemFromEntries(entryStream: AsyncIterable, ipfs: IPFS, readKey: string): Promise { ipfsConfig.set(ipfs) await webnative.crypto.keystore.importSymmKey(readKey, await identifiers.readKey({ path: path.directory("private") })) const filesystem = await FileSystem.empty({ rootKey: readKey, localOnly: true, permissions: { fs: { private: [path.root()], public: [path.root()], } }}) for await (const entry of entryStream) { try { if (entry.isFile) { await filesystem.write(path.file(...entry.path), entry.content) } else { await filesystem.mkdir(path.directory(...entry.path)) } } catch (e) { console.error(`Error while trying to process ${path.toPosix(path.file(...entry.path))}` + (e instanceof Error ? ` ("${e.message}")` : "") + " continuing.") } } return await filesystem.root.put() }