diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000000..ce760a22ae --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,96 @@ +# Architecture + +``` +┌───┐ ┌───────────────┐ ┌──────────────┐ +│CLI│───▶│ HTTP API ├───▶│IPFS Core Impl│ +└───┘ └───────────────┘ └──────────────┘ + △ △ △ + └──────────────└──────────┬─────────┘ + │ + ┌─────┐ + │Tests│ + └─────┘ +``` + +## IPFS Core implementation architecture + +IPFS Core is divided into separate subsystems, each of them exist in their own repo/module. The dependencies between each subsystem is assured by injection at the IPFS Core level. IPFS Core exposes an API, defined by the IPFS API spec. libp2p is the networking layer used by IPFS, but out of scope in IPFS core, follow that project [here](https://github.com/diasdavid/js-libp2p) + + +``` + ▶ ┌───────────────────────────────────────────────────────────────────────────────┐ + │ IPFS Core │ + │ └───────────────────────────────────────────────────────────────────────────────┘ + │ + │ │ + │ + │ ┌──────────────┬──────────────┼────────────┬─────────────────┐ + │ │ │ │ │ + │ │ │ │ │ │ + ▼ │ ▼ │ ▼ + │ ┌──────────────────┐ │ ┌──────────────────┐ │ ┌──────────────────┐ + │ │ │ │ │ │ │ │ + │ │ Block Service │ │ │ DAG Service │ │ │ IPFS Repo │ + │ │ │ │ │ │ │ │ + │ └──────────────────┘ │ └──────────────────┘ │ └──────────────────┘ + │ │ │ │ + IPFS Core │ ▼ │ ┌────┴────┐ │ + ┌────────┐ │ ▼ ▼ │ + │ │ Block │ │ ┌────────┐┌────────┐ │ + └────────┘ │ │DAG Node││DAG Link│ │ + │ │ └────────┘└────────┘ │ + ┌──────────────────┐ │ │ ┌──────────────────┐ + │ │ │ │ │ │ │ + │ Bitswap │◀────┤ ├──────▶│ Importer │ + │ │ │ │ │ │ │ + └──────────────────┘ │ │ └──────────────────┘ + │ │ │ │ + │ │ ┌────┴────┐ + │ │ │ ▼ ▼ + │ │ ┌────────┐┌────────┐ + │ ┌──────────────────┐ │ │ │ layout ││chunker │ + │ │ │ ┌────────────┘ └────────┘└────────┘ + │ │ Files │◀────┘ │ + │ │ │ + │ └──────────────────┘ │ + ▶ │ + ▼ + ┌───────────────────────────────────────────────────────────────────────────────┐ + │ │ + │ │ + │ │ + │ libp2p │ + │ │ + │ │ + └───────────────────────────────────────────────────────────────────────────────┘ +``` + +#### IPFS Core + +IPFS Core is the entry point module for IPFS. It exposes an interface defined on [IPFS Specs.](https://github.com/ipfs/specs/blob/ipfs/api/api/core/README.md) + +#### Block Service + +Block Service uses IPFS Repo (local storage) and Bitswap (network storage) to store and fetch blocks. A block is a serialized MerkleDAG node. + +#### DAG Service + +DAG Service offers some graph language semantics on top of the MerkleDAG, composed by DAG Nodes (which can have DAG Links). It uses the Block Service as its storage and discovery service. + +#### IPFS Repo + +IPFS Repo is storage driver of IPFS, follows the [IPFS Repo Spec](https://github.com/ipfs/specs/tree/master/repo) and supports the storage of different types of files. + +#### Bitswap + +Bitswap is the exchange protocol used by IPFS to 'trade' blocks with other IPFS nodes. + +#### Files + +Files is the API that lets us work with IPFS objects (DAG Nodes) as if they were Unix Files. + +#### Importer + +Importer are a set of layouts (e.g. UnixFS) and chunkers (e.g: fixed-size, rabin, etc) that convert data to a MerkleDAG representation inside IPFS. + + diff --git a/README.md b/README.md index a714856b8a..7d02051d83 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,7 @@ This repo contains the JavaScript implementation of the IPFS protocol, with feat ### Project status -Consult the [Roadmap](/ROADMAP.md) for a complete state description of the project, or you can find `in process` updates in our [`Captain.log`](https://github.com/ipfs/js-ipfs/issues/30). A lot of components can be used currently, but it is a WIP, so beware of the Dragons. - -[![](https://camo.githubusercontent.com/561516567e49f00b5a4f489e122ca9d22815b547/68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f4965685335436f46667a5175512f67697068792e676966)](https://github.com/ipfs/js-ipfs/issues/30) +Consult the [Roadmap](/ROADMAP.md) for a complete state description of the project, or you can find `in process` updates in our [`Captain.log`](https://github.com/ipfs/js-ipfs/issues/30). A lot of components can be used currently, but it is a WIP, so beware of the Dragons 🐉. ## Table of Contents @@ -37,15 +35,7 @@ Consult the [Roadmap](/ROADMAP.md) for a complete state description of the proje - [Examples](#examples) - [API](#api) - [Development](#development) -- [Project structure](#project-structure) -- [IPFS Core implementation architecture](#ipfs-core-implementation-architecture) - - [IPFS Core](#ipfs-core) - - [Block Service](#block-service) - - [DAG Service](#dag-service) - - [IPFS Repo](#ipfs-repo) - - [Bitswap](#bitswap) - - [Files](#files) - - [Importer](#importer) +- [Project Architecture](/ARCHITECTURE.md) - [Packages](#packages) - [Contribute](#contribute) - [Want to hack on IPFS?](#want-to-hack-on-ipfs) @@ -97,155 +87,151 @@ Loading this module in a browser (using a ` - ``` -* loading the human-readable (not minified) version +```html + + - ```html - - ``` + + +``` ## Usage -### Examples +### CLI -> **Will come soon** +The `jsipfs` CLI, available when `js-ipfs` is installed globably, follows(should, it is a WIP) the same interface defined by `go-ipfs`, you can always use the `help` command for help menus. -### API +``` +# Install js-ipfs globally +> npm install ipfs --global +> jsipfs --help +Commands: + bitswap A set of commands to manipulate the bitswap agent. + block Manipulate raw IPFS blocks. + bootstrap Show or edit the list of bootstrap peers. + commands List all available commands + config [value] Get and set IPFS config values + daemon Start a long-running daemon process +# ... +``` -A complete API definition will come, meanwhile, you can learn how to you use js-ipfs throught he standard interface at [![](https://img.shields.io/badge/interface--ipfs--core-API%20Docs-blue.svg)](https://github.com/ipfs/interface-ipfs-core) +### HTTP-API -## Development +The HTTP-API exposed by the js-ipfs daemon follows the [`http-api-spec`](https://github.com/ipfs/http-api-spec). You can use any of the IPFS HTTP-API client libraries with it, such as: [js-ipfs-api](https://github.com/ipfs/js-ipfs-api). -### Clone -``` -git clone https://github.com/ipfs/js-ipfs.git -cd js-ipfs -``` +### IPFS Core examples (use IPFS as a module) -### Install Dependencies -``` -npm install -``` +#### Create a IPFS node instance -### Run Tests -``` -npm test -``` +```JavaScript +// IPFS will need a repo, it can create one for you or you can pass +// it a repo instance of the type IPFS Repo +// https://github.com/ipfs/js-ipfs-repo +const repo = -### Lint +// Create the IPFS node instance +const node = new IPFS(repo) -*Conforming to linting rules is a prerequisite to commit to js-ipfs.* +// We need to init our repo, in this case the repo was empty +// We are picking 2048 bits for the RSA key that will be our PeerId +ipfs.init({ emptyRepo: true, bits: 2048 }, (err) => { + if (err) { throw err } -``` -npm run lint -``` + // Once the repo is initiated, we have to load it so that the IPFS + // instance has its config values. This is useful when you have + // previous created repos and you don't need to generate a new one + ipfs.load((err) => { + if (err) { throw err } -### Build -``` -npm run build + // Last but not the least, we want our IPFS node to use its peer + // connections to fetch and serve blocks from. + ipfs.goOnline((err) => { + if (err) { throw err } + // Here you should be good to go and call any IPFS function + }) +}) ``` -The ES5 distributable build will be located in `lib/`. The browser distributable will be located in `dist/index.js`. +> We are working on making this init process better, see https://github.com/ipfs/js-ipfs/issues/556 for the discussion. -## Project structure +#### More to come -``` -┌───┐ ┌───────────────┐ ┌──────────────┐ -│CLI│───▶│ HTTP API ├───▶│IPFS Core Impl│ -└───┘ └───────────────┘ └──────────────┘ - △ △ △ - └──────────────└──────────┬─────────┘ - │ - ┌─────┐ - │Tests│ - └─────┘ -``` +> If you have built an example, please share it with the community by submitting a Pull Request to this repo!. -## IPFS Core implementation architecture +### API -IPFS Core is divided into separate subsystems, each of them exist in their own repo/module. The dependencies between each subsystem is assured by injection at the IPFS Core level. IPFS Core exposes an API, defined by the IPFS API spec. libp2p is the networking layer used by IPFS, but out of scope in IPFS core, follow that project [here](https://github.com/diasdavid/js-libp2p) +[![](https://github.com/ipfs/interface-ipfs-core/raw/master/img/badge.png)](https://github.com/ipfs/interface-ipfs-core) +A complete API definition will come, meanwhile, you can learn how to you use js-ipfs throught he standard interface at [![](https://img.shields.io/badge/interface--ipfs--core-API%20Docs-blue.svg)](https://github.com/ipfs/interface-ipfs-core). -``` - ▶ ┌───────────────────────────────────────────────────────────────────────────────┐ - │ IPFS Core │ - │ └───────────────────────────────────────────────────────────────────────────────┘ - │ - │ │ - │ - │ ┌──────────────┬──────────────┼────────────┬─────────────────┐ - │ │ │ │ │ - │ │ │ │ │ │ - ▼ │ ▼ │ ▼ - │ ┌──────────────────┐ │ ┌──────────────────┐ │ ┌──────────────────┐ - │ │ │ │ │ │ │ │ - │ │ Block Service │ │ │ DAG Service │ │ │ IPFS Repo │ - │ │ │ │ │ │ │ │ - │ └──────────────────┘ │ └──────────────────┘ │ └──────────────────┘ - │ │ │ │ - IPFS Core │ ▼ │ ┌────┴────┐ │ - ┌────────┐ │ ▼ ▼ │ - │ │ Block │ │ ┌────────┐┌────────┐ │ - └────────┘ │ │DAG Node││DAG Link│ │ - │ │ └────────┘└────────┘ │ - ┌──────────────────┐ │ │ ┌──────────────────┐ - │ │ │ │ │ │ │ - │ Bitswap │◀────┤ ├──────▶│ Importer │ - │ │ │ │ │ │ │ - └──────────────────┘ │ │ └──────────────────┘ - │ │ │ │ - │ │ ┌────┴────┐ - │ │ │ ▼ ▼ - │ │ ┌────────┐┌────────┐ - │ ┌──────────────────┐ │ │ │ layout ││chunker │ - │ │ │ ┌────────────┘ └────────┘└────────┘ - │ │ Files │◀────┘ │ - │ │ │ - │ └──────────────────┘ │ - ▶ │ - ▼ - ┌───────────────────────────────────────────────────────────────────────────────┐ - │ │ - │ │ - │ │ - │ libp2p │ - │ │ - │ │ - └───────────────────────────────────────────────────────────────────────────────┘ +##### [Generic API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/generic) + +##### [Block API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/block) + +##### [Object API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/object) + +##### [Config API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/config) + +##### [Files API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/files) + +##### [Swarm API](https://github.com/ipfs/interface-ipfs-core/tree/master/API/swarm) + +##### [libp2p API](https://github.com/libp2p/interface-libp2p) + +Every IPFS instance also exposes the libp2p API at `ipfs.libp2p`. The formal interface for this API hasn't been defined by you can find documentation at its implementations: + +- [libp2p-ipfs](https://github.com/ipfs/js-libp2p-ipfs) +- [libp2p-ipfs-browser](https://github.com/ipfs/js-libp2p-ipfs-browser) + +## Development + +### Clone + +```sh +> git clone https://github.com/ipfs/js-ipfs.git +> cd js-ipfs ``` -#### IPFS Core +### Install Dependencies -IPFS Core is the entry point module for IPFS. It exposes an interface defined on [IPFS Specs.](https://github.com/ipfs/specs/blob/ipfs/api/api/core/README.md) +```sh +> npm install +``` -#### Block Service +### Run Tests -Block Service uses IPFS Repo (local storage) and Bitswap (network storage) to store and fetch blocks. A block is a serialized MerkleDAG node. +```sh +> npm test -#### DAG Service +# run just IPFS core tests +> npm run test:node:core -DAG Service offers some graph language semantics on top of the MerkleDAG, composed by DAG Nodes (which can have DAG Links). It uses the Block Service as its storage and discovery service. +# run just IPFS HTTP-API tests +> npm run test:node:http -#### IPFS Repo +# run just IPFS CLI tests +> npm run test:node:cli -IPFS Repo is storage driver of IPFS, follows the [IPFS Repo Spec](https://github.com/ipfs/specs/tree/master/repo) and supports the storage of different types of files. +# run just IPFS Browser tests +> npm run test:browser +``` -#### Bitswap +### Lint -Bitswap is the exchange protocol used by IPFS to 'trade' blocks with other IPFS nodes. +*Conforming to linting rules is a prerequisite to commit to js-ipfs.* -#### Files +```sh +> npm run lint +``` -Files is the API that lets us work with IPFS objects (DAG Nodes) as if they were Unix Files. +### Build a dist version -#### Importer +``` +> npm run build +``` -Importer are a set of layouts (e.g. UnixFS) and chunkers (e.g: fixed-size, rabin, etc) that convert data to a MerkleDAG representation inside IPFS. +The ES5 distributable build will be located in `lib/`. The browser distributable will be located in `dist/index.js`. ## Packages diff --git a/package.json b/package.json index f51fa89c86..ba802a99ff 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "detect-node": "^2.0.3", "fs-pull-blob-store": "^0.3.0", "glob": "^7.0.6", - "hapi": "^15.0.3", + "hapi": "hapijs/hapi#137be35", "idb-pull-blob-store": "^0.5.1", "ipfs-api": "^10.0.0", "ipfs-bitswap": "^0.7.0", diff --git a/src/cli/commands/object/patch/add-link.js b/src/cli/commands/object/patch/add-link.js index fb8fb9d242..8ef98e7a71 100644 --- a/src/cli/commands/object/patch/add-link.js +++ b/src/cli/commands/object/patch/add-link.js @@ -5,6 +5,7 @@ const debug = require('debug') const log = debug('cli:object') const dagPB = require('ipld-dag-pb') const DAGLink = dagPB.DAGLink +const series = require('async/series') log.error = debug('cli:object:error') module.exports = { @@ -15,41 +16,72 @@ module.exports = { builder: {}, handler (argv) { - utils.getIPFS(gotIPFS) + let ipfs + let node + let nodeSize + let nodeMultihash + let nodePatched + series([ - function gotIPFS (err, ipfs) { - if (err) { - throw err - } + (cb) => { + utils.getIPFS(gotIPFS) + + function gotIPFS (err, _ipfs) { + if (err) { + cb(err) + } + ipfs = _ipfs + } + }, + (cb) => { + ipfs.object.get(argv.ref, {enc: 'base58'}, (err, _node) => { + if (err) { + cb(err) + } + node = _node + cb() + }) + }, + (cb) => { + node.size((err, size) => { + if (err) { + cb(err) + } + nodeSize = size + cb() + }) + }, + (cb) => { + node.multihash((err, multihash) => { + if (err) { + cb(err) + } + nodeMultihash = multihash + }) + }, + (cb) => { + const link = new DAGLink(argv.name, nodeSize, nodeMultihash) - ipfs.object.get(argv.ref, {enc: 'base58'}).then((linkedObj) => { - linkedObj.size((err, size) => { + ipfs.object.patch.addLink(argv.root, link, {enc: 'base58'}, (err, node) => { if (err) { - throw err + cb(err) } - linkedObj.multihash((err, multihash) => { - if (err) { - throw err - } - - const link = new DAGLink(argv.name, size, multihash) - - ipfs.object.patch.addLink(argv.root, link, {enc: 'base58'}) - .then((node) => { - node.toJSON(gotJSON) - - function gotJSON (err, nodeJSON) { - if (err) { - throw err - } - console.log(nodeJSON.Hash) - } - }) - }) + nodePatched = node + cb() }) - }).catch((err) => { + } + ], (err) => { + if (err) { throw err - }) - } + } + nodePatched.toJSON(gotJSON) + + function gotJSON (err, nodeJSON) { + if (err) { + throw err + } + console.log(nodeJSON.Hash) + } + }) } }