Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

A fully offline, CAR-centric js-ipfs node #4183

Closed
ikreymer opened this issue Aug 11, 2022 · 6 comments
Closed

A fully offline, CAR-centric js-ipfs node #4183

ikreymer opened this issue Aug 11, 2022 · 6 comments
Labels
kind/stale kind/support A question or request for support need/author-input Needs input from the original author

Comments

@ikreymer
Copy link
Contributor

ikreymer commented Aug 11, 2022

Description:

I'm wondering if it'd be possible to support a fully offline, no-network, in-memory instance of js-ipfs that is designed to be used to only import, export CAR files, or add data directly, while supporting existing apis (or at least the workable subset).

I guess this functionality is sort of provided by web3-storage/ipfs-car, but the interface there is fairly different.

The goal would be to provide similar functionality, but with the standard ipfs apis, as well as ability to specify a custom blockstore from web3-storage/ipfs-car blockstores.

Could look something like:

const ipfs = await IPFS.create({"offline": true, blockstore: new MemoryBlockStore()})
...
ipfs.add(...)
...
ipfs.dag.put(...)
...
// export
const CAR = await ipfs.dag.export(...)

Probably at least the ipfs.files, ipfs.dag, ipfs.object apis could be supported?

This would allow for switching between an offline, CAR-only environment, and a 'live' environment, w/o having to use two different sets of APIs / systems.

Is this something that might be feasible in some way (or not?), or perhaps alternatively, something that could be built on top of web3-storage/ipfs-car itself. (If that repo is better place for this, feel free to move there!)

@ikreymer ikreymer added the need/triage Needs initial labeling and prioritization label Aug 11, 2022
@achingbrain
Copy link
Member

This should be possible, yes.

Instead of specifying a blockstore argument as above, you should check out the js-ipfs-custom-repo example. Instead of using FsDatastore everywhere for the root, blocks etc datastore as per the example, use MemoryDatastore from datastore-core instead.

@achingbrain achingbrain added kind/support A question or request for support need/author-input Needs input from the original author and removed need/triage Needs initial labeling and prioritization labels Sep 30, 2022
@github-actions
Copy link
Contributor

github-actions bot commented Oct 7, 2022

Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.

@ikreymer
Copy link
Contributor Author

ikreymer commented Oct 7, 2022

Thanks @achingbrain !

It worked! Based on that example I was able to create the following:

import { createRepo } from "ipfs-repo";

import { MemoryLock } from "ipfs-repo/locks/memory";
import { MemoryDatastore } from "datastore-core";
import { MemoryBlockstore } from "blockstore-core";

import * as dagPb from "@ipld/dag-pb";
import * as dagCbor from "@ipld/dag-cbor";
import * as raw from "multiformats/codecs/raw";

// multiformat codecs to support
const codecs = [dagPb, dagCbor, raw].reduce((acc, curr) => {
  acc[curr.name] = curr;
  acc[curr.code] = curr;
  return acc;
}, {});

export async function createInMemoryRepo() {
  const loadCodec = (nameOrCode) => {
    if (codecs[nameOrCode]) {
      return codecs[nameOrCode];
    }

    throw new Error(`Could not load codec for ${nameOrCode}`);
  };

  const repo = createRepo(
    "",
    loadCodec,
    {
      root: new MemoryDatastore(),

      blocks: new MemoryBlockstore(),

      keys: new MemoryDatastore(),
      datastore: new MemoryDatastore(),
      pins: new MemoryDatastore(),
    },
    {
      lock: MemoryLock,
      autoMigrate: false,
      repoOwner: true,
    }
  );

  return {
    repo,
    init: {
      emptyRepo: true
    },

    offline: true,
    start: false,

    config: {
      Bootstrap: [],
      Addresses: {},
      Discovery: {},
    },

    libp2p: {
      nat: {
        enabled: false,
      },
    },
  };
}

which can then be passed in to await IPFS.create(await createInMemoryRepo());

I think it'd be really neat if js-ipfs offered createInMemoryRepo() as a utility function, as it is a lot of boilerplate, but it seems to working well!

@BigLep
Copy link
Contributor

BigLep commented Oct 7, 2022

@ikreymer: great to hear that you were successful here. This isn't functionality we want to expose in js-ipfs itself, but we're glad you were able to find utility. Feel free to post/share on discuss.ipfs.tech for others to be aware of your solution.

@BigLep BigLep closed this as completed Oct 7, 2022
@ikreymer
Copy link
Contributor Author

ikreymer commented Oct 7, 2022

Actually, after testing in the browser, it seems the repo (in the above example) is not fully 'offline', eg. it tries to make connection to the preload nodes (https://node0.preload.ipfs.io/api/v0/refs...), despite also adding offline: true, and

config: {
      Bootstrap: [],
      Addresses: {},
      Discovery: {},
 }

Is there anything else that's missing? perhaps something in libp2p to make it truly offline and not connect anywhere?

@ikreymer
Copy link
Contributor Author

ikreymer commented Oct 7, 2022

It looks like this is also in some ways a duplicate of:
#2751 (comment) (though w/o custom codecs).

It looks like that issue was in relation to https://github.com/mikeal/ipfs-for-car from @mikeal, which appears to no longer be used.

Also don't want to be reinventing the wheel, what I was hoping for was basically ipfs-for-car, but wonder if it was abandoned for certain reasons?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
kind/stale kind/support A question or request for support need/author-input Needs input from the original author
Projects
None yet
Development

No branches or pull requests

3 participants