web3-storage / web3.storage

DEPRECATED ⁂ The simple file storage service for IPFS & Filecoin
https://web3.storage
Other
503 stars 119 forks source link

An example of reading a car file #1437

Closed am2222 closed 2 years ago

am2222 commented 2 years ago

Hi, I have a hard time reading a car file from the web3.storage. I want to store a cbor file and read it back. So here is my example I use this code to save a json object

import {CarReader} from "@ipld/car"
import * as cbor from "@ipld/dag-cbor"
import {encode,decode} from "multiformats/block"
import {sha256} from "multiformats/hashes/sha2"

const WEB3STORAGE_TOKEN = process.env.WEB3STORAGE_TOKEN
export const w3StorageClient = new Web3Storage({ token: WEB3STORAGE_TOKEN })
export const ipfsApiClient = new ipfsAPI({ host: 'ipfs.infura.io', port: 5001, protocol: "https" });

const makeCar = async (rootCID, ipldBlocks) => {
    return new CarReader(1, [rootCID], ipldBlocks)
}
const encodeCborBlock = async (value) => {
    return encode({ value, codec: cbor, hasher: sha256 })
}

export const uploadToIPFS =async (object)=>{
    const featureBlock = await encodeCborBlock(object)
    const car = await makeCar(featureBlock.cid, [featureBlock])

    const cid = await w3StorageClient.putCar(car)
    console.log("Content added with CID:", cid);
    return cid;
}

and When I want to read it I use this function

const readFiles = async (files) => {
  const filePromises = files.map((file) => {
    // Return a promise per file
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = async (e) => {
        try {
          // Resolve the promise with the response value
          resolve(e.target.result);
        } catch (err) {
          reject(err);
        }
      };
      reader.onerror = (error) => {
        reject(error);
      };
      reader.readAsArrayBuffer(file);
    });
  });

  const fileInfos = await Promise.all(filePromises);

  return fileInfos;
};

   const res = await w3StorageClient.get("bafybeia6d32ql6a22ydkn3g2so7yw73waaxe4agni5amh62oxcwhypeezq") // Promise<Web3Response | null>
    const files = await res.files() // Promise<Web3Response | null>
    const fileInfos = await readFiles(files)
    for (let index = 0; index < fileInfos.length; index++) {
      const carFile = fileInfos[index];
      let bytes=new Uint8Array(carFile); 
      const reader = await CarReader.fromBytes(bytes)
      const indexer = await CarIndexer.fromBytes(bytes)
      // const reader = await CarReader.fromBytes(bytes)
      const fixture = {
        header: reader._header, // a little naughty but we need gory details
        blocks: []
      }
      let i = 0
      for await (const blockIndex of indexer) {
        fixture.blocks[i] = blockIndex
        const block = await reader.get(blockIndex.cid)
        fixture.blocks[i].content = decode(blockIndex.cid, block.bytes)
        i++
      }
      const json = new TextDecoder().decode(cbor.encode(fixture))

    }

I think my file is being saved with no issues, just reading it and converting it back to json object is causing errors. Is there any example I can figure out how to do it? Thanks

am2222 commented 2 years ago

for the people might face similar issue in future this is my solution:

async function* streamAsyncIterator(stream) {
  // Get a lock on the stream
  const reader = stream.getReader();

  try {
    while (true) {
      // Read from the stream
      const { done, value } = await reader.read();
      // Exit if we're done
      if (done) return;
      // Else yield the chunk
      yield value;
    }
  }
  finally {
    reader.releaseLock();
  }
}

const info = await w3StorageClient.status(response)

    if (info) {
      // Fetch and verify files from web3.storage
      const res = await w3StorageClient.get(response);
      const reader = await CarReader.fromIterable(streamAsyncIterator(res.body))
      // read the list of roots from the header
      const roots = await reader.getRoots()
      // retrieve a block, as a { cid:CID, bytes:UInt8Array } pair from the archive
      const got = await reader.get(roots[0])
      // also possible: for await (const { cid, bytes } of CarIterator.fromIterable(inStream)) { ... }
      let decoded = cbor.decode(got.bytes)
      console.log('Retrieved [%s] from example.car with CID [%s]',
      decoded,
        roots[0].toString())
    }