Merge branch 'master' into release

This commit is contained in:
Steven Allen 2020-04-28 10:24:45 -07:00
commit fd6b59bb6e
363 changed files with 11764 additions and 9404 deletions

View File

@ -6,16 +6,21 @@ aliases:
restore_gomod: &restore_gomod
restore_cache:
keys:
- v4-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-{{ .Environment.CIRCLE_JOB }}
- v4-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-
- v4-dep-{{ .Branch }}-
- v4-dep-master-
- v5-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-{{ .Environment.CIRCLE_JOB }}
- v5-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-
- v5-dep-{{ .Branch }}-
- v5-dep-master-
store_gomod: &store_gomod
save_cache:
key: v4-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-{{ .Environment.CIRCLE_JOB }}
key: v5-dep-{{ .Branch }}-{{ checksum "~/ipfs/go-ipfs/go.sum" }}-{{ .Environment.CIRCLE_JOB }}
paths:
- ~/go/pkg/mod
- ~/.cache/go-build/
only-version-tags: &only-version-tags
tags:
only: /^v[0-9].*/
branches:
ignore: /.*/
default_environment: &default_environment
SERVICE: circle-ci
@ -27,12 +32,8 @@ default_environment: &default_environment
executors:
golang:
parameters:
tag:
type: string
default: "1.12"
docker:
- image: circleci/golang:<< parameters.tag >>
- image: circleci/golang:1.13.8
working_directory: ~/ipfs/go-ipfs
environment:
<<: *default_environment
@ -57,6 +58,12 @@ executors:
IPFS_REUSEPORT: false
LIBP2P_ALLOW_WEAK_RSA_KEYS: 1
E2E_IPFSD_TYPE: go
dockerizer:
docker:
- image: circleci/golang:1.13.8
environment:
IMAGE_NAME: ipfs/go-ipfs
WIP_IMAGE_TAG: wip
jobs:
gobuild:
@ -170,22 +177,17 @@ jobs:
git -C interop log -1
- restore_cache:
keys:
- v1-interop-{{ checksum "~/ipfs/go-ipfs/interop/package-lock.json" }}
- v1-interop-
- v2-interop-{{ checksum "~/ipfs/go-ipfs/interop/package-lock.json" }}
- v2-interop-
- run:
name: Installing dependencies
command: |
npm install
working_directory: ~/ipfs/go-ipfs/interop
- save_cache:
key: v1-interop-{{ checksum "~/ipfs/go-ipfs/interop/package-lock.json" }}
key: v2-interop-{{ checksum "~/ipfs/go-ipfs/interop/package-lock.json" }}
paths:
- ~/ipfs/go-ipfs/interop/node_modules
- run:
name: Installing js-ipfs
command: |
npm install ipfs ipfs-http-client
working_directory: ~/ipfs/go-ipfs/interop
- run:
name: Installing reporting tools
command: |
@ -207,9 +209,7 @@ jobs:
- store_test_results:
path: /tmp/test-results
go-ipfs-api:
executor:
name: golang
tag: "1.13"
executor: golang
steps:
- *make_out_dirs
- attach_workspace:
@ -306,8 +306,45 @@ jobs:
key: v1-ipfs-webui-{{ checksum "~/ipfs/go-ipfs/ipfs-webui/package-lock.json" }}
paths:
- ~/ipfs/go-ipfs/ipfs-webui/node_modules
docker-build:
executor: dockerizer
steps:
- checkout
- setup_remote_docker:
version: "18.09.3"
- run:
name: Build Docker image
command: |
docker build -t $IMAGE_NAME:$WIP_IMAGE_TAG .
- run:
name: Archive Docker image
command: docker save -o go-ipfs-image.tar $IMAGE_NAME
- persist_to_workspace:
root: .
paths:
- ./go-ipfs-image.tar
docker-push:
executor: dockerizer
steps:
- checkout
- setup_remote_docker:
version: "18.09.3"
- attach_workspace:
at: /tmp/workspace
- run:
name: Load archived Docker image
command: docker load -i /tmp/workspace/go-ipfs-image.tar
- run:
name: Publish Docker Image to Docker Hub
command: |
echo "$DOCKERHUB_PASS" | docker login -u "$DOCKERHUB_USERNAME" --password-stdin
./bin/push-docker-tags.sh $(date -u +%F) "$CIRCLE_SHA1" "$CIRCLE_BRANCH" "$CIRCLE_TAG"
workflows:
version: 2
# Runs for all branches, but not on tags
# see: https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag
test:
jobs:
- gobuild
@ -327,3 +364,35 @@ workflows:
- ipfs-webui:
requires:
- build
- docker-build
- docker-push:
# Requires dockerhub credentials, from circleci context.
context: dockerhub
requires:
- docker-build
- golint
- gotest
- sharness
- interop
- go-ipfs-api
- go-ipfs-http-client
- ipfs-webui
filters:
branches:
only:
- master
- feat/stabilize-dht
# NOTE: CircleCI only builds tags if you explicitly filter for them. That
# also means tag-based jobs can only depend on other tag-based jobs, so we
# use a separate workflow because every job needs to be tagged together.
# see: https://circleci.com/docs/2.0/workflows/#executing-workflows-for-a-git-tag
docker-on-tag:
jobs:
- docker-build:
filters: *only-version-tags
- docker-push:
context: dockerhub
filters: *only-version-tags
requires:
- docker-build

2
.gitattributes vendored
View File

@ -9,6 +9,8 @@ LICENSE text eol=auto
*.png binary
*.tar binary
*.gz binary
*.xz binary
*.car binary
# Binary assets
assets/init-doc/* binary

View File

@ -1,8 +1,7 @@
---
name: 'Bug Report'
about: 'Report a bug in go-ipfs.'
labels:
- bug
labels: kind/bug, need/triage
---
#### Version information:

17
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,17 @@
blank_issues_enabled: false
contact_links:
- name: Getting Help on IPFS
url: https://ipfs.io/help
about: All information about how and where to get help on IPFS.
- name: Go-ipfs configuration reference
url: https://github.com/ipfs/go-ipfs/blob/master/docs/config.md
about: Documentation on the different configuration settings
- name: Go-ipfs experimental features docs
url: https://github.com/ipfs/go-ipfs/blob/master/docs/experimental-features.md
about: Documentation on Private Networks, Filestore and other experimental features.
- name: HTTP API Reference
url: https://docs-beta.ipfs.io/reference/http/api/#api-v0-add
about: Documentation of all go-ipfs HTTP API endpoints.
- name: IPFS Official Forum
url: https://discuss.ipfs.io
about: Please post general questions, support requests, and discussions here.

View File

@ -1,13 +1,13 @@
---
name: 'Documentation Issue'
about: 'Report missing/erroneous documentation, propose new documentation, report broken links, etc.'
labels:
- documentation
about: 'Report missing, erroneous docs, broken links or propose new go-ipfs docs'
labels: topic/docs-ipfs, need/triage
---
<!-- Problems with documentation on https://docs.ipfs.io should be reported to https://github.com/ipfs/docs -->
#### Location
<!-- In the case of missing/erroneous documentation, where is the error? If possible, a link/url would be great! -->
<!-- In the case of missing/erroneous documentation, where is the error? If possible, a link/URL would be great! -->
#### Description

View File

@ -1,12 +1,11 @@
---
name: 'Enhancement'
about: 'Suggest an improvement to an existing go-ipfs feature.'
labels:
- enhancement
labels: kind/enhancement
---
<!--
Note: If you'd like to suggest an idea related to IPFS but not specifically related to the go implementation, please file an issue at https://github.com/ipfs/ipfs instead
Note: If you'd like to suggest an idea related to IPFS but not specifically related to the Go implementation, please post in https://discuss.ipfs.io instead.
When requesting an _enhancement_, please be sure to include your motivation and try to be as specific as possible.
-->

View File

@ -1,12 +1,11 @@
---
name: 'Feature'
about: 'Suggest a new feature in go-ipfs.'
labels:
- feature
labels: kind/feature, need/triage
---
<!--
Note: If you'd like to suggest an idea related to IPFS but not specifically related to the go implementation, please file an issue at https://github.com/ipfs/ipfs instead
Note: If you'd like to suggest an idea related to IPFS but not specifically related to the Go implementation, please post in https://discuss.ipfs.io instead.
When requesting a _feature_, please be sure to include:
* Your motivation. Why do you need the feature?

View File

@ -1,11 +0,0 @@
---
name: 'Question/Support'
about: 'Ask a question about go-ipfs or request support.'
labels:
- question
- invalid
---
This bug tracker is only for actionable bug reports and feature requests. Please direct any questions to https://discuss.ipfs.io or to our Matrix (#ipfs:matrix.org) or IRC (#ipfs on freenode) channels.
If you don't get an immediate response, please keep trying.

3
.gitignore vendored
View File

@ -15,6 +15,7 @@ gx-workspace-update.json
.ipfs
bin/gx
bin/protoc-*
bin/gx*
bin/tmp
bin/gocovmerge
@ -24,3 +25,5 @@ bin/cover
vendor
.tarball
go-ipfs-source.tar.gz
docs/examples/go-ipfs-as-a-library/example-folder/Qm*
/test/sharness/t0054-dag-car-import-export-data/*.car

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "assets/dir-index-html"]
path = assets/dir-index-html
url = https://github.com/ipfs/dir-index-html.git

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,11 @@
FROM golang:1.12-stretch
MAINTAINER Lars Gierth <lgierth@ipfs.io>
FROM golang:1.13.10-buster
LABEL maintainer="Steven Allen <steven@stebalien.com>"
# Install deps
RUN apt-get update && apt-get install -y \
libssl-dev \
ca-certificates \
fuse
ENV SRC_DIR /go-ipfs
@ -10,35 +16,38 @@ RUN cd $SRC_DIR \
COPY . $SRC_DIR
# Preload an in-tree but disabled-by-default plugin by adding it to the IPFS_PLUGINS variable
# e.g. docker build --build-arg IPFS_PLUGINS="foo bar baz"
ARG IPFS_PLUGINS
# Build the thing.
# Also: fix getting HEAD commit hash via git rev-parse.
RUN cd $SRC_DIR \
&& mkdir .git/objects \
&& make build
&& make build GOTAGS=openssl IPFS_PLUGINS=$IPFS_PLUGINS
# Get su-exec, a very minimal tool for dropping privileges,
# and tini, a very minimal init daemon for containers
ENV SUEXEC_VERSION v0.2
ENV TINI_VERSION v0.16.1
RUN set -x \
&& cd /tmp \
ENV TINI_VERSION v0.19.0
RUN set -eux; \
dpkgArch="$(dpkg --print-architecture)"; \
case "${dpkgArch##*-}" in \
"amd64" | "armhf" | "arm64") tiniArch="tini-$dpkgArch" ;;\
*) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
esac; \
cd /tmp \
&& git clone https://github.com/ncopa/su-exec.git \
&& cd su-exec \
&& git checkout -q $SUEXEC_VERSION \
&& make \
&& cd /tmp \
&& wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \
&& wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/$tiniArch \
&& chmod +x tini
# Get the TLS CA certificates, they're not provided by busybox.
RUN apt-get update && apt-get install -y ca-certificates
# Install FUSE
RUN apt-get update && apt-get install -y fuse
# Now comes the actual target image, which aims to be as small as possible.
FROM busybox:1-glibc
MAINTAINER Lars Gierth <lgierth@ipfs.io>
FROM busybox:1.31.1-glibc
LABEL maintainer="Steven Allen <steven@stebalien.com>"
# Get the ipfs binary, entrypoint script, and TLS CAs from the build container.
ENV SRC_DIR /go-ipfs
@ -52,8 +61,15 @@ COPY --from=0 /etc/ssl/certs /etc/ssl/certs
# Add suid bit on fusermount so it will run properly
RUN chmod 4755 /usr/local/bin/fusermount
# Fix permissions on start_ipfs (ignore the build machine's permissions)
RUN chmod 0755 /usr/local/bin/start_ipfs
# This shared lib (part of glibc) doesn't seem to be included with busybox.
COPY --from=0 /lib/x86_64-linux-gnu/libdl-2.24.so /lib/libdl.so.2
COPY --from=0 /lib/*-linux-gnu*/libdl.so.2 /lib/
# Copy over SSL libraries.
COPY --from=0 /usr/lib/*-linux-gnu*/libssl.so* /usr/lib/
COPY --from=0 /usr/lib/*-linux-gnu*/libcrypto.so* /usr/lib/
# Swarm TCP; should be exposed to the public
EXPOSE 4001
@ -76,7 +92,7 @@ RUN mkdir /ipfs /ipns \
# Expose the fs-repo as a volume.
# start_ipfs initializes an fs-repo if none is mounted.
# Important this happens after the USER directive so permission are correct.
# Important this happens after the USER directive so permissions are correct.
VOLUME $IPFS_PATH
# The default logging level

8
GNUmakefile Normal file
View File

@ -0,0 +1,8 @@
# General tools
SHELL=PATH='$(PATH)' /bin/sh
# enable second expansion
.SECONDEXPANSION:
include Rules.mk

View File

@ -3,3 +3,6 @@ Unless otherwise noted, all code contributed prior to 2019-05-06 and not contrib
a user listed in [this signoff issue](https://github.com/ipfs/go-ipfs/issues/6302) is
licensed under MIT-only. All new contributions (and past contributions since 2019-05-06)
are licensed under a dual MIT/Apache-2.0 license.
MIT: https://www.opensource.org/licenses/mit
Apache-2.0: https://www.apache.org/licenses/license-2.0

View File

@ -1,10 +1,6 @@
# General tools
all:
@gmake $@
.PHONY: all
SHELL=PATH='$(PATH)' /bin/sh
PROTOC = protoc --gogofaster_out=. --proto_path=.:$(GOPATH)/src:$(dir $@) $<
# enable second expansion
.SECONDEXPANSION:
include Rules.mk
.DEFAULT:
@gmake $@

247
README.md
View File

@ -3,21 +3,25 @@
![banner](https://ipfs.io/ipfs/QmVk7srrwahXLNmcDYvyUEJptyoxpndnRa57YJ11L4jV26/ipfs.go.png)
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io)
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![Matrix](https://img.shields.io/badge/matrix-%23ipfs%3Amatrix.org-blue.svg?style=flat-square)](https://matrix.to/#/room/#ipfs:matrix.org)
[![IRC](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![Discord](https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord&style=flat-square)](https://discord.gg/24fmuwR)
[![GoDoc](https://img.shields.io/badge/godoc-reference-5272B4.svg?style=flat-square)](https://godoc.org/github.com/ipfs/go-ipfs)
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
[![GoDoc](https://godoc.org/github.com/ipfs/go-ipfs?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs)
[![Build Status](https://travis-ci.com/ipfs/go-ipfs.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs)
[![CircleCI](https://img.shields.io/circleci/build/github/ipfs/go-ipfs?style=flat-square)](https://circleci.com/gh/ipfs/go-ipfs)
## What is IPFS?
IPFS is a global, versioned, peer-to-peer filesystem. It combines good ideas from Git, BitTorrent, Kademlia, SFS, and the Web. It is like a single bittorrent swarm, exchanging git objects. IPFS provides an interface as simple as the HTTP web, but with permanence built in. You can also mount the world at /ipfs.
IPFS is a global, versioned, peer-to-peer filesystem. It combines good ideas from previous systems such Git, BitTorrent, Kademlia, SFS, and the Web. It is like a single bittorrent swarm, exchanging git objects. IPFS provides an interface as simple as the HTTP web, but with permanence built in. You can also mount the world at /ipfs.
For more info see: https://github.com/ipfs/ipfs.
For more info see: https://docs.ipfs.io/introduction/overview/
Please put all issues regarding:
- IPFS _design_ in the [ipfs repo issues](https://github.com/ipfs/ipfs/issues).
- Go IPFS _implementation_ in [this repo](https://github.com/ipfs/go-ipfs/issues).
Before opening an issue, consider using one of the following locations to ensure you are opening your thread in the right place:
- go-ipfs _implementation_ bugs in [this repo](https://github.com/ipfs/go-ipfs/issues).
- Documentation issues in [ipfs/docs issues](https://github.com/ipfs/docs/issues).
- IPFS _design_ in [ipfs/specs issues](https://github.com/ipfs/specs/issues).
- Exploration of new ideas in [ipfs/notes issues](https://github.com/ipfs/notes/issues).
- Ask questions and meet the rest of the community at the [IPFS Forum](https://discuss.ipfs.io).
## Table of Contents
@ -30,15 +34,17 @@ Please put all issues regarding:
- [Install Go](#install-go)
- [Download and Compile IPFS](#download-and-compile-ipfs)
- [Troubleshooting](#troubleshooting)
- [Development Dependencies](#development-dependencies)
- [Updating](#updating-go-ipfs)
- [Usage](#usage)
- [Updating go-ipfs](#updating-go-ipfs)
- [Getting Started](#getting-started)
- [Some things to try](#some-things-to-try)
- [Docker usage](#docker-usage)
- [Usage](#usage)
- [Running IPFS inside Docker](#running-ipfs-inside-docker)
- [Troubleshooting](#troubleshooting-1)
- [Packages](#packages)
- [Development](#development)
- [CLI, HTTP-API, Architecture Diagram](#cli-http-api-architecture-diagram)
- [Testing](#testing)
- [Development Dependencies](#development-dependencies)
- [Contributing](#contributing)
- [License](#license)
@ -46,17 +52,22 @@ Please put all issues regarding:
The IPFS protocol and its implementations are still in heavy development. This means that there may be problems in our protocols, or there may be mistakes in our implementations. And -- though IPFS is not production-ready yet -- many people are already running nodes in their machines. So we take security vulnerabilities very seriously. If you discover a security issue, please bring it to our attention right away!
If you find a vulnerability that may affect live deployments -- for example, by exposing a remote execution exploit -- please send your report privately to security@ipfs.io. Please DO NOT file a public issue. The GPG key for security@ipfs.io is [4B9665FB 92636D17 7C7A86D3 50AAE8A9 59B13AF3](https://pgp.mit.edu/pks/lookup?op=get&search=0x50AAE8A959B13AF3).
If you find a vulnerability that may affect live deployments -- for example, by exposing a remote execution exploit -- please send your report privately to security@ipfs.io. Please DO NOT file a public issue.
If the issue is a protocol weakness that cannot be immediately exploited or something not yet deployed, just discuss it openly.
## Install
The canonical download instructions for IPFS are over at: https://docs.ipfs.io/introduction/install/. It is **highly suggested** you follow those instructions if you are not interested in working on IPFS development.
The canonical download instructions for IPFS are over at: https://docs.ipfs.io/guides/guides/install/. It is **highly recommended** you follow those instructions if you are not interested in working on IPFS development.
### System Requirements
IPFS can run on most Linux, macOS, and Windows systems. We recommend running it on a machine with at least 2 GB of RAM (itll do fine with only one CPU core), but it should run fine with as little as 1 GB of RAM. On systems with less memory, it may not be completely stable.
IPFS can run on most Linux, macOS, and Windows systems. We recommend running it on a machine with at least 2 GB of RAM and 2 CPU cores (go-ipfs is highly parallel). On systems with less memory, it may not be completely stable.
If your system is resource constrained, we recommend:
1. Installing OpenSSL and rebuilding go-ipfs manually with `make build GOTAGS=openssl`. See the [download and compile](#download-and-compile-ipfs) section for more information on compiling go-ipfs.
2. Initializing your daemon with `ipfs init --profile=lowpower`
### Install prebuilt packages
@ -73,6 +84,7 @@ You can also download go-ipfs from this project's GitHub releases page if you ar
- [Arch Linux](#arch-linux)
- [Nix](#nix)
- [Solus](#solus)
- [Snap](#snap)
#### Arch Linux
@ -96,7 +108,7 @@ For Linux and MacOSX you can use the purely functional package manager [Nix](htt
$ nix-env -i ipfs
```
You can also install the Package by using it's attribute name, which is also `ipfs`.
You can also install the Package by using its attribute name, which is also `ipfs`.
#### Guix
@ -106,6 +118,17 @@ GNU's functional package manager, [Guix](https://www.gnu.org/software/guix/), al
$ guix package -i go-ipfs
```
#### Solus
In solus, go-ipfs is available in the main repository as
[go-ipfs](https://dev.getsol.us/source/go-ipfs/repository/master/).
```
$ sudo eopkg install go-ipfs
```
You can also install it through the Solus software center.
#### Snap
With snap, in any of the [supported Linux distributions](https://snapcraft.io/docs/core/install):
@ -114,11 +137,40 @@ With snap, in any of the [supported Linux distributions](https://snapcraft.io/do
$ sudo snap install ipfs
```
### From Windows package managers
- [Chocolatey](#chocolatey)
- [Scoop](#scoop)
#### Chocolatey
The package [ipfs](https://chocolatey.org/packages/ipfs) currently points to go-ipfs and is being maintained.
```Powershell
PS> choco install ipfs
```
#### Scoop
Scoop provides `go-ipfs` in its 'extras' bucket.
```Powershell
PS> scoop bucket add extras
PS> scoop install go-ipfs
```
### Build from Source
go-ipfs's build system requires Go 1.13 and some standard POSIX build tools:
* GNU make
* Git
* GCC (or some other go compatible C Compiler) (optional)
To build without GCC, build with `CGO_ENABLED=0` (e.g., `make build CGO_ENABLED=0`).
#### Install Go
The build process for ipfs requires Go 1.11 or higher. If you don't have it: [Download Go 1.11+](https://golang.org/dl/).
The build process for ipfs requires Go 1.12 or higher. If you don't have it: [Download Go 1.12+](https://golang.org/dl/).
You'll need to add Go's bin directories to your `$PATH` environment variable e.g., by adding these lines to your `/etc/profile` (for a system-wide installation) or `$HOME/.profile`:
@ -138,12 +190,27 @@ $ cd go-ipfs
$ make install
```
If you are building on a non-GNU system, use `gmake` in place of `make`.
Unsupported platforms (run `(g)make supported` for a list) will also need to set the `nofuse` gotag during build.
Alternatively, you can run `make build` to build the go-ipfs binary (storing it in `cmd/ipfs/ipfs`) without installing it.
**NOTE:** If you get an error along the lines of "fatal error: stdlib.h: No such file or directory", you're missing a C compiler. Either re-run `make` with `CGO_ENABLED=0` or install GCC.
##### Cross Compiling
Compiling for a different platform is as simple as running:
```
$ GOTAGS=nofuse (g)make install
make build GOOS=myTargetOS GOARCH=myTargetArchitecture
```
##### OpenSSL
To build go-ipfs with OpenSSL support, append `GOTAGS=openssl` to your `make` invocation. Building with OpenSSL should significantly reduce the background CPU usage on nodes that frequently make or receive new connections.
Note: OpenSSL requires CGO support and, by default, CGO is disabled when cross compiling. To cross compile with OpenSSL support, you must:
1. Install a compiler toolchain for the target platform.
2. Set the `CGO_ENABLED=1` environment variable.
#### Troubleshooting
- Separate [instructions are available for building on Windows](docs/windows.md).
@ -193,7 +260,26 @@ $ ipfs get /ipns/dist.ipfs.io/go-ipfs/$VERSION/go-ipfs_$VERSION_linux-arm.tar.gz
$ ipfs get /ipns/dist.ipfs.io/go-ipfs/$VERSION/go-ipfs_$VERSION_windows-amd64.zip # windows 64-bit build
```
## Usage
## Getting Started
See also: https://docs.ipfs.io/introduction/usage/
To start using IPFS, you must first initialize IPFS's config files on your
system, this is done with `ipfs init`. See `ipfs init --help` for information on
the optional arguments it takes. After initialization is complete, you can use
`ipfs mount`, `ipfs add` and any of the other commands to explore!
### Some things to try
Basic proof of 'ipfs working' locally:
echo "hello world" > hello
ipfs add hello
# This should output a hash string that looks something like:
# QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o
ipfs cat <that hash>
### Usage
```
ipfs - Global p2p merkle-dag filesystem.
@ -245,27 +331,7 @@ SUBCOMMANDS
export IPFS_PATH=/path/to/ipfsrepo
```
## Getting Started
See also: http://ipfs.io/docs/getting-started/
To start using IPFS, you must first initialize IPFS's config files on your
system, this is done with `ipfs init`. See `ipfs init --help` for information on
the optional arguments it takes. After initialization is complete, you can use
`ipfs mount`, `ipfs add` and any of the other commands to explore!
### Some things to try
Basic proof of 'ipfs working' locally:
echo "hello world" > hello
ipfs add hello
# This should output a hash string that looks something like:
# QmT78zSuBmuS4z925WZfrqQ1qHaJ56DQaTfyMUF7F8ff5o
ipfs cat <that hash>
### Docker usage
### Running IPFS inside Docker
An IPFS docker image is hosted at [hub.docker.com/r/ipfs/go-ipfs](https://hub.docker.com/r/ipfs/go-ipfs/).
To make files visible inside the container you need to mount a host directory
@ -312,6 +378,15 @@ When starting a container running ipfs for the first time with an empty data dir
docker run -d --name ipfs_host -e IPFS_PROFILE=server -v $ipfs_staging:/export -v $ipfs_data:/data/ipfs -p 4001:4001 -p 127.0.0.1:8080:8080 -p 127.0.0.1:5001:5001 ipfs/go-ipfs:latest
It is possible to initialize the container with a swarm key file (`/data/ipfs/swarm.key`) using the variables `IPFS_SWARM_KEY` and `IPFS_SWARM_KEY_FILE`. The `IPFS_SWARM_KEY` creates `swarm.key` with the contents of the variable itself, whilst `IPFS_SWARM_KEY_FILE` copies the key from a path stored in the variable. The `IPFS_SWARM_KEY_FILE` **overwrites** the key generated by `IPFS_SWARM_KEY`.
docker run -d --name ipfs_host -e IPFS_SWARM_KEY=<your swarm key> -v $ipfs_staging:/export -v $ipfs_data:/data/ipfs -p 4001:4001 -p 127.0.0.1:8080:8080 -p 127.0.0.1:5001:5001 ipfs/go-ipfs:latest
The swarm key initialization can also be done using docker secrets **(requires docker swarm or docker-compose)**:
cat your_swarm.key | docker secret create swarm_key_secret -
docker run -d --name ipfs_host --secret swarm_key_secret -e IPFS_SWARM_KEY_FILE=/run/secrets/swarm_key_secret -v $ipfs_staging:/export -v $ipfs_data:/data/ipfs -p 4001:4001 -p 127.0.0.1:8080:8080 -p 127.0.0.1:5001:5001 ipfs/go-ipfs:latest
### Troubleshooting
If you have previously installed IPFS before and you are running into problems getting a newer version to work, try deleting (or backing up somewhere else) your IPFS config directory (~/.ipfs by default) and rerunning `ipfs init`. This will reinitialize the config file to its defaults and clear out the local datastore of any bad entries.
@ -328,45 +403,62 @@ Listing of the main packages used in the IPFS ecosystem. There are also three sp
| Name | CI/Travis | Coverage | Description |
| ---------|---------|---------|--------- |
| **Libp2p** |
| [`go-libp2p`](//github.com/libp2p/go-libp2p) | [![Travis CI](https://flat.badgen.net/travis/libp2p/go-libp2p/master)](https://travis-ci.com/libp2p/go-libp2p) | [![codecov](https://codecov.io/gh/libp2p/go-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/go-libp2p) | p2p networking library |
| [`go-libp2p-pubsub`](//github.com/libp2p/go-libp2p-pubsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/go-libp2p-pubsub/master)](https://travis-ci.com/libp2p/go-libp2p-pubsub) | [![codecov](https://codecov.io/gh/libp2p/go-libp2p-pubsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/go-libp2p-pubsub) | pubsub built on libp2p |
| [`go-libp2p-kad-dht`](//github.com/libp2p/go-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/go-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/go-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/go-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/go-libp2p-kad-dht) | dht-backed router |
| [`go-libp2p-pubsub-router`](//github.com/libp2p/go-libp2p-pubsub-router) | [![Travis CI](https://flat.badgen.net/travis/libp2p/go-libp2p-pubsub-router/master)](https://travis-ci.com/libp2p/go-libp2p-pubsub-router) | [![codecov](https://codecov.io/gh/libp2p/go-libp2p-pubsub-router/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/go-libp2p-pubsub-router) | pubsub-backed router |
| **Multiformats** |
| [`go-cid`](//github.com/ipfs/go-cid) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-cid/master)](https://travis-ci.com/ipfs/go-cid) | [![codecov](https://codecov.io/gh/ipfs/go-cid/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-cid) | CID implementation |
| [`go-multiaddr`](//github.com/multiformats/go-multiaddr) | [![Travis CI](https://flat.badgen.net/travis/multiformats/go-multiaddr/master)](https://travis-ci.com/multiformats/go-multiaddr) | [![codecov](https://codecov.io/gh/multiformats/go-multiaddr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/multiformats/go-multiaddr) | multiaddr implementation |
| [`go-multihash`](//github.com/multiformats/go-multihash) | [![Travis CI](https://flat.badgen.net/travis/multiformats/go-multihash/master)](https://travis-ci.com/multiformats/go-multihash) | [![codecov](https://codecov.io/gh/multiformats/go-multihash/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/multiformats/go-multihash) | multihash implementation |
| [`go-multibase`](//github.com/multiformats/go-multibase) | [![Travis CI](https://flat.badgen.net/travis/multiformats/go-multibase/master)](https://travis-ci.com/multiformats/go-multibase) | [![codecov](https://codecov.io/gh/multiformats/go-multibase/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/multiformats/go-multibase) | mulitbase implementation |
| **Files** |
| [`go-unixfs`](//github.com/ipfs/go-unixfs) | [![Travis CI](https://travis-ci.com/ipfs/go-unixfs.svg?branch=master)](https://travis-ci.com/ipfs/go-unixfs) | [![codecov](https://codecov.io/gh/ipfs/go-unixfs/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-unixfs) | the core 'filesystem' logic |
| [`go-mfs`](//github.com/ipfs/go-mfs) | [![Travis CI](https://travis-ci.com/ipfs/go-mfs.svg?branch=master)](https://travis-ci.com/ipfs/go-mfs) | [![codecov](https://codecov.io/gh/ipfs/go-mfs/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-mfs) | a mutable filesystem editor for unixfs |
| [`go-ipfs-posinfo`](//github.com/ipfs/go-ipfs-posinfo) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-posinfo.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-posinfo) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-posinfo/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-posinfo) | helper datatypes for the filestore |
| [`go-ipfs-chunker`](//github.com/ipfs/go-ipfs-chunker) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-chunker.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-chunker) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-chunker/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-chunker) | file chunkers |
| [`go-unixfs`](//github.com/ipfs/go-unixfs) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-unixfs/master)](https://travis-ci.com/ipfs/go-unixfs) | [![codecov](https://codecov.io/gh/ipfs/go-unixfs/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-unixfs) | the core 'filesystem' logic |
| [`go-mfs`](//github.com/ipfs/go-mfs) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-mfs/master)](https://travis-ci.com/ipfs/go-mfs) | [![codecov](https://codecov.io/gh/ipfs/go-mfs/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-mfs) | a mutable filesystem editor for unixfs |
| [`go-ipfs-posinfo`](//github.com/ipfs/go-ipfs-posinfo) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-posinfo/master)](https://travis-ci.com/ipfs/go-ipfs-posinfo) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-posinfo/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-posinfo) | helper datatypes for the filestore |
| [`go-ipfs-chunker`](//github.com/ipfs/go-ipfs-chunker) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-chunker/master)](https://travis-ci.com/ipfs/go-ipfs-chunker) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-chunker/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-chunker) | file chunkers |
| **Exchange** |
| [`go-ipfs-exchange-interface`](//github.com/ipfs/go-ipfs-exchange-interface) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-exchange-interface.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-exchange-interface) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-exchange-interface/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-exchange-interface) | exchange service interface |
| [`go-ipfs-exchange-offline`](//github.com/ipfs/go-ipfs-exchange-offline) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-exchange-offline.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-exchange-offline) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-exchange-offline/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-exchange-offline) | (dummy) offline implementation of the exchange service |
| [`go-bitswap`](//github.com/ipfs/go-bitswap) | [![Travis CI](https://travis-ci.com/ipfs/go-bitswap.svg?branch=master)](https://travis-ci.com/ipfs/go-bitswap) | [![codecov](https://codecov.io/gh/ipfs/go-bitswap/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-bitswap) | bitswap protocol implementation |
| [`go-blockservice`](//github.com/ipfs/go-blockservice) | [![Travis CI](https://travis-ci.com/ipfs/go-blockservice.svg?branch=master)](https://travis-ci.com/ipfs/go-blockservice) | [![codecov](https://codecov.io/gh/ipfs/go-blockservice/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-blockservice) | service that plugs a blockstore and an exchange together |
| [`go-ipfs-exchange-interface`](//github.com/ipfs/go-ipfs-exchange-interface) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-exchange-interface/master)](https://travis-ci.com/ipfs/go-ipfs-exchange-interface) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-exchange-interface/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-exchange-interface) | exchange service interface |
| [`go-ipfs-exchange-offline`](//github.com/ipfs/go-ipfs-exchange-offline) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-exchange-offline/master)](https://travis-ci.com/ipfs/go-ipfs-exchange-offline) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-exchange-offline/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-exchange-offline) | (dummy) offline implementation of the exchange service |
| [`go-bitswap`](//github.com/ipfs/go-bitswap) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-bitswap/master)](https://travis-ci.com/ipfs/go-bitswap) | [![codecov](https://codecov.io/gh/ipfs/go-bitswap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-bitswap) | bitswap protocol implementation |
| [`go-blockservice`](//github.com/ipfs/go-blockservice) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-blockservice/master)](https://travis-ci.com/ipfs/go-blockservice) | [![codecov](https://codecov.io/gh/ipfs/go-blockservice/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-blockservice) | service that plugs a blockstore and an exchange together |
| **Datastores** |
| [`go-datastore`](//github.com/ipfs/go-datastore) | [![Travis CI](https://travis-ci.com/ipfs/go-datastore.svg?branch=master)](https://travis-ci.com/ipfs/go-datastore) | [![codecov](https://codecov.io/gh/ipfs/go-datastore/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-datastore) | datastore interfaces, adapters, and basic implementations |
| [`go-ipfs-ds-help`](//github.com/ipfs/go-ipfs-ds-help) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-ds-help.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-ds-help) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-ds-help/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-ds-help) | datastore utility functions |
| [`go-ds-flatfs`](//github.com/ipfs/go-ds-flatfs) | [![Travis CI](https://travis-ci.com/ipfs/go-ds-flatfs.svg?branch=master)](https://travis-ci.com/ipfs/go-ds-flatfs) | [![codecov](https://codecov.io/gh/ipfs/go-ds-flatfs/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ds-flatfs) | a filesystem-based datastore |
| [`go-ds-measure`](//github.com/ipfs/go-ds-measure) | [![Travis CI](https://travis-ci.com/ipfs/go-ds-measure.svg?branch=master)](https://travis-ci.com/ipfs/go-ds-measure) | [![codecov](https://codecov.io/gh/ipfs/go-ds-measure/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ds-measure) | a metric-collecting database adapter |
| [`go-ds-leveldb`](//github.com/ipfs/go-ds-leveldb) | [![Travis CI](https://travis-ci.com/ipfs/go-ds-leveldb.svg?branch=master)](https://travis-ci.com/ipfs/go-ds-leveldb) | [![codecov](https://codecov.io/gh/ipfs/go-ds-leveldb/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ds-leveldb) | a leveldb based datastore |
| [`go-ds-badger`](//github.com/ipfs/go-ds-badger) | [![Travis CI](https://travis-ci.com/ipfs/go-ds-badger.svg?branch=master)](https://travis-ci.com/ipfs/go-ds-badger) | [![codecov](https://codecov.io/gh/ipfs/go-ds-badger/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ds-badger) | a badgerdb based datastore |
| [`go-datastore`](//github.com/ipfs/go-datastore) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-datastore/master)](https://travis-ci.com/ipfs/go-datastore) | [![codecov](https://codecov.io/gh/ipfs/go-datastore/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-datastore) | datastore interfaces, adapters, and basic implementations |
| [`go-ipfs-ds-help`](//github.com/ipfs/go-ipfs-ds-help) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-ds-help/master)](https://travis-ci.com/ipfs/go-ipfs-ds-help) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-ds-help/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-ds-help) | datastore utility functions |
| [`go-ds-flatfs`](//github.com/ipfs/go-ds-flatfs) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ds-flatfs/master)](https://travis-ci.com/ipfs/go-ds-flatfs) | [![codecov](https://codecov.io/gh/ipfs/go-ds-flatfs/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ds-flatfs) | a filesystem-based datastore |
| [`go-ds-measure`](//github.com/ipfs/go-ds-measure) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ds-measure/master)](https://travis-ci.com/ipfs/go-ds-measure) | [![codecov](https://codecov.io/gh/ipfs/go-ds-measure/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ds-measure) | a metric-collecting database adapter |
| [`go-ds-leveldb`](//github.com/ipfs/go-ds-leveldb) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ds-leveldb/master)](https://travis-ci.com/ipfs/go-ds-leveldb) | [![codecov](https://codecov.io/gh/ipfs/go-ds-leveldb/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ds-leveldb) | a leveldb based datastore |
| [`go-ds-badger`](//github.com/ipfs/go-ds-badger) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ds-badger/master)](https://travis-ci.com/ipfs/go-ds-badger) | [![codecov](https://codecov.io/gh/ipfs/go-ds-badger/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ds-badger) | a badgerdb based datastore |
| **Namesys** |
| [`go-ipns`](//github.com/ipfs/go-ipns) | [![Travis CI](https://travis-ci.com/ipfs/go-ipns.svg?branch=master)](https://travis-ci.com/ipfs/go-ipns) | [![codecov](https://codecov.io/gh/ipfs/go-ipns/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipns) | IPNS datastructures and validation logic |
| [`go-ipns`](//github.com/ipfs/go-ipns) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipns/master)](https://travis-ci.com/ipfs/go-ipns) | [![codecov](https://codecov.io/gh/ipfs/go-ipns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipns) | IPNS datastructures and validation logic |
| **Repo** |
| [`go-ipfs-config`](//github.com/ipfs/go-ipfs-config) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-config.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-config) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-config/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-config) | go-ipfs config file definitions |
| [`go-fs-lock`](//github.com/ipfs/go-fs-lock) | [![Travis CI](https://travis-ci.com/ipfs/go-fs-lock.svg?branch=master)](https://travis-ci.com/ipfs/go-fs-lock) | [![codecov](https://codecov.io/gh/ipfs/go-fs-lock/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-fs-lock) | lockfile management functions |
| [`fs-repo-migrations`](//github.com/ipfs/fs-repo-migrations) | [![Travis CI](https://travis-ci.com/ipfs/fs-repo-migrations.svg?branch=master)](https://travis-ci.com/ipfs/fs-repo-migrations) | [![codecov](https://codecov.io/gh/ipfs/fs-repo-migrations/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/fs-repo-migrations) | repo migrations |
| **Blocks** |
| [`go-block-format`](//github.com/ipfs/go-block-format) | [![Travis CI](https://travis-ci.com/ipfs/go-block-format.svg?branch=master)](https://travis-ci.com/ipfs/go-block-format) | [![codecov](https://codecov.io/gh/ipfs/go-block-format/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-block-format) | block interfaces and implementations |
| [`go-ipfs-blockstore`](//github.com/ipfs/go-ipfs-blockstore) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-blockstore.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-blockstore) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-blockstore/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-blockstore) | blockstore interfaces and implementations |
| [`go-ipfs-config`](//github.com/ipfs/go-ipfs-config) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-config/master)](https://travis-ci.com/ipfs/go-ipfs-config) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-config/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-config) | go-ipfs config file definitions |
| [`go-fs-lock`](//github.com/ipfs/go-fs-lock) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-fs-lock/master)](https://travis-ci.com/ipfs/go-fs-lock) | [![codecov](https://codecov.io/gh/ipfs/go-fs-lock/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-fs-lock) | lockfile management functions |
| [`fs-repo-migrations`](//github.com/ipfs/fs-repo-migrations) | [![Travis CI](https://flat.badgen.net/travis/ipfs/fs-repo-migrations/master)](https://travis-ci.com/ipfs/fs-repo-migrations) | [![codecov](https://codecov.io/gh/ipfs/fs-repo-migrations/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/fs-repo-migrations) | repo migrations |
| **IPLD** |
| [`go-block-format`](//github.com/ipfs/go-block-format) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-block-format/master)](https://travis-ci.com/ipfs/go-block-format) | [![codecov](https://codecov.io/gh/ipfs/go-block-format/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-block-format) | block interfaces and implementations |
| [`go-ipfs-blockstore`](//github.com/ipfs/go-ipfs-blockstore) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-blockstore/master)](https://travis-ci.com/ipfs/go-ipfs-blockstore) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-blockstore/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-blockstore) | blockstore interfaces and implementations |
| [`go-ipld-format`](//github.com/ipfs/go-ipld-format) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipld-format/master)](https://travis-ci.com/ipfs/go-ipld-format) | [![codecov](https://codecov.io/gh/ipfs/go-ipld-format/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipld-format) | IPLD interfaces |
| [`go-ipld-cbor`](//github.com/ipfs/go-ipld-cbor) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipld-cbor/master)](https://travis-ci.com/ipfs/go-ipld-cbor) | [![codecov](https://codecov.io/gh/ipfs/go-ipld-cbor/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipld-cbor) | IPLD-CBOR implementation |
| [`go-ipld-git`](//github.com/ipfs/go-ipld-git) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipld-git/master)](https://travis-ci.com/ipfs/go-ipld-git) | [![codecov](https://codecov.io/gh/ipfs/go-ipld-git/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipld-git) | IPLD-Git implementation |
| [`go-merkledag`](//github.com/ipfs/go-merkledag) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-merkledag/master)](https://travis-ci.com/ipfs/go-merkledag) | [![codecov](https://codecov.io/gh/ipfs/go-merkledag/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-merkledag) | IPLD-Merkledag implementation (and then some) |
| **Commands** |
| [`go-ipfs-cmds`](//github.com/ipfs/go-ipfs-cmds) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-cmds.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-cmds) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-cmds/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-cmds) | CLI & HTTP commands library |
| [`go-ipfs-api`](//github.com/ipfs/go-ipfs-api) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-api.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-api) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-api/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-api) | a shell for the IPFS HTTP API |
| [`go-ipfs-cmds`](//github.com/ipfs/go-ipfs-cmds) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-cmds/master)](https://travis-ci.com/ipfs/go-ipfs-cmds) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-cmds/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-cmds) | CLI & HTTP commands library |
| [`go-ipfs-files`](//github.com/ipfs/go-ipfs-files) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-files/master)](https://travis-ci.com/ipfs/go-ipfs-files) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-files/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-files) | CLI & HTTP commands library |
| [`go-ipfs-api`](//github.com/ipfs/go-ipfs-api) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-api/master)](https://travis-ci.com/ipfs/go-ipfs-api) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-api/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-api) | an old, stable shell for the IPFS HTTP API |
| [`go-ipfs-http-client`](//github.com/ipfs/go-ipfs-http-client) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-http-client/master)](https://travis-ci.com/ipfs/go-ipfs-http-client) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-http-client/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-http-client) | a new, unstable shell for the IPFS HTTP API |
| [`interface-go-ipfs-core`](//github.com/ipfs/interface-go-ipfs-core) | [![Travis CI](https://flat.badgen.net/travis/ipfs/interface-go-ipfs-core/master)](https://travis-ci.com/ipfs/interface-go-ipfs-core) | [![codecov](https://codecov.io/gh/ipfs/interface-go-ipfs-core/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/interface-go-ipfs-core) | core go-ipfs API interface definitions |
| **Metrics & Logging** |
| [`go-metrics-interface`](//github.com/ipfs/go-metrics-interface) | [![Travis CI](https://travis-ci.com/ipfs/go-metrics-interface.svg?branch=master)](https://travis-ci.com/ipfs/go-metrics-interface) | [![codecov](https://codecov.io/gh/ipfs/go-metrics-interface/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-metrics-interface) | metrics collection interfaces |
| [`go-metrics-prometheus`](//github.com/ipfs/go-metrics-prometheus) | [![Travis CI](https://travis-ci.com/ipfs/go-metrics-prometheus.svg?branch=master)](https://travis-ci.com/ipfs/go-metrics-prometheus) | [![codecov](https://codecov.io/gh/ipfs/go-metrics-prometheus/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-metrics-prometheus) | prometheus-backed metrics collector |
| [`go-log`](//github.com/ipfs/go-log) | [![Travis CI](https://travis-ci.com/ipfs/go-log.svg?branch=master)](https://travis-ci.com/ipfs/go-log) | [![codecov](https://codecov.io/gh/ipfs/go-log/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-log) | logging framework |
| [`go-metrics-interface`](//github.com/ipfs/go-metrics-interface) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-metrics-interface/master)](https://travis-ci.com/ipfs/go-metrics-interface) | [![codecov](https://codecov.io/gh/ipfs/go-metrics-interface/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-metrics-interface) | metrics collection interfaces |
| [`go-metrics-prometheus`](//github.com/ipfs/go-metrics-prometheus) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-metrics-prometheus/master)](https://travis-ci.com/ipfs/go-metrics-prometheus) | [![codecov](https://codecov.io/gh/ipfs/go-metrics-prometheus/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-metrics-prometheus) | prometheus-backed metrics collector |
| [`go-log`](//github.com/ipfs/go-log) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-log/master)](https://travis-ci.com/ipfs/go-log) | [![codecov](https://codecov.io/gh/ipfs/go-log/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-log) | logging framework |
| **Generics/Utils** |
| [`go-ipfs-routing`](//github.com/ipfs/go-ipfs-routing) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-routing.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-routing) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-routing/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-routing) | routing (content, peer, value) helpers |
| [`go-ipfs-util`](//github.com/ipfs/go-ipfs-util) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-util.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-util) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-util/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-util) | the kitchen sink |
| [`go-ipfs-addr`](//github.com/ipfs/go-ipfs-addr) | [![Travis CI](https://travis-ci.com/ipfs/go-ipfs-addr.svg?branch=master)](https://travis-ci.com/ipfs/go-ipfs-addr) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-addr/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-ipfs-addr) | utility functions for parsing IPFS multiaddrs |
| [`go-ipfs-routing`](//github.com/ipfs/go-ipfs-routing) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-routing/master)](https://travis-ci.com/ipfs/go-ipfs-routing) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-routing) | routing (content, peer, value) helpers |
| [`go-ipfs-util`](//github.com/ipfs/go-ipfs-util) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-util/master)](https://travis-ci.com/ipfs/go-ipfs-util) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-util/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-util) | the kitchen sink |
| [`go-ipfs-addr`](//github.com/ipfs/go-ipfs-addr) | [![Travis CI](https://flat.badgen.net/travis/ipfs/go-ipfs-addr/master)](https://travis-ci.com/ipfs/go-ipfs-addr) | [![codecov](https://codecov.io/gh/ipfs/go-ipfs-addr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ipfs/go-ipfs-addr) | utility functions for parsing IPFS multiaddrs |
For brevity, we've omitted go-libp2p and go-ipld packages. These package tables can be found in their respective project's READMEs:
For brevity, we've omitted most go-libp2p, go-ipld, and go-multiformats packages. These package tables can be found in their respective project's READMEs:
* [go-libp2p](https://github.com/libp2p/go-libp2p#packages)
* [go-ipld](https://github.com/ipld/go-ipld#packages)
@ -384,6 +476,10 @@ Some places to get you started on the codebase:
- PubSub: https://github.com/libp2p/go-libp2p-pubsub
- [IPFS : The `Add` command demystified](https://github.com/ipfs/go-ipfs/tree/master/docs/add-code-flow.md)
### Map of go-ipfs Subsystems
**WIP**: This is a high-level architecture diagram of the various sub-systems of go-ipfs. To be updated with how they interact. Anyone who has suggestions is welcome to comment [here](https://docs.google.com/drawings/d/1OVpBT2q-NtSJqlPX3buvjYhOnWfdzb85YEsM_njesME/edit) on how we can improve this!
<img src="https://docs.google.com/drawings/d/e/2PACX-1vS_n1FvSu6mdmSirkBrIIEib2gqhgtatD9awaP2_WdrGN4zTNeg620XQd9P95WT-IvognSxIIdCM5uE/pub?w=1446&amp;h=1036">
### CLI, HTTP-API, Architecture Diagram
![](./docs/cli-http-api-core-diagram.png)
@ -419,4 +515,7 @@ You can contact us on the freenode #ipfs-dev channel or attend one of our
## License
[MIT](./LICENSE)
The go-ipfs project is dual-licensed under Apache 2.0 and MIT terms:
- Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/ipfs/go-ipfs/blob/master/LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](https://github.com/ipfs/go-ipfs/blob/master/LICENSE-MIT) or http://opensource.org/licenses/MIT)

View File

@ -5,6 +5,7 @@ DISTCLEAN :=
TEST :=
TEST_SHORT :=
GOCC ?= go
PROTOC ?= protoc
all: help # all has to be first defined target
.PHONY: all
@ -47,19 +48,12 @@ ifneq ($(filter coverage% clean distclean test/unit/gotest.junit.xml,$(MAKECMDGO
include $(dir)/Rules.mk
endif
dir := pin/internal/pb
include $(dir)/Rules.mk
dir := filestore/pb
include $(dir)/Rules.mk
# -------------------- #
# universal rules #
# -------------------- #
%.pb.go: %.proto
$(PROTOC)
%.pb.go: %.proto bin/protoc-gen-gogofaster
$(PROTOC) --gogofaster_out=. --proto_path=.:$(GOPATH)/src:$(dir $@) $<
# -------------------- #
# core targets #

View File

@ -1,6 +1,13 @@
# Assets loaded in with IPFS
## Generating docs
This directory contains the go-ipfs assets:
* Getting started documentation (`init-doc`).
* Directory listing HTML template (`dir-index-html` git submodule).
These assets are compiled into `bindata.go` with `go generate`.
## Re-generating
Do not edit the .go files directly.
@ -8,6 +15,36 @@ Instead, edit the source files and use `go generate` from within the
assets directory:
```
go get -u github.com/jteeuwen/go-bindata/...
go generate
go generate .
```
## Updating dir-index-html
Upstream: https://github.com/ipfs/dir-index-html
dir-index-html is a git submodule. To update, run the following commands from
this directory.
```bash
> git -C dir-index-html pull
> git -C dir-index-html checkout vX.Y.Z # target version
```
Then, you'll need to commit the updated submodule _before_ regenerating
`bindata.go`. Otherwise, `go generate` will checkout the checked-in version of
dir-index-html.
```bash
> git add dir-index-html
> git commit -m 'chore: update dir-index-html to vX.Y.Z'
```
Finally, re-generate the directory index HTML template and amend the previous
commit.
```bash
> go generate .
> git add bindata.go
> git commit --amend --no-edit
```

View File

@ -1,11 +1,10 @@
//go:generate go-bindata -pkg=assets -prefix=$GOPATH/src/gx/ipfs/QmT1jwrqzSMjSjLG5oBd9w4P9vXPKQksWuf5ghsE3Q88ZV init-doc $GOPATH/src/gx/ipfs/QmT1jwrqzSMjSjLG5oBd9w4P9vXPKQksWuf5ghsE3Q88ZV/dir-index-html
//go:generate git submodule update --init ./dir-index-html
//go:generate go run github.com/go-bindata/go-bindata/go-bindata -pkg=assets init-doc dir-index-html/dir-index.html dir-index-html/knownIcons.txt
//go:generate gofmt -w bindata.go
package assets
import (
"fmt"
"os"
"path/filepath"
"github.com/ipfs/go-ipfs/core"
@ -15,9 +14,6 @@ import (
files "github.com/ipfs/go-ipfs-files"
options "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/ipfs/interface-go-ipfs-core/path"
// this import keeps gx from thinking the dep isn't used
_ "github.com/ipfs/dir-index-html"
)
// initDocPaths lists the paths for the docs we want to seed during --init
@ -36,16 +32,6 @@ func SeedInitDocs(nd *core.IpfsNode) (cid.Cid, error) {
return addAssetList(nd, initDocPaths)
}
var initDirPath = filepath.Join(os.Getenv("GOPATH"), "gx", "ipfs", "QmT1jwrqzSMjSjLG5oBd9w4P9vXPKQksWuf5ghsE3Q88ZV", "dir-index-html")
var initDirIndex = []string{
filepath.Join(initDirPath, "knownIcons.txt"),
filepath.Join(initDirPath, "dir-index.html"),
}
func SeedInitDirIndex(nd *core.IpfsNode) (cid.Cid, error) {
return addAssetList(nd, initDirIndex)
}
func addAssetList(nd *core.IpfsNode, l []string) (cid.Cid, error) {
api, err := coreapi.NewCoreAPI(nd)
if err != nil {

View File

@ -12,14 +12,6 @@ func TestEmbeddedDocs(t *testing.T) {
testNFiles(initDocPaths, 5, t, "documents")
}
func TestDirIndex(t *testing.T) {
t.Skip("skipping for now, code being tested is currently unused")
// TODO: import assets during init.
// this will require figuring out how to set the right paths up for
// referencing the code from its gx path
testNFiles(initDirIndex, 2, t, "assets")
}
func testNFiles(fs []string, wantCnt int, t *testing.T, ftype string) {
if len(fs) < wantCnt {
t.Fatalf("expected %d %s. got %d", wantCnt, ftype, len(fs))

File diff suppressed because one or more lines are too long

9
assets/bindata_dep.go Normal file
View File

@ -0,0 +1,9 @@
//+build never,!never
package assets
import (
// Make sure go mod tracks these deps but avoid including them in the
// actual build.
_ "github.com/go-bindata/go-bindata/v3"
)

1
assets/dir-index-html Submodule

@ -0,0 +1 @@
Subproject commit 545a1fd882f34f8cd0ae84ece19d458d62471549

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,8 +2,8 @@ include mk/header.mk
dist_root_$(d)="/ipfs/QmPrXH9jRVwvd7r5MC5e6nV4uauQGzLk1i2647Ye9Vbbwe"
TGTS_$(d) := $(d)/gx $(d)/gx-go
DISTCLEAN += $(wildcard $(d)/gx-v*) $(wildcard $(d)/gx-go-v*) $(d)/tmp
TGTS_$(d) := $(d)/protoc
DISTCLEAN += $(d)/protoc $(d)/tmp
PATH := $(realpath $(d)):$(PATH)
@ -15,5 +15,8 @@ else
ln -s $(notdir $^) $@
endif
bin/protoc-gen-gogofaster:
$(call go-build,github.com/gogo/protobuf/protoc-gen-gogofaster)
CLEAN += $(TGTS_$(d))
include mk/footer.mk

View File

@ -29,7 +29,7 @@ PREFIX=$(expr "$0" : "\(.*\/\)") || PREFIX='./'
# Include the 'check_at_least_version' function
. ${PREFIX}check_version
# Check that the go binary exist and is in the path
# Check that the go binary exists and is in the path
GOCC=${GOCC="go"}

46
bin/collect-profiles.sh Normal file → Executable file
View File

@ -1,39 +1,51 @@
#!/usr/bin/env bash
set -x
# collect-profiles.sh
#
# Collects go profile information from a running `ipfs` daemon.
# Creates an archive including the profiles, profile graph svgs,
# ...and where available, a copy of the `ipfs` binary on the PATH.
#
# Please run this script and attach the profile archive it creates
# when reporting bugs at https://github.com/ipfs/go-ipfs/issues
set -euo pipefail
IFS=$'\n\t'
HTTP_API="${1:-localhost:5001}"
SOURCE_URL="${1:-http://127.0.0.1:5001}"
tmpdir=$(mktemp -d)
export PPROF_TMPDIR="$tmpdir"
pushd "$tmpdir"
pushd "$tmpdir" > /dev/null
if command -v ipfs > /dev/null 2>&1; then
cp "$(command -v ipfs)" ipfs
fi
echo Collecting goroutine stacks
curl -o goroutines.stacks "http://$HTTP_API"'/debug/pprof/goroutine?debug=2'
curl -s -o goroutines.stacks "$SOURCE_URL"'/debug/pprof/goroutine?debug=2'
echo Collecting goroutine profile
go tool pprof -symbolize=remote -svg -output goroutine.svg "http://$HTTP_API/debug/pprof/goroutine"
go tool pprof -symbolize=remote -svg -output goroutine.svg "$SOURCE_URL/debug/pprof/goroutine"
echo Collecting heap profile
go tool pprof -symbolize=remote -svg -output heap.svg "http://$HTTP_API/debug/pprof/heap"
go tool pprof -symbolize=remote -svg -output heap.svg "$SOURCE_URL/debug/pprof/heap"
echo "Collecting cpu profile (~30s)"
go tool pprof -symbolize=remote -svg -output cpu.svg "http://$HTTP_API/debug/pprof/profile"
go tool pprof -symbolize=remote -svg -output cpu.svg "$SOURCE_URL/debug/pprof/profile"
echo "Enabling mutex profiling"
curl -X POST -v "http://$HTTP_API"'/debug/pprof-mutex/?fraction=4'
curl -X POST "$SOURCE_URL"'/debug/pprof-mutex/?fraction=4'
echo "Waiting for mutex data to be updated (30s)"
sleep 30
curl -o mutex.txt "http://$HTTP_API"'/debug/pprof/mutex?debug=2'
go tool pprof -symbolize=remote -svg -output mutex.svg "http://$HTTP_API/debug/pprof/mutex"
curl -s -o mutex.txt "$SOURCE_URL"'/debug/pprof/mutex?debug=2'
go tool pprof -symbolize=remote -svg -output mutex.svg "$SOURCE_URL/debug/pprof/mutex"
echo "Disabling mutex profiling"
curl -X POST -v "http://$HTTP_API"'/debug/pprof-mutex/?fraction=0'
curl -X POST "$SOURCE_URL"'/debug/pprof-mutex/?fraction=0'
popd
tar cvzf "./ipfs-profile-$(uname -n)-$(date -Iseconds).tar.gz" -C "$tmpdir" .
OUTPUT_NAME=ipfs-profile-$(uname -n)-$(date +'%Y-%m-%dT%H:%M:%S%z').tar.gz
echo "Creating $OUTPUT_NAME"
popd > /dev/null
tar czf "./$OUTPUT_NAME" -C "$tmpdir" .
rm -rf "$tmpdir"

View File

@ -24,6 +24,33 @@ else
ipfs init $INIT_ARGS
ipfs config Addresses.API /ip4/0.0.0.0/tcp/5001
ipfs config Addresses.Gateway /ip4/0.0.0.0/tcp/8080
# Set up the swarm key, if provided
SWARM_KEY_FILE="$repo/swarm.key"
SWARM_KEY_PERM=0400
# Create a swarm key from a given environment variable
if [ ! -z "$IPFS_SWARM_KEY" ] ; then
echo "Copying swarm key from variable..."
echo -e "$IPFS_SWARM_KEY" >"$SWARM_KEY_FILE" || exit 1
chmod $SWARM_KEY_PERM "$SWARM_KEY_FILE"
fi
# Unset the swarm key variable
unset IPFS_SWARM_KEY
# Check during initialization if a swarm key was provided and
# copy it to the ipfs directory with the right permissions
# WARNING: This will replace the swarm key if it exists
if [ ! -z "$IPFS_SWARM_KEY_FILE" ] ; then
echo "Copying swarm key from file..."
install -m $SWARM_KEY_PERM "$IPFS_SWARM_KEY_FILE" "$SWARM_KEY_FILE" || exit 1
fi
# Unset the swarm key file variable
unset IPFS_SWARM_KEY_FILE
fi
exec ipfs "$@"

View File

@ -63,7 +63,7 @@ dep_changes() {
# resolve_commits resolves a git ref for each version.
resolve_commits() {
jq '. + {Ref: (.Version|capture("^((?<ref1>.*)\\+incompatible|v.*-[0-9]{14}-(?<ref2>[a-f0-9]{12})|(?<ref3>v.*))$") | .ref1 // .ref2 // .ref3)}'
jq '. + {Ref: (.Version|capture("^((?<ref1>.*)\\+incompatible|v.*-(0\\.)?[0-9]{14}-(?<ref2>[a-f0-9]{12})|(?<ref3>v.*))$") | .ref1 // .ref2 // .ref3)}'
}
# Generate a release log for a range of commits in a single repo.
@ -126,6 +126,7 @@ recursive_release_log() {
local repo_root="$(git rev-parse --show-toplevel)"
local package="$(go list)"
(
local result=0
local workspace="$(mktemp -d)"
trap "$(printf 'rm -rf "%q"' "$workspace")" INT TERM EXIT
cd "$workspace"
@ -153,9 +154,13 @@ recursive_release_log() {
# Compute changelogs
jq -r '"\(.Path) \(.New.Version) \(.New.Ref) \(.Old.Version) \(.Old.Ref // "")"' |
while read repo new new_ref old old_ref; do
ensure "$repo" "$new_ref"
statlog "$repo" "$old_ref" "$new_ref" >> statlog.json
local changelog="$(release_log "$repo" "$old_ref" "$new_ref")"
if ! ensure "$repo" "$new_ref"; then
result=1
local changelog="failed to fetch repo"
else
statlog "$repo" "$old_ref" "$new_ref" >> statlog.json
local changelog="$(release_log "$repo" "$old_ref" "$new_ref")"
fi
if [[ -n "$changelog" ]]; then
printf -- "- %s (%s -> %s):\n" "$repo" "$old" "$new"
echo "$changelog" | indent
@ -171,6 +176,7 @@ recursive_release_log() {
statsummary <statlog.json |
jq -s 'sort_by(.Lines) | reverse | .[]' |
jq -r '"| \(.Author) | \(.Commits) | +\(.Insertions)/-\(.Deletions) | \(.Files) |"'
return "$status"
)
}

77
bin/push-docker-tags.sh Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env bash
# push-docker-tags.sh
#
# Run from ci to tag images based on the current branch or tag name.
# A bit like dockerhub autobuild config, but somewhere we can version control it.
#
# The `docker-build` job in .circleci/config.yml builds the current commit
# in docker and tags it as ipfs/go-ipfs:wip
#
# Then the `docker-publish` job runs this script to decide what tag, if any,
# to publish to dockerhub.
#
# Usage:
# ./push-docker-tags.sh <build number> <git commit sha1> <git branch name> [git tag name] [dry run]
#
# Example:
# # dry run. pass a 5th arg to have it print what it would do rather than do it.
# ./push-docker-tags.sh $(date -u +%F) testingsha master "" dryrun
#
# # push tag for the master branch
# ./push-docker-tags.sh $(date -u +%F) testingsha master
#
# # push tag for a release tag
# ./push-docker-tags.sh $(date -u +%F) testingsha release v0.5.0
#
# # Serving suggestion in circle ci - https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables
# ./push-docker-tags.sh $(date -u +%F) "$CIRCLE_SHA1" "$CIRCLE_BRANCH" "$CIRCLE_TAG"
#
set -euo pipefail
if [[ $# -lt 3 ]] ; then
echo 'At least 3 args required. Pass 5 args for a dry run.'
echo 'Usage:'
echo './push-docker-tags.sh <build number> <git commit sha1> <git branch name> [git tag name] [dry run]'
exit 1
fi
BUILD_NUM=$1
GIT_SHA1=$2
GIT_SHA1_SHORT=$(echo "$GIT_SHA1" | cut -c 1-7)
GIT_BRANCH=$3
GIT_TAG=${4:-""}
DRY_RUN=${5:-false}
WIP_IMAGE_TAG=${WIP_IMAGE_TAG:-wip}
IMAGE_NAME=${IMAGE_NAME:-ipfs/go-ipfs}
pushTag () {
local IMAGE_TAG=$1
if [ "$DRY_RUN" != false ]; then
echo "DRY RUN! I would have tagged and pushed the following..."
echo docker tag "$IMAGE_NAME:$WIP_IMAGE_TAG" "$IMAGE_NAME:$IMAGE_TAG"
echo docker push "$IMAGE_NAME:$IMAGE_TAG"
else
echo "Tagging $IMAGE_NAME:$IMAGE_TAG and pushing to dockerhub"
docker tag "$IMAGE_NAME:$WIP_IMAGE_TAG" "$IMAGE_NAME:$IMAGE_TAG"
docker push "$IMAGE_NAME:$IMAGE_TAG"
fi
}
if [[ $GIT_TAG =~ ^v[0-9]+ ]]; then
pushTag "$GIT_TAG"
pushTag "latest"
elif [ "$GIT_BRANCH" = "feat/stabilize-dht" ]; then
pushTag "bifrost-${BUILD_NUM}-${GIT_SHA1_SHORT}"
pushTag "bifrost-latest"
elif [ "$GIT_BRANCH" = "master" ]; then
pushTag "master-${BUILD_NUM}-${GIT_SHA1_SHORT}"
pushTag "master-latest"
else
echo "Nothing to do. No docker tag defined for branch: $GIT_BRANCH, tag: $GIT_TAG"
fi

View File

@ -1,7 +1,10 @@
#!/usr/bin/env bash
set -euo pipefail
T="$(mktemp)"
find . -name '*.go' | xargs gofmt -l > "$T"
find . \
-path ./test/sharness -prune \
-o -path ./plugin/loader/preload.go -prune \
-o -name '*.go' -print0 | xargs -0 gofmt -l > "$T"
if [ -n "$(cat $T)" ]; then
echo "Following Go code is not formatted."

View File

@ -2,21 +2,20 @@
package blockstoreutil
import (
"context"
"fmt"
"io"
"github.com/ipfs/go-ipfs/pin"
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
bs "github.com/ipfs/go-ipfs-blockstore"
"github.com/ipfs/go-ipfs-pinner"
)
// RemovedBlock is used to respresent the result of removing a block.
// RemovedBlock is used to represent the result of removing a block.
// If a block was removed successfully than the Error string will be
// empty. If a block could not be removed than Error will contain the
// reason the block could not be removed. If the removal was aborted
// due to a fatal error Hash will be be empty, Error will contain the
// due to a fatal error Hash will be empty, Error will contain the
// reason, and no more results will be sent.
type RemovedBlock struct {
Hash string `json:",omitempty"`
@ -34,7 +33,7 @@ type RmBlocksOpts struct {
// It returns a channel where objects of type RemovedBlock are placed, when
// not using the Quiet option. Block removal is asynchronous and will
// skip any pinned blocks.
func RmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, cids []cid.Cid, opts RmBlocksOpts) (<-chan interface{}, error) {
func RmBlocks(ctx context.Context, blocks bs.GCBlockstore, pins pin.Pinner, cids []cid.Cid, opts RmBlocksOpts) (<-chan interface{}, error) {
// make the channel large enough to hold any result to avoid
// blocking while holding the GCLock
out := make(chan interface{}, len(cids))
@ -44,13 +43,23 @@ func RmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, cids []cid.Cid, opts RmBl
unlocker := blocks.GCLock()
defer unlocker.Unlock()
stillOkay := FilterPinned(pins, out, cids)
stillOkay := FilterPinned(ctx, pins, out, cids)
for _, c := range stillOkay {
err := blocks.DeleteBlock(c)
if err != nil && opts.Force && (err == bs.ErrNotFound || err == ds.ErrNotFound) {
// ignore non-existent blocks
} else if err != nil {
// Kept for backwards compatibility. We may want to
// remove this sometime in the future.
has, err := blocks.Has(c)
if err != nil {
out <- &RemovedBlock{Hash: c.String(), Error: err.Error()}
continue
}
if !has && !opts.Force {
out <- &RemovedBlock{Hash: c.String(), Error: bs.ErrNotFound.Error()}
continue
}
err = blocks.DeleteBlock(c)
if err != nil {
out <- &RemovedBlock{Hash: c.String(), Error: err.Error()}
} else if !opts.Quiet {
out <- &RemovedBlock{Hash: c.String()}
@ -65,9 +74,9 @@ func RmBlocks(blocks bs.GCBlockstore, pins pin.Pinner, cids []cid.Cid, opts RmBl
// out channel, with an error which indicates that the Cid is pinned.
// This function is used in RmBlocks to filter out any blocks which are not
// to be removed (because they are pinned).
func FilterPinned(pins pin.Pinner, out chan<- interface{}, cids []cid.Cid) []cid.Cid {
func FilterPinned(ctx context.Context, pins pin.Pinner, out chan<- interface{}, cids []cid.Cid) []cid.Cid {
stillOkay := make([]cid.Cid, 0, len(cids))
res, err := pins.CheckIfPinned(cids...)
res, err := pins.CheckIfPinned(ctx, cids...)
if err != nil {
out <- &RemovedBlock{Error: fmt.Sprintf("pin check failed: %s", err)}
return nil

View File

@ -1,46 +0,0 @@
FROM golang:1.11
MAINTAINER Jakub Sztandera <kubuxu@ipfs.io>
RUN apt-get update && apt-get install -y --no-install-recommends \
netcat-openbsd bash curl \
sudo \
&& rm -rf /var/lib/apt/lists/*
ENV GOBIN $GOPATH/bin
ENV SRC_PATH /go/src/github.com/ipfs/go-ipfs
RUN curl -s https://codecov.io/bash > /usr/bin/codecov && chmod +x /usr/bin/codecov \
&& go get -u github.com/Kubuxu/gocovmerge && go get -u golang.org/x/tools/cmd/cover
ENV IPFS_SKIP_COVER_BINS 1
RUN useradd user
RUN chown -R user $GOPATH
WORKDIR $SRC_PATH
COPY ./bin $SRC_PATH/bin/
COPY ./mk $SRC_PATH/mk/
RUN chown -R user $GOPATH
USER user
# install gx and gx-go
RUN make -j 4 -f bin/Rules.mk d=bin bin/gx bin/gx-go && cp bin/gx bin/gx-go $GOBIN
USER root
ENV IPFS_GX_USE_GLOBAL 1
COPY package.json $SRC_PATH/
ENV PATH $SRC_PATH/bin:$PATH
USER user
RUN make -f mk/gx.mk gx-deps
USER root
COPY . $SRC_PATH
RUN chown -R user:user $GOPATH
USER user
# mkdir .git/objects is required for git to detect repo
RUN mkdir .git/objects && make cmd/ipfs/ipfs #populate go cache
CMD ["/bin/bash", "-c", "trap : TERM INT; sleep infinity & wait"]

223
ci/Jenkinsfile vendored
View File

@ -1,223 +0,0 @@
import groovy.transform.Field
/* SETTINGS */
// in minutes
def sharness_timeout = 15
def gotest_timeout = 10
def build_timeout = 20
def check_timeout = 4
def test = 'go test -v ./...'
def fast_build_platforms = [
['linux', 'amd64'],
]
def build_platforms = [
['windows', '386'],
['windows', 'amd64'],
['linux', 'arm'],
['linux', 'arm64'],
['linux', '386'],
['darwin', '386'],
['darwin', 'amd64'],
['freebsd', 'amd64']
]
/* PIPELINE UTILS */
def setupStep(nodeLabel, f) {
node(label: nodeLabel) {
def ps = nodeLabel != 'windows' ? '/' : '\\'
def psep = nodeLabel != 'windows' ? ':' : ';'
def root = tool name: '1.11', type: 'go'
def jobNameArr = "${JOB_NAME}"
def jobName = jobNameArr.split("/")[0..1].join(nodeLabel != 'windows' ? '/' : '\\\\').toLowerCase()
def subName = jobNameArr.split("/")[2].toLowerCase()
def originalWs = "${WORKSPACE}"
ws("${originalWs}${ps}src${ps}github.com${ps}${jobName}") {
def goEnv = ["GOROOT=${root}", "GOPATH=${originalWs}", "SUBNAME=${subName}", "PATH=$PATH${psep}${root}${ps}bin${psep}${originalWs}${ps}bin"]
withEnv(goEnv) {
checkout scm
def run = nodeLabel != 'windows' ? this.&sh : this.&bat
try {
f(run)
} finally {
cleanWs()
}
}
}
}
}
def gobuild_step = { list ->
setupStep('linux') { run ->
timeout(time: build_timeout, unit: 'MINUTES') {
run "make gx-deps"
list.each { platform ->
timeout(time: check_timeout, unit: 'MINUTES') {
withEnv(["GOOS=${platform[0]}", "GOARCH=${platform[1]}"]) {
run "go build -i -ldflags=\"-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=${env.SUBNAME}-${env.BUILD_NUMBER}\" -o cmd/ipfs/ipfs github.com/ipfs/go-ipfs/cmd/ipfs"
run "cp cmd/ipfs/ipfs cmd/ipfs/dist; cd cmd/ipfs/dist; tar -czvf ../go-ipfs_${env.GOOS}-${env.GOARCH}-${env.SUBNAME}-${env.BUILD_NUMBER}.tar.gz ."
archiveArtifacts artifacts: "cmd/ipfs/go-ipfs_${env.GOOS}-${env.GOARCH}-${env.SUBNAME}-${env.BUILD_NUMBER}.tar.gz", fingerprint: true
}
}
}
}
}
}
def sharness_step = { run, osname, makeargs, ignore ->
timeout(time: sharness_timeout, unit: 'MINUTES') {
run "make gx-deps"
try {
run "make -j12 ${makeargs} test/sharness/test-results/sharness.xml CONTINUE_ON_S_FAILURE=1 TEST_NO_FUSE=1 TEST_NO_DOCKER=1"
try {
// archive trash directories if any
run "tar -czf sharnessTrashDirs-${osname}.tar.gz test/sharness/trash\\ *"
archiveArtifacts artifacts: "sharnessTrashDirs-${osname}.tar.gz", fingerprint: true
} catch (_) {}
} catch (err) {
throw err
} finally {
if (!ignore) {
junit allowEmptyResults: true, testResults: 'test/sharness/test-results/sharness.xml'
}
}
}
}
def gotest_step = { run ->
timeout(time: gotest_timeout, unit: 'MINUTES') {
run "make gx-deps"
try {
run test + ' -tags="nofuse" 2>&1 | tee output'
run 'cat output | go-junit-report > junit-report-linux.xml'
} catch (err) {
throw err
} finally {
junit allowEmptyResults: true, testResults: 'junit-report-*.xml'
}
}
}
/* PIPELINE */
ansiColor('xterm') { withEnv(['TERM=xterm-color']) {
stage('Checks') {
parallel(
'go fmt': {
setupStep('linux') { run ->
timeout(time: check_timeout, unit: 'MINUTES') {
run 'make test_go_fmt'
}
}
},
'go vet': {
setupStep('linux') { run ->
timeout(time: check_timeout, unit: 'MINUTES') {
run 'make gx-deps'
run 'go vet ./...'
}
}
},
'go build': {
gobuild_step(fast_build_platforms)
},
'gx deps dupes': {
setupStep('linux') { run ->
timeout(time: check_timeout, unit: 'MINUTES') {
run 'make gx-deps'
run 'test -z "$(./bin/gx deps dupes)"'
}
}
}
)
}
stage('Tests') {
parallel(
'go build (other platforms)': {
gobuild_step(build_platforms)
},
windows: {
setupStep('windows') { run ->
timeout(time: gotest_timeout, unit: 'MINUTES') {
run 'go get -v github.com/jstemmer/go-junit-report github.com/whyrusleeping/gx github.com/whyrusleeping/gx-go'
run "gx install --global"
try {
run test + ' -tags="nofuse" > output & type output'
run 'type output | go-junit-report > junit-report-windows.xml'
} catch (err) {
throw err
} finally {
/* IGNORE TEST FAILS */
/* junit allowEmptyResults: true, testResults: 'junit-report-*.xml' */
}
}
}
},
linux: {
setupStep('linux') { run ->
run 'go get -v github.com/jstemmer/go-junit-report'
gotest_step(run)
}
},
linuxSharness: {
setupStep('linux') { run ->
sharness_step(run, 'linux', '-Otarget', false)
}
},
linux32: {
setupStep('linux') { run ->
run 'go get -v github.com/jstemmer/go-junit-report'
withEnv(["GOARCH=386"]) {
gotest_step(run)
}
}
},
linux32Sharness: {
setupStep('linux') { run ->
withEnv(["GOARCH=386", "TEST_NO_PLUGIN=1"]) {
sharness_step(run, 'linux', '-Otarget', false)
}
}
},
//macOS: {
// setupStep('macos') { run ->
// sharness_step(run, 'macos', '', true)
// }
//},
//macSharness: {
// setupStep('macos') { run ->
// timeout(time: sharness_timeout, unit: 'MINUTES') {
// run 'go get -v github.com/jstemmer/go-junit-report'
// run "make gx-deps"
// try {
// run "make -j12 test/sharness/test-results/sharness.xml CONTINUE_ON_S_FAILURE=1 TEST_NO_FUSE=1"
// } catch (err) {
// throw err
// } finally {
// /* IGNORE TEST FAILS */
// /* junit allowEmptyResults: true, testResults: 'test/sharness/test-results/sharness.xml' */
// }
// }
// }
//},
)
}
}}

View File

@ -12,32 +12,37 @@ import (
"sort"
"sync"
multierror "github.com/hashicorp/go-multierror"
version "github.com/ipfs/go-ipfs"
config "github.com/ipfs/go-ipfs-config"
cserial "github.com/ipfs/go-ipfs-config/serialize"
utilmain "github.com/ipfs/go-ipfs/cmd/ipfs/util"
oldcmds "github.com/ipfs/go-ipfs/commands"
"github.com/ipfs/go-ipfs/core"
commands "github.com/ipfs/go-ipfs/core/commands"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
corehttp "github.com/ipfs/go-ipfs/core/corehttp"
corerepo "github.com/ipfs/go-ipfs/core/corerepo"
libp2p "github.com/ipfs/go-ipfs/core/node/libp2p"
nodeMount "github.com/ipfs/go-ipfs/fuse/node"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
sockets "github.com/libp2p/go-socket-activation"
"github.com/hashicorp/go-multierror"
"github.com/ipfs/go-ipfs-cmds"
cmds "github.com/ipfs/go-ipfs-cmds"
mprome "github.com/ipfs/go-metrics-prometheus"
goprocess "github.com/jbenet/goprocess"
ma "github.com/multiformats/go-multiaddr"
"github.com/multiformats/go-multiaddr-net"
"github.com/prometheus/client_golang/prometheus"
manet "github.com/multiformats/go-multiaddr-net"
prometheus "github.com/prometheus/client_golang/prometheus"
promauto "github.com/prometheus/client_golang/prometheus/promauto"
)
const (
adjustFDLimitKwd = "manage-fdlimit"
enableGCKwd = "enable-gc"
initOptionKwd = "init"
initConfigOptionKwd = "init-config"
initProfileOptionKwd = "init-profile"
ipfsMountKwd = "mount-ipfs"
ipnsMountKwd = "mount-ipns"
@ -48,6 +53,7 @@ const (
routingOptionSupernodeKwd = "supernode"
routingOptionDHTClientKwd = "dhtclient"
routingOptionDHTKwd = "dht"
routingOptionDHTServerKwd = "dhtserver"
routingOptionNoneKwd = "none"
routingOptionDefaultKwd = "default"
unencryptTransportKwd = "disable-transport-encryption"
@ -116,7 +122,7 @@ You can setup CORS headers the same way:
Shutdown
To shutdown the daemon, send a SIGINT signal to it (e.g. by pressing 'Ctrl-C')
To shut down the daemon, send a SIGINT signal to it (e.g. by pressing 'Ctrl-C')
or send a SIGTERM signal to it (e.g. with 'kill'). It may take a while for the
daemon to shutdown gracefully, but it can be killed forcibly by sending a
second signal.
@ -154,6 +160,7 @@ Headers.
Options: []cmds.Option{
cmds.BoolOption(initOptionKwd, "Initialize ipfs with default settings if not already initialized"),
cmds.StringOption(initConfigOptionKwd, "Path to existing configuration file to be loaded during --init"),
cmds.StringOption(initProfileOptionKwd, "Configuration profiles to apply for --init. See ipfs init --help for more"),
cmds.StringOption(routingOptionKwd, "Overrides the routing option").WithDefault(routingOptionDefaultKwd),
cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem"),
@ -222,24 +229,27 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
// check transport encryption flag.
unencrypted, _ := req.Options[unencryptTransportKwd].(bool)
if unencrypted {
log.Warningf(`Running with --%s: All connections are UNENCRYPTED.
log.Warnf(`Running with --%s: All connections are UNENCRYPTED.
You will not be able to connect to regular encrypted networks.`, unencryptTransportKwd)
}
// first, whether user has provided the initialization flag. we may be
// running in an uninitialized state.
initialize, _ := req.Options[initOptionKwd].(bool)
if initialize {
if initialize && !fsrepo.IsInitialized(cctx.ConfigRoot) {
cfgLocation, _ := req.Options[initConfigOptionKwd].(string)
profiles, _ := req.Options[initProfileOptionKwd].(string)
var conf *config.Config
cfg := cctx.ConfigRoot
if !fsrepo.IsInitialized(cfg) {
profiles, _ := req.Options[initProfileOptionKwd].(string)
err := initWithDefaults(os.Stdout, cfg, profiles)
if err != nil {
if cfgLocation != "" {
if conf, err = cserial.Load(cfgLocation); err != nil {
return err
}
}
if err = doInit(os.Stdout, cctx.ConfigRoot, false, nBitsForKeypairDefault, profiles, conf); err != nil {
return err
}
}
// acquire the repo lock _before_ constructing a node. we need to make
@ -283,11 +293,6 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
// fail before we get to that. It can't hurt to close it twice.
defer repo.Close()
cfg, err := cctx.GetConfig()
if err != nil {
return err
}
offline, _ := req.Options[offlineKwd].(bool)
ipnsps, _ := req.Options[enableIPNSPubSubKwd].(bool)
pubsub, _ := req.Options[enablePubSubKwd].(bool)
@ -326,6 +331,8 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
ncfg.Routing = libp2p.DHTClientOption
case routingOptionDHTKwd:
ncfg.Routing = libp2p.DHTOption
case routingOptionDHTServerKwd:
ncfg.Routing = libp2p.DHTServerOption
case routingOptionNoneKwd:
ncfg.Routing = libp2p.NilRouterOption
default:
@ -364,11 +371,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
// Start "core" plugins. We want to do this *before* starting the HTTP
// API as the user may be relying on these plugins.
api, err := coreapi.NewCoreAPI(node)
if err != nil {
return err
}
err = cctx.Plugins.Start(api)
err = cctx.Plugins.Start(node)
if err != nil {
return err
}
@ -397,31 +400,41 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
return err
}
// construct http gateway - if it is set in the config
var gwErrc <-chan error
if len(cfg.Addresses.Gateway) > 0 {
var err error
gwErrc, err = serveHTTPGateway(req, cctx)
if err != nil {
return err
}
// construct http gateway
gwErrc, err := serveHTTPGateway(req, cctx)
if err != nil {
return err
}
// Add ipfs version info to prometheus metrics
var ipfsInfoMetric = promauto.NewGaugeVec(prometheus.GaugeOpts{
Name: "ipfs_info",
Help: "IPFS version information.",
}, []string{"version", "commit"})
// Setting to 1 lets us multiply it with other stats to add the version labels
ipfsInfoMetric.With(prometheus.Labels{
"version": version.CurrentVersionNumber,
"commit": version.CurrentCommit,
}).Set(1)
// initialize metrics collector
prometheus.MustRegister(&corehttp.IpfsNodeCollector{Node: node})
// The daemon is *finally* ready.
fmt.Printf("Daemon is ready\n")
notifyReady()
// Give the user some immediate feedback when they hit C-c
go func() {
<-req.Context.Done()
notifyStopping()
fmt.Println("Received interrupt signal, shutting down...")
fmt.Println("(Hit ctrl-c again to force-shutdown the daemon.)")
}()
// collect long-running errors and block for shutdown
// TODO(cryptix): our fuse currently doesnt follow this pattern for graceful shutdown
// TODO(cryptix): our fuse currently doesn't follow this pattern for graceful shutdown
var errs error
for err := range merge(apiErrc, gwErrc, gcErrc) {
if err != nil {
@ -439,6 +452,11 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
return nil, fmt.Errorf("serveHTTPApi: GetConfig() failed: %s", err)
}
listeners, err := sockets.TakeListeners("io.ipfs.api")
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: socket activation failed: %s", err)
}
apiAddrs := make([]string, 0, 2)
apiAddr, _ := req.Options[commands.ApiOption].(string)
if apiAddr == "" {
@ -447,11 +465,18 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
apiAddrs = append(apiAddrs, apiAddr)
}
listeners := make([]manet.Listener, 0, len(apiAddrs))
listenerAddrs := make(map[string]bool, len(listeners))
for _, listener := range listeners {
listenerAddrs[string(listener.Multiaddr().Bytes())] = true
}
for _, addr := range apiAddrs {
apiMaddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", apiAddr, err)
return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", addr, err)
}
if listenerAddrs[string(apiMaddr.Bytes())] {
continue
}
apiLis, err := manet.Listen(apiMaddr)
@ -459,13 +484,20 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
return nil, fmt.Errorf("serveHTTPApi: manet.Listen(%s) failed: %s", apiMaddr, err)
}
// we might have listened to /tcp/0 - lets see what we are listing on
apiMaddr = apiLis.Multiaddr()
fmt.Printf("API server listening on %s\n", apiMaddr)
fmt.Printf("WebUI: http://%s/webui\n", apiLis.Addr())
listenerAddrs[string(apiMaddr.Bytes())] = true
listeners = append(listeners, apiLis)
}
for _, listener := range listeners {
// we might have listened to /tcp/0 - let's see what we are listing on
fmt.Printf("API server listening on %s\n", listener.Multiaddr())
// Browsers require TCP.
switch listener.Addr().Network() {
case "tcp", "tcp4", "tcp6":
fmt.Printf("WebUI: http://%s/webui\n", listener.Addr())
}
}
// by default, we don't let you load arbitrary ipfs objects through the api,
// because this would open up the api to scripting vulnerabilities.
// only the webui objects are allowed.
@ -564,36 +596,51 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
writable = cfg.Gateway.Writable
}
listeners, err := sockets.TakeListeners("io.ipfs.gateway")
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: socket activation failed: %s", err)
}
listenerAddrs := make(map[string]bool, len(listeners))
for _, listener := range listeners {
listenerAddrs[string(listener.Multiaddr().Bytes())] = true
}
gatewayAddrs := cfg.Addresses.Gateway
listeners := make([]manet.Listener, 0, len(gatewayAddrs))
for _, addr := range gatewayAddrs {
gatewayMaddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: invalid gateway address: %q (err: %s)", addr, err)
}
if listenerAddrs[string(gatewayMaddr.Bytes())] {
continue
}
gwLis, err := manet.Listen(gatewayMaddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: manet.Listen(%s) failed: %s", gatewayMaddr, err)
}
// we might have listened to /tcp/0 - lets see what we are listing on
gatewayMaddr = gwLis.Multiaddr()
if writable {
fmt.Printf("Gateway (writable) server listening on %s\n", gatewayMaddr)
} else {
fmt.Printf("Gateway (readonly) server listening on %s\n", gatewayMaddr)
}
listenerAddrs[string(gatewayMaddr.Bytes())] = true
listeners = append(listeners, gwLis)
}
// we might have listened to /tcp/0 - let's see what we are listing on
gwType := "readonly"
if writable {
gwType = "writable"
}
for _, listener := range listeners {
fmt.Printf("Gateway (%s) server listening on %s\n", gwType, listener.Multiaddr())
}
cmdctx := *cctx
cmdctx.Gateway = true
var opts = []corehttp.ServeOption{
corehttp.MetricsCollectionOption("gateway"),
corehttp.IPNSHostnameOption(),
corehttp.HostnameOption(),
corehttp.GatewayOption(writable, "/ipfs", "/ipns"),
corehttp.VersionOption(),
corehttp.CheckVersionOption(),
@ -601,7 +648,7 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
}
if cfg.Experimental.P2pHttpProxy {
opts = append(opts, corehttp.ProxyOption())
opts = append(opts, corehttp.P2PProxyOption())
}
if len(cfg.Gateway.RootRedirect) > 0 {
@ -726,7 +773,11 @@ func YesNoPrompt(prompt string) bool {
}
func printVersion() {
fmt.Printf("go-ipfs version: %s-%s\n", version.CurrentVersionNumber, version.CurrentCommit)
v := version.CurrentVersionNumber
if version.CurrentCommit != "" {
v += "-" + version.CurrentCommit
}
fmt.Printf("go-ipfs version: %s\n", v)
fmt.Printf("Repo version: %d\n", fsrepo.RepoVersion)
fmt.Printf("System version: %s\n", runtime.GOARCH+"/"+runtime.GOOS)
fmt.Printf("Golang version: %s\n", runtime.Version())

15
cmd/ipfs/daemon_linux.go Normal file
View File

@ -0,0 +1,15 @@
// +build linux
package main
import (
daemon "github.com/coreos/go-systemd/v22/daemon"
)
func notifyReady() {
_, _ = daemon.SdNotify(false, daemon.SdNotifyReady)
}
func notifyStopping() {
_, _ = daemon.SdNotify(false, daemon.SdNotifyStopping)
}

7
cmd/ipfs/daemon_other.go Normal file
View File

@ -0,0 +1,7 @@
// +build !linux
package main
func notifyReady() {}
func notifyStopping() {}

27
cmd/ipfs/dist/LICENSE vendored
View File

@ -1,21 +1,8 @@
The MIT License (MIT)
This project is transitioning from an MIT-only license to a dual MIT/Apache-2.0 license.
Unless otherwise noted, all code contributed prior to 2019-05-06 and not contributed by
a user listed in [this signoff issue](https://github.com/ipfs/go-ipfs/issues/6302) is
licensed under MIT-only. All new contributions (and past contributions since 2019-05-06)
are licensed under a dual MIT/Apache-2.0 license.
Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
MIT: https://www.opensource.org/licenses/mit
Apache-2.0: https://www.apache.org/licenses/license-2.0

5
cmd/ipfs/dist/LICENSE-APACHE vendored Normal file
View File

@ -0,0 +1,5 @@
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

19
cmd/ipfs/dist/LICENSE-MIT vendored Normal file
View File

@ -0,0 +1,19 @@
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -13,7 +13,7 @@ binpaths="/usr/local/bin /usr/bin"
is_write_perm_missing=""
for binpath in $binpaths; do
if mv "$bin" "$binpath/$bin" ; then
if mv "$bin" "$binpath/ipfs" ; then
echo "Moved $bin to $binpath"
exit 0
else

View File

@ -7,7 +7,7 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
assets "github.com/ipfs/go-ipfs/assets"
@ -16,9 +16,9 @@ import (
namesys "github.com/ipfs/go-ipfs/namesys"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
"github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs-config"
"github.com/ipfs/go-ipfs-files"
cmds "github.com/ipfs/go-ipfs-cmds"
config "github.com/ipfs/go-ipfs-config"
files "github.com/ipfs/go-ipfs-files"
)
const (
@ -28,6 +28,10 @@ const (
profileOptionName = "profile"
)
var errRepoExists = errors.New(`ipfs configuration file already exists!
Reinitializing would overwrite your keys.
`)
var initCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Initializes ipfs config file.",
@ -102,31 +106,30 @@ environment variable:
}
}
profile, _ := req.Options[profileOptionName].(string)
var profiles []string
if profile != "" {
profiles = strings.Split(profile, ",")
}
profiles, _ := req.Options[profileOptionName].(string)
return doInit(os.Stdout, cctx.ConfigRoot, empty, nBitsForKeypair, profiles, conf)
},
}
var errRepoExists = errors.New(`ipfs configuration file already exists!
Reinitializing would overwrite your keys.
`)
func initWithDefaults(out io.Writer, repoRoot string, profile string) error {
var profiles []string
if profile != "" {
profiles = strings.Split(profile, ",")
func applyProfiles(conf *config.Config, profiles string) error {
if profiles == "" {
return nil
}
return doInit(out, repoRoot, false, nBitsForKeypairDefault, profiles, nil)
for _, profile := range strings.Split(profiles, ",") {
transformer, ok := config.Profiles[profile]
if !ok {
return fmt.Errorf("invalid configuration profile: %s", profile)
}
if err := transformer.Transform(conf); err != nil {
return err
}
}
return nil
}
func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, confProfiles []string, conf *config.Config) error {
func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, confProfiles string, conf *config.Config) error {
if _, err := fmt.Fprintf(out, "initializing IPFS node at %s\n", repoRoot); err != nil {
return err
}
@ -147,15 +150,8 @@ func doInit(out io.Writer, repoRoot string, empty bool, nBitsForKeypair int, con
}
}
for _, profile := range confProfiles {
transformer, ok := config.Profiles[profile]
if !ok {
return fmt.Errorf("invalid configuration profile: %s", profile)
}
if err := transformer.Transform(conf); err != nil {
return err
}
if err := applyProfiles(conf, confProfiles); err != nil {
return err
}
if err := fsrepo.Init(repoRoot, conf); err != nil {
@ -175,7 +171,7 @@ func checkWritable(dir string) error {
_, err := os.Stat(dir)
if err == nil {
// dir exists, make sure we can write to it
testfile := path.Join(dir, "test")
testfile := filepath.Join(dir, "test")
fi, err := os.Create(testfile)
if err != nil {
if os.IsPermission(err) {

View File

@ -6,8 +6,9 @@ import (
"errors"
"fmt"
"math/rand"
"net"
"net/http"
"os"
"path/filepath"
"runtime/pprof"
"strings"
"time"
@ -21,11 +22,10 @@ import (
repo "github.com/ipfs/go-ipfs/repo"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
osh "github.com/Kubuxu/go-os-helper"
"github.com/ipfs/go-ipfs-cmds"
cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs-cmds/cli"
"github.com/ipfs/go-ipfs-cmds/http"
"github.com/ipfs/go-ipfs-config"
cmdhttp "github.com/ipfs/go-ipfs-cmds/http"
config "github.com/ipfs/go-ipfs-config"
u "github.com/ipfs/go-ipfs-util"
logging "github.com/ipfs/go-log"
loggables "github.com/libp2p/go-libp2p-loggables"
@ -47,18 +47,7 @@ const (
)
func loadPlugins(repoPath string) (*loader.PluginLoader, error) {
pluginpath := filepath.Join(repoPath, "plugins")
// check if repo is accessible before loading plugins
var plugins *loader.PluginLoader
ok, err := checkPermissions(repoPath)
if err != nil {
return nil, err
}
if !ok {
pluginpath = ""
}
plugins, err = loader.NewPluginLoader(pluginpath)
plugins, err := loader.NewPluginLoader(repoPath)
if err != nil {
return nil, fmt.Errorf("error loading plugins: %s", err)
}
@ -124,6 +113,9 @@ func mainRet() int {
os.Args[1] = "--help"
}
}
} else if insideGUI() { // if no args were passed, and we're in a GUI environment
// launch the daemon instead of launching a ghost window
os.Args = append(os.Args, "daemon", "--init")
}
// output depends on executable name passed in os.Args
@ -183,6 +175,10 @@ func mainRet() int {
return 0
}
func insideGUI() bool {
return util.InsideGUI()
}
func checkDebug(req *cmds.Request) {
// check if user wants to debug. option OR env var.
debug, _ := req.Options["debug"].(bool)
@ -195,39 +191,114 @@ func checkDebug(req *cmds.Request) {
}
}
func apiAddrOption(req *cmds.Request) (ma.Multiaddr, error) {
apiAddrStr, apiSpecified := req.Options[corecmds.ApiOption].(string)
if !apiSpecified {
return nil, nil
}
return ma.NewMultiaddr(apiAddrStr)
}
func makeExecutor(req *cmds.Request, env interface{}) (cmds.Executor, error) {
exe := cmds.NewExecutor(req.Root)
cctx := env.(*oldcmds.Context)
details := commandDetails(req.Path)
client, err := commandShouldRunOnDaemon(*details, req, env.(*oldcmds.Context))
// Check if the command is disabled.
if details.cannotRunOnClient && details.cannotRunOnDaemon {
return nil, fmt.Errorf("command disabled: %v", req.Path)
}
// Can we just run this locally?
if !details.cannotRunOnClient && details.doesNotUseRepo {
return exe, nil
}
// Get the API option from the commandline.
apiAddr, err := apiAddrOption(req)
if err != nil {
return nil, err
}
var exctr cmds.Executor
if client != nil && !req.Command.External {
exctr = client.(cmds.Executor)
} else {
exctr = cmds.NewExecutor(req.Root)
// Require that the command be run on the daemon when the API flag is
// passed (unless we're trying to _run_ the daemon).
daemonRequested := apiAddr != nil && req.Command != daemonCmd
// Run this on the client if required.
if details.cannotRunOnDaemon || req.Command.External {
if daemonRequested {
// User requested that the command be run on the daemon but we can't.
// NOTE: We drop this check for the `ipfs daemon` command.
return nil, errors.New("api flag specified but command cannot be run on the daemon")
}
return exe, nil
}
return exctr, nil
}
func checkPermissions(path string) (bool, error) {
_, err := os.Open(path)
if os.IsNotExist(err) {
// repo does not exist yet - don't load plugins, but also don't fail
return false, nil
}
if os.IsPermission(err) {
// repo is not accessible. error out.
return false, fmt.Errorf("error opening repository at %s: permission denied", path)
// Finally, look in the repo for an API file.
if apiAddr == nil {
var err error
apiAddr, err = fsrepo.APIAddr(cctx.ConfigRoot)
switch err {
case nil, repo.ErrApiNotRunning:
default:
return nil, err
}
}
return true, nil
// Still no api specified? Run it on the client or fail.
if apiAddr == nil {
if details.cannotRunOnClient {
return nil, fmt.Errorf("command must be run on the daemon: %v", req.Path)
}
return exe, nil
}
// Resolve the API addr.
apiAddr, err = resolveAddr(req.Context, apiAddr)
if err != nil {
return nil, err
}
network, host, err := manet.DialArgs(apiAddr)
if err != nil {
return nil, err
}
// Construct the executor.
opts := []cmdhttp.ClientOpt{
cmdhttp.ClientWithAPIPrefix(corehttp.APIPath),
}
// Fallback on a local executor if we (a) have a repo and (b) aren't
// forcing a daemon.
if !daemonRequested && fsrepo.IsInitialized(cctx.ConfigRoot) {
opts = append(opts, cmdhttp.ClientWithFallback(exe))
}
switch network {
case "tcp", "tcp4", "tcp6":
case "unix":
path := host
host = "unix"
opts = append(opts, cmdhttp.ClientWithHTTPClient(&http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial("unix", path)
},
},
}))
default:
return nil, fmt.Errorf("unsupported API address: %s", apiAddr)
}
return cmdhttp.NewClient(host, opts...), nil
}
// commandDetails returns a command's details for the command given by |path|.
func commandDetails(path []string) *cmdDetails {
func commandDetails(path []string) cmdDetails {
if len(path) == 0 {
// special case root command
return cmdDetails{doesNotUseRepo: true}
}
var details cmdDetails
// find the last command in path that has a cmdDetailsMap entry
for i := range path {
@ -235,67 +306,7 @@ func commandDetails(path []string) *cmdDetails {
details = cmdDetails
}
}
return &details
}
// commandShouldRunOnDaemon determines, from command details, whether a
// command ought to be executed on an ipfs daemon.
//
// It returns a client if the command should be executed on a daemon and nil if
// it should be executed on a client. It returns an error if the command must
// NOT be executed on either.
func commandShouldRunOnDaemon(details cmdDetails, req *cmds.Request, cctx *oldcmds.Context) (http.Client, error) {
path := req.Path
// root command.
if len(path) < 1 {
return nil, nil
}
if details.cannotRunOnClient && details.cannotRunOnDaemon {
return nil, fmt.Errorf("command disabled: %s", path[0])
}
if details.doesNotUseRepo && details.canRunOnClient() {
return nil, nil
}
// at this point need to know whether api is running. we defer
// to this point so that we don't check unnecessarily
// did user specify an api to use for this command?
apiAddrStr, _ := req.Options[corecmds.ApiOption].(string)
client, err := getAPIClient(req.Context, cctx.ConfigRoot, apiAddrStr)
if err == repo.ErrApiNotRunning {
if apiAddrStr != "" && req.Command != daemonCmd {
// if user SPECIFIED an api, and this cmd is not daemon
// we MUST use it. so error out.
return nil, err
}
// ok for api not to be running
} else if err != nil { // some other api error
return nil, err
}
if client != nil {
if details.cannotRunOnDaemon {
// check if daemon locked. legacy error text, for now.
log.Debugf("Command cannot run on daemon. Checking if daemon is locked")
if daemonLocked, _ := fsrepo.LockedByOtherProcess(cctx.ConfigRoot); daemonLocked {
return nil, cmds.ClientError("ipfs daemon is running. please stop it to run this command")
}
return nil, nil
}
return client, nil
}
if details.cannotRunOnClient {
return nil, cmds.ClientError("must run on the ipfs daemon")
}
return nil, nil
return details
}
func getRepoPath(req *cmds.Request) (string, error) {
@ -366,67 +377,6 @@ func profileIfEnabled() (func(), error) {
return func() {}, nil
}
var apiFileErrorFmt string = `Failed to parse '%[1]s/api' file.
error: %[2]s
If you're sure go-ipfs isn't running, you can just delete it.
`
var checkIPFSUnixFmt = "Otherwise check:\n\tps aux | grep ipfs"
var checkIPFSWinFmt = "Otherwise check:\n\ttasklist | findstr ipfs"
// getAPIClient checks the repo, and the given options, checking for
// a running API service. if there is one, it returns a client.
// otherwise, it returns errApiNotRunning, or another error.
func getAPIClient(ctx context.Context, repoPath, apiAddrStr string) (http.Client, error) {
var apiErrorFmt string
switch {
case osh.IsUnix():
apiErrorFmt = apiFileErrorFmt + checkIPFSUnixFmt
case osh.IsWindows():
apiErrorFmt = apiFileErrorFmt + checkIPFSWinFmt
default:
apiErrorFmt = apiFileErrorFmt
}
var addr ma.Multiaddr
var err error
if len(apiAddrStr) != 0 {
addr, err = ma.NewMultiaddr(apiAddrStr)
if err != nil {
return nil, err
}
if len(addr.Protocols()) == 0 {
return nil, fmt.Errorf("multiaddr doesn't provide any protocols")
}
} else {
addr, err = fsrepo.APIAddr(repoPath)
if err == repo.ErrApiNotRunning {
return nil, err
}
if err != nil {
return nil, fmt.Errorf(apiErrorFmt, repoPath, err.Error())
}
}
if len(addr.Protocols()) == 0 {
return nil, fmt.Errorf(apiErrorFmt, repoPath, "multiaddr doesn't provide any protocols")
}
return apiClientForAddr(ctx, addr)
}
func apiClientForAddr(ctx context.Context, addr ma.Multiaddr) (http.Client, error) {
addr, err := resolveAddr(ctx, addr)
if err != nil {
return nil, err
}
_, host, err := manet.DialArgs(addr)
if err != nil {
return nil, err
}
return http.NewClient(host, http.ClientWithAPIPrefix(corehttp.APIPath)), nil
}
func resolveAddr(ctx context.Context, addr ma.Multiaddr) (ma.Multiaddr, error) {
ctx, cancelFunc := context.WithTimeout(ctx, 10*time.Second)
defer cancelFunc()

7
cmd/ipfs/util/ui.go Normal file
View File

@ -0,0 +1,7 @@
//+build !windows
package util
func InsideGUI() bool {
return false
}

View File

@ -0,0 +1,18 @@
package util
import "golang.org/x/sys/windows"
func InsideGUI() bool {
conhostInfo := &windows.ConsoleScreenBufferInfo{}
if err := windows.GetConsoleScreenBufferInfo(windows.Stdout, conhostInfo); err != nil {
return false
}
if (conhostInfo.CursorPosition.X | conhostInfo.CursorPosition.Y) == 0 {
// console cursor has not moved prior to our execution
// high probability that we're not in a terminal
return true
}
return false
}

View File

@ -66,8 +66,8 @@ func ManageFdLimit() (changed bool, newLimit uint64, err error) {
// the soft limit is the value that the kernel enforces for the
// corresponding resource
// the hard limit acts as a ceiling for the soft limit
// an unprivileged process may only set it's soft limit to a
// alue in the range from 0 up to the hard limit
// an unprivileged process may only set its soft limit to a
// value in the range from 0 up to the hard limit
err = setLimit(targetLimit, targetLimit)
switch err {
case nil:
@ -82,7 +82,7 @@ func ManageFdLimit() (changed bool, newLimit uint64, err error) {
// set the soft value
err = setLimit(targetLimit, hard)
if err != nil {
err = fmt.Errorf("error setting ulimit wihout hard limit: %s", err)
err = fmt.Errorf("error setting ulimit without hard limit: %s", err)
break
}
newLimit = targetLimit

View File

@ -10,7 +10,6 @@ package main
import (
"context"
"errors"
"flag"
"fmt"
"io"
@ -20,9 +19,9 @@ import (
"syscall"
logging "github.com/ipfs/go-log"
ci "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
ci "github.com/libp2p/go-libp2p-core/crypto"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
pstoremem "github.com/libp2p/go-libp2p-peerstore/pstoremem"
secio "github.com/libp2p/go-libp2p-secio"
)
@ -113,8 +112,8 @@ func main() {
}
func setupPeer(a args) (peer.ID, pstore.Peerstore, error) {
if a.keybits < 1024 {
return "", nil, errors.New("bitsize less than 1024 is considered unsafe")
if a.keybits < ci.MinRsaKeyBits {
return "", nil, ci.ErrRsaKeyTooSmall
}
out("generating key pair...")

View File

@ -57,6 +57,12 @@ func (c *Context) GetNode() (*core.IpfsNode, error) {
return nil, errors.New("nil ConstructNode function")
}
c.node, err = c.ConstructNode()
if err == nil {
// Pre-load the config from the repo to avoid re-parsing it from disk.
if cfg, err := c.node.Repo.Config(); err != nil {
c.config = cfg
}
}
}
return c.node, err
}

View File

@ -9,17 +9,15 @@ import (
"sync"
"time"
config "github.com/ipfs/go-ipfs-config"
logging "github.com/ipfs/go-log"
"github.com/jbenet/goprocess"
"github.com/jbenet/goprocess/context"
"github.com/jbenet/goprocess/periodic"
"github.com/libp2p/go-libp2p-host"
"github.com/libp2p/go-libp2p-loggables"
"github.com/libp2p/go-libp2p-net"
"github.com/libp2p/go-libp2p-peer"
"github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-libp2p-routing"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/peerstore"
"github.com/libp2p/go-libp2p-core/routing"
)
var log = logging.Logger("bootstrap")
@ -51,7 +49,7 @@ type BootstrapConfig struct {
// BootstrapPeers is a function that returns a set of bootstrap peers
// for the bootstrap process to use. This makes it possible for clients
// to control the peers the process uses at any moment.
BootstrapPeers func() []peerstore.PeerInfo
BootstrapPeers func() []peer.AddrInfo
}
// DefaultBootstrapConfig specifies default sane parameters for bootstrapping.
@ -61,9 +59,9 @@ var DefaultBootstrapConfig = BootstrapConfig{
ConnectionTimeout: (30 * time.Second) / 3, // Perod / 3
}
func BootstrapConfigWithPeers(pis []peerstore.PeerInfo) BootstrapConfig {
func BootstrapConfigWithPeers(pis []peer.AddrInfo) BootstrapConfig {
cfg := DefaultBootstrapConfig
cfg.BootstrapPeers = func() []peerstore.PeerInfo {
cfg.BootstrapPeers = func() []peer.AddrInfo {
return pis
}
return cfg
@ -73,7 +71,7 @@ func BootstrapConfigWithPeers(pis []peerstore.PeerInfo) BootstrapConfig {
// check the number of open connections and -- if there are too few -- initiate
// connections to well-known bootstrap peers. It also kicks off subsystem
// bootstrapping (i.e. routing).
func Bootstrap(id peer.ID, host host.Host, rt routing.IpfsRouting, cfg BootstrapConfig) (io.Closer, error) {
func Bootstrap(id peer.ID, host host.Host, rt routing.Routing, cfg BootstrapConfig) (io.Closer, error) {
// make a signal to wait for one bootstrap round to complete.
doneWithRound := make(chan struct{})
@ -81,16 +79,14 @@ func Bootstrap(id peer.ID, host host.Host, rt routing.IpfsRouting, cfg Bootstrap
if len(cfg.BootstrapPeers()) == 0 {
// We *need* to bootstrap but we have no bootstrap peers
// configured *at all*, inform the user.
log.Warning("no bootstrap nodes configured: go-ipfs may have difficulty connecting to the network")
log.Warn("no bootstrap nodes configured: go-ipfs may have difficulty connecting to the network")
}
// the periodic bootstrap function -- the connection supervisor
periodic := func(worker goprocess.Process) {
ctx := goprocessctx.OnClosingContext(worker)
defer log.EventBegin(ctx, "periodicBootstrap", id).Done()
if err := bootstrapRound(ctx, host, cfg); err != nil {
log.Event(ctx, "bootstrapError", id, loggables.Error(err))
log.Debugf("%s bootstrap error: %s", id, err)
}
@ -127,7 +123,6 @@ func bootstrapRound(ctx context.Context, host host.Host, cfg BootstrapConfig) er
// determine how many bootstrap connections to open
connected := host.Network().Peers()
if len(connected) >= cfg.MinPeerThreshold {
log.Event(ctx, "bootstrapSkip", id)
log.Debugf("%s core bootstrap skipped -- connected to %d (> %d) nodes",
id, len(connected), cfg.MinPeerThreshold)
return nil
@ -135,9 +130,9 @@ func bootstrapRound(ctx context.Context, host host.Host, cfg BootstrapConfig) er
numToDial := cfg.MinPeerThreshold - len(connected)
// filter out bootstrap nodes we are already connected to
var notConnected []peerstore.PeerInfo
var notConnected []peer.AddrInfo
for _, p := range peers {
if host.Network().Connectedness(p.ID) != net.Connected {
if host.Network().Connectedness(p.ID) != network.Connected {
notConnected = append(notConnected, p)
}
}
@ -151,12 +146,11 @@ func bootstrapRound(ctx context.Context, host host.Host, cfg BootstrapConfig) er
// connect to a random susbset of bootstrap candidates
randSubset := randomSubsetOfPeers(notConnected, numToDial)
defer log.EventBegin(ctx, "bootstrapStart", id).Done()
log.Debugf("%s bootstrapping to %d nodes: %s", id, numToDial, randSubset)
return bootstrapConnect(ctx, host, randSubset)
}
func bootstrapConnect(ctx context.Context, ph host.Host, peers []peerstore.PeerInfo) error {
func bootstrapConnect(ctx context.Context, ph host.Host, peers []peer.AddrInfo) error {
if len(peers) < 1 {
return ErrNotEnoughBootstrapPeers
}
@ -171,19 +165,16 @@ func bootstrapConnect(ctx context.Context, ph host.Host, peers []peerstore.PeerI
// Also, performed asynchronously for dial speed.
wg.Add(1)
go func(p peerstore.PeerInfo) {
go func(p peer.AddrInfo) {
defer wg.Done()
defer log.EventBegin(ctx, "bootstrapDial", ph.ID(), p.ID).Done()
log.Debugf("%s bootstrapping to %s", ph.ID(), p.ID)
ph.Peerstore().AddAddrs(p.ID, p.Addrs, peerstore.PermanentAddrTTL)
if err := ph.Connect(ctx, p); err != nil {
log.Event(ctx, "bootstrapDialFailed", p.ID)
log.Debugf("failed to bootstrap with %v: %s", p.ID, err)
errs <- err
return
}
log.Event(ctx, "bootstrapDialSuccess", p.ID)
log.Infof("bootstrapped with %v", p.ID)
}(p)
}
@ -205,37 +196,14 @@ func bootstrapConnect(ctx context.Context, ph host.Host, peers []peerstore.PeerI
return nil
}
func randomSubsetOfPeers(in []peerstore.PeerInfo, max int) []peerstore.PeerInfo {
func randomSubsetOfPeers(in []peer.AddrInfo, max int) []peer.AddrInfo {
if max > len(in) {
max = len(in)
}
out := make([]peerstore.PeerInfo, max)
out := make([]peer.AddrInfo, max)
for i, val := range rand.Perm(len(in))[:max] {
out[i] = in[val]
}
return out
}
type Peers []config.BootstrapPeer
func (bpeers Peers) ToPeerInfos() []peerstore.PeerInfo {
pinfos := make(map[peer.ID]*peerstore.PeerInfo)
for _, bootstrap := range bpeers {
pinfo, ok := pinfos[bootstrap.ID()]
if !ok {
pinfo = new(peerstore.PeerInfo)
pinfos[bootstrap.ID()] = pinfo
pinfo.ID = bootstrap.ID()
}
pinfo.Addrs = append(pinfo.Addrs, bootstrap.Transport())
}
var peers []peerstore.PeerInfo
for _, pinfo := range pinfos {
peers = append(peers, *pinfo)
}
return peers
}

View File

@ -1,56 +1,25 @@
package bootstrap
import (
"fmt"
"testing"
config "github.com/ipfs/go-ipfs-config"
pstore "github.com/libp2p/go-libp2p-peerstore"
testutil "github.com/libp2p/go-testutil"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-core/test"
)
func TestSubsetWhenMaxIsGreaterThanLengthOfSlice(t *testing.T) {
var ps []pstore.PeerInfo
var ps []peer.AddrInfo
sizeofSlice := 100
for i := 0; i < sizeofSlice; i++ {
pid, err := testutil.RandPeerID()
pid, err := test.RandPeerID()
if err != nil {
t.Fatal(err)
}
ps = append(ps, pstore.PeerInfo{ID: pid})
ps = append(ps, peer.AddrInfo{ID: pid})
}
out := randomSubsetOfPeers(ps, 2*sizeofSlice)
if len(out) != len(ps) {
t.Fail()
}
}
func TestMultipleAddrsPerPeer(t *testing.T) {
var bsps []config.BootstrapPeer
for i := 0; i < 10; i++ {
pid, err := testutil.RandPeerID()
if err != nil {
t.Fatal(err)
}
addr := fmt.Sprintf("/ip4/127.0.0.1/tcp/5001/ipfs/%s", pid.Pretty())
bsp1, err := config.ParseBootstrapPeer(addr)
if err != nil {
t.Fatal(err)
}
addr = fmt.Sprintf("/ip4/127.0.0.1/udp/5002/utp/ipfs/%s", pid.Pretty())
bsp2, err := config.ParseBootstrapPeer(addr)
if err != nil {
t.Fatal(err)
}
bsps = append(bsps, bsp1, bsp2)
}
pinfos := Peers.ToPeerInfos(bsps)
if len(pinfos) != len(bsps)/2 {
t.Fatal("expected fewer peers")
}
}

View File

@ -3,18 +3,35 @@ package core
import (
"context"
"sync"
"github.com/ipfs/go-metrics-interface"
"go.uber.org/fx"
"time"
"github.com/ipfs/go-ipfs/core/bootstrap"
"github.com/ipfs/go-ipfs/core/node"
"github.com/ipfs/go-metrics-interface"
"go.uber.org/fx"
)
// from https://stackoverflow.com/a/59348871
type valueContext struct {
context.Context
}
func (valueContext) Deadline() (deadline time.Time, ok bool) { return }
func (valueContext) Done() <-chan struct{} { return nil }
func (valueContext) Err() error { return nil }
type BuildCfg = node.BuildCfg // Alias for compatibility until we properly refactor the constructor interface
// NewNode constructs and returns an IpfsNode using the given cfg.
func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) {
// save this context as the "lifetime" ctx.
lctx := ctx
// derive a new context that ignores cancellations from the lifetime ctx.
ctx, cancel := context.WithCancel(valueContext{ctx})
// add a metrics scope.
ctx = metrics.CtxScope(ctx, "ipfs")
n := &IpfsNode{
@ -33,18 +50,27 @@ func NewNode(ctx context.Context, cfg *BuildCfg) (*IpfsNode, error) {
n.stop = func() error {
once.Do(func() {
stopErr = app.Stop(context.Background())
if stopErr != nil {
log.Error("failure on stop: ", stopErr)
}
// Cancel the context _after_ the app has stopped.
cancel()
})
return stopErr
}
n.IsOnline = cfg.Online
go func() {
// Note that some services use contexts to signal shutting down, which is
// very suboptimal. This needs to be here until that's addressed somehow
<-ctx.Done()
err := n.stop()
if err != nil {
log.Error("failure on stop: ", err)
// Shut down the application if the lifetime context is canceled.
// NOTE: we _should_ stop the application by calling `Close()`
// on the process. But we currently manage everything with contexts.
select {
case <-lctx.Done():
err := n.stop()
if err != nil {
log.Error("failure on stop: ", err)
}
case <-ctx.Done():
}
}()

View File

@ -11,7 +11,7 @@ import (
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs-files"
files "github.com/ipfs/go-ipfs-files"
coreiface "github.com/ipfs/interface-go-ipfs-core"
"github.com/ipfs/interface-go-ipfs-core/options"
mh "github.com/multiformats/go-multihash"
@ -80,9 +80,9 @@ how to break files into blocks. Blocks with same content can
be deduplicated. Different chunking strategies will produce different
hashes for the same file. The default is a fixed block size of
256 * 1024 bytes, 'size-262144'. Alternatively, you can use the
Rabin fingerprint chunker for content defined chunking by specifying
rabin-[min]-[avg]-[max] (where min/avg/max refer to the desired
chunk sizes in bytes), e.g. 'rabin-262144-524288-1048576'.
Buzhash or Rabin fingerprint chunker for content defined chunking by
specifying buzhash or rabin-[min]-[avg]-[max] (where min/avg/max refer
to the desired chunk sizes in bytes), e.g. 'rabin-262144-524288-1048576'.
The following examples use very small byte sizes to demonstrate the
properties of the different chunkers on a small file. You'll likely
@ -102,6 +102,11 @@ You can now check what blocks have been created by:
QmY6yj1GsermExDXoosVE3aSPxdMNYr6aKuw3nA8LoWPRS 2059
QmerURi9k4XzKCaaPbsK6BL5pMEjF7PGphjDvkkjDtsVf3 868
QmQB28iwSriSUSMqG2nXDTLtdPHgWb4rebBrU7Q1j4vxPv 338
Finally, a note on hash determinism. While not guaranteed, adding the same
file/directory with the same flags will almost always result in the same output
hash. However, almost all of the flags provided by this command (other than pin,
only-hash, and progress/status related flags) will change the final hash.
`,
},
@ -113,6 +118,8 @@ You can now check what blocks have been created by:
cmds.OptionDerefArgs, // a builtin option that resolves passed in filesystem links (--dereference-args)
cmds.OptionStdinName, // a builtin option that optionally allows wrapping stdin into a named file
cmds.OptionHidden,
cmds.OptionIgnore,
cmds.OptionIgnoreRules,
cmds.BoolOption(quietOptionName, "q", "Write minimal output."),
cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
cmds.BoolOption(silentOptionName, "Write no output."),
@ -120,7 +127,7 @@ You can now check what blocks have been created by:
cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."),
cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."),
cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes] or rabin-[min]-[avg]-[max]").WithDefault("size-262144"),
cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm, size-[bytes], rabin-[min]-[avg]-[max] or buzhash").WithDefault("size-262144"),
cmds.BoolOption(pinOptionName, "Pin this object when adding.").WithDefault(true),
cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"),
cmds.BoolOption(noCopyOptionName, "Add the file using filestore. Implies raw-leaves. (experimental)"),
@ -286,7 +293,7 @@ You can now check what blocks have been created by:
go func() {
size, err := req.Files.Size()
if err != nil {
log.Warningf("error getting files size: %s", err)
log.Warnf("error getting files size: %s", err)
// see comment above
return
}

View File

@ -12,7 +12,7 @@ import (
decision "github.com/ipfs/go-bitswap/decision"
cidutil "github.com/ipfs/go-cidutil"
cmds "github.com/ipfs/go-ipfs-cmds"
peer "github.com/libp2p/go-libp2p-peer"
peer "github.com/libp2p/go-libp2p-core/peer"
)
var BitswapCmd = &cmds.Command{
@ -60,7 +60,7 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`,
pstr, found := req.Options[peerOptionName].(string)
if found {
pid, err := peer.IDB58Decode(pstr)
pid, err := peer.Decode(pstr)
if err != nil {
return err
}
@ -195,7 +195,7 @@ prints the ledger associated with a given peer.
return e.TypeErr(bs, nd.Exchange)
}
partner, err := peer.IDB58Decode(req.Arguments[0])
partner, err := peer.Decode(req.Arguments[0])
if err != nil {
return err
}
@ -233,7 +233,7 @@ Trigger reprovider to announce our data to network.
return ErrNotOnline
}
err = nd.Reprovider.Trigger(req.Context)
err = nd.Provider.Reprovide(req.Context)
if err != nil {
return err
}

View File

@ -6,6 +6,8 @@ import (
"io"
"os"
files "github.com/ipfs/go-ipfs-files"
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
@ -129,7 +131,7 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
},
Arguments: []cmds.Argument{
cmds.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(),
cmds.FileArg("data", true, true, "The data to be stored as an IPFS block.").EnableStdin(),
},
Options: []cmds.Option{
cmds.StringOption(blockFormatOptionName, "f", "cid format for blocks to be created with."),
@ -143,11 +145,6 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
return err
}
file, err := cmdenv.GetFileArg(req.Files.Entries())
if err != nil {
return err
}
mhtype, _ := req.Options[mhtypeOptionName].(string)
mhtval, ok := mh.Names[mhtype]
if !ok {
@ -170,18 +167,31 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
pin, _ := req.Options[pinOptionName].(bool)
p, err := api.Block().Put(req.Context, file,
options.Block.Hash(mhtval, mhlen),
options.Block.Format(format),
options.Block.Pin(pin))
if err != nil {
return err
it := req.Files.Entries()
for it.Next() {
file := files.FileFromEntry(it)
if file == nil {
return errors.New("expected a file")
}
p, err := api.Block().Put(req.Context, file,
options.Block.Hash(mhtval, mhlen),
options.Block.Format(format),
options.Block.Pin(pin))
if err != nil {
return err
}
err = res.Emit(&BlockStat{
Key: p.Path().Cid().String(),
Size: p.Size(),
})
if err != nil {
return err
}
}
return cmds.EmitOnce(res, &BlockStat{
Key: p.Path().Cid().String(),
Size: p.Size(),
})
return it.Err()
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, bs *BlockStat) error {

View File

@ -2,6 +2,7 @@ package commands
import (
"errors"
"fmt"
"io"
"sort"
@ -11,6 +12,8 @@ import (
cmds "github.com/ipfs/go-ipfs-cmds"
config "github.com/ipfs/go-ipfs-config"
peer "github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
)
type BootstrapOutput struct {
@ -64,26 +67,13 @@ in the bootstrap list).
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
deflt, _ := req.Options[defaultOptionName].(bool)
var inputPeers []config.BootstrapPeer
if deflt {
// parse separately for meaningful, correct error.
defltPeers, err := config.DefaultBootstrapPeers()
if err != nil {
return err
}
inputPeers = defltPeers
} else {
inputPeers := config.DefaultBootstrapAddresses
if !deflt {
if err := req.ParseBodyArgs(); err != nil {
return err
}
parsedPeers, err := config.ParseBootstrapPeers(req.Arguments)
if err != nil {
return err
}
inputPeers = parsedPeers
inputPeers = req.Arguments
}
if len(inputPeers) == 0 {
@ -110,7 +100,7 @@ in the bootstrap list).
return err
}
return cmds.EmitOnce(res, &BootstrapOutput{config.BootstrapPeerStrings(added)})
return cmds.EmitOnce(res, &BootstrapOutput{added})
},
Type: BootstrapOutput{},
Encoders: cmds.EncoderMap{
@ -127,11 +117,6 @@ var bootstrapAddDefaultCmd = &cmds.Command{
in the bootstrap list).`,
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
defltPeers, err := config.DefaultBootstrapPeers()
if err != nil {
return err
}
cfgRoot, err := cmdenv.GetConfigRoot(env)
if err != nil {
return err
@ -148,12 +133,12 @@ in the bootstrap list).`,
return err
}
added, err := bootstrapAdd(r, cfg, defltPeers)
added, err := bootstrapAdd(r, cfg, config.DefaultBootstrapAddresses)
if err != nil {
return err
}
return cmds.EmitOnce(res, &BootstrapOutput{config.BootstrapPeerStrings(added)})
return cmds.EmitOnce(res, &BootstrapOutput{added})
},
Type: BootstrapOutput{},
Encoders: cmds.EncoderMap{
@ -201,26 +186,20 @@ var bootstrapRemoveCmd = &cmds.Command{
return err
}
var removed []config.BootstrapPeer
var removed []string
if all {
removed, err = bootstrapRemoveAll(r, cfg)
} else {
if err := req.ParseBodyArgs(); err != nil {
return err
}
input, perr := config.ParseBootstrapPeers(req.Arguments)
if perr != nil {
return perr
}
removed, err = bootstrapRemove(r, cfg, input)
removed, err = bootstrapRemove(r, cfg, req.Arguments)
}
if err != nil {
return err
}
return cmds.EmitOnce(res, &BootstrapOutput{config.BootstrapPeerStrings(removed)})
return cmds.EmitOnce(res, &BootstrapOutput{removed})
},
Type: BootstrapOutput{},
Encoders: cmds.EncoderMap{
@ -257,7 +236,7 @@ var bootstrapRemoveAllCmd = &cmds.Command{
return err
}
return cmds.EmitOnce(res, &BootstrapOutput{config.BootstrapPeerStrings(removed)})
return cmds.EmitOnce(res, &BootstrapOutput{removed})
},
Type: BootstrapOutput{},
Encoders: cmds.EncoderMap{
@ -315,23 +294,36 @@ func bootstrapWritePeers(w io.Writer, prefix string, peers []string) error {
return nil
}
func bootstrapAdd(r repo.Repo, cfg *config.Config, peers []config.BootstrapPeer) ([]config.BootstrapPeer, error) {
func bootstrapAdd(r repo.Repo, cfg *config.Config, peers []string) ([]string, error) {
for _, p := range peers {
m, err := ma.NewMultiaddr(p)
if err != nil {
return nil, err
}
tpt, p2ppart := ma.SplitLast(m)
if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P {
return nil, fmt.Errorf("invalid bootstrap address: %s", p)
}
if tpt == nil {
return nil, fmt.Errorf("bootstrap address without a transport: %s", p)
}
}
addedMap := map[string]struct{}{}
addedList := make([]config.BootstrapPeer, 0, len(peers))
addedList := make([]string, 0, len(peers))
// re-add cfg bootstrap peers to rm dupes
bpeers := cfg.Bootstrap
cfg.Bootstrap = nil
// add new peers
for _, peer := range peers {
s := peer.String()
for _, s := range peers {
if _, found := addedMap[s]; found {
continue
}
cfg.Bootstrap = append(cfg.Bootstrap, s)
addedList = append(addedList, peer)
addedList = append(addedList, s)
addedMap[s] = struct{}{}
}
@ -352,27 +344,56 @@ func bootstrapAdd(r repo.Repo, cfg *config.Config, peers []config.BootstrapPeer)
return addedList, nil
}
func bootstrapRemove(r repo.Repo, cfg *config.Config, toRemove []config.BootstrapPeer) ([]config.BootstrapPeer, error) {
removed := make([]config.BootstrapPeer, 0, len(toRemove))
keep := make([]config.BootstrapPeer, 0, len(cfg.Bootstrap))
func bootstrapRemove(r repo.Repo, cfg *config.Config, toRemove []string) ([]string, error) {
removed := make([]peer.AddrInfo, 0, len(toRemove))
keep := make([]peer.AddrInfo, 0, len(cfg.Bootstrap))
toRemoveAddr, err := config.ParseBootstrapPeers(toRemove)
if err != nil {
return nil, err
}
toRemoveMap := make(map[peer.ID][]ma.Multiaddr, len(toRemoveAddr))
for _, addr := range toRemoveAddr {
toRemoveMap[addr.ID] = addr.Addrs
}
peers, err := cfg.BootstrapPeers()
if err != nil {
return nil, err
}
for _, peer := range peers {
found := false
for _, peer2 := range toRemove {
if peer.Equal(peer2) {
found = true
removed = append(removed, peer)
break
for _, p := range peers {
addrs, ok := toRemoveMap[p.ID]
// not in the remove set?
if !ok {
keep = append(keep, p)
continue
}
// remove the entire peer?
if len(addrs) == 0 {
removed = append(removed, p)
continue
}
var (
keptAddrs, removedAddrs []ma.Multiaddr
)
// remove specific addresses
filter:
for _, addr := range p.Addrs {
for _, addr2 := range addrs {
if addr.Equal(addr2) {
removedAddrs = append(removedAddrs, addr)
continue filter
}
}
keptAddrs = append(keptAddrs, addr)
}
if len(removedAddrs) > 0 {
removed = append(removed, peer.AddrInfo{ID: p.ID, Addrs: removedAddrs})
}
if !found {
keep = append(keep, peer)
if len(keptAddrs) > 0 {
keep = append(keep, peer.AddrInfo{ID: p.ID, Addrs: keptAddrs})
}
}
cfg.SetBootstrapPeers(keep)
@ -381,10 +402,10 @@ func bootstrapRemove(r repo.Repo, cfg *config.Config, toRemove []config.Bootstra
return nil, err
}
return removed, nil
return config.BootstrapPeerStrings(removed), nil
}
func bootstrapRemoveAll(r repo.Repo, cfg *config.Config) ([]config.BootstrapPeer, error) {
func bootstrapRemoveAll(r repo.Repo, cfg *config.Config) ([]string, error) {
removed, err := cfg.BootstrapPeers()
if err != nil {
return nil, err
@ -394,8 +415,7 @@ func bootstrapRemoveAll(r repo.Repo, cfg *config.Config) ([]config.BootstrapPeer
if err := r.SetConfig(cfg); err != nil {
return nil, err
}
return removed, nil
return config.BootstrapPeerStrings(removed), nil
}
const bootstrapSecurityWarning = `

View File

@ -104,7 +104,7 @@ var CatCmd = &cmds.Command{
return err
}
default:
log.Warningf("cat postrun: received unexpected type %T", val)
log.Warnf("cat postrun: received unexpected type %T", val)
}
}
},

View File

@ -31,6 +31,7 @@ var CidCmd = &cmds.Command{
const (
cidFormatOptionName = "f"
cidVerisonOptionName = "v"
cidCodecOptionName = "codec"
cidMultibaseOptionName = "b"
)
@ -49,11 +50,13 @@ The optional format string is a printf style format string:
Options: []cmds.Option{
cmds.StringOption(cidFormatOptionName, "Printf style format string.").WithDefault("%s"),
cmds.StringOption(cidVerisonOptionName, "CID version to convert to."),
cmds.StringOption(cidCodecOptionName, "CID codec to convert to."),
cmds.StringOption(cidMultibaseOptionName, "Multibase to display CID in."),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
fmtStr, _ := req.Options[cidFormatOptionName].(string)
verStr, _ := req.Options[cidVerisonOptionName].(string)
codecStr, _ := req.Options[cidCodecOptionName].(string)
baseStr, _ := req.Options[cidMultibaseOptionName].(string)
opts := cidFormatOpts{}
@ -63,10 +66,21 @@ The optional format string is a printf style format string:
}
opts.fmtStr = fmtStr
if codecStr != "" {
codec, ok := cid.Codecs[codecStr]
if !ok {
return fmt.Errorf("unknown IPLD codec: %s", codecStr)
}
opts.newCodec = codec
} // otherwise, leave it as 0 (not a valid IPLD codec)
switch verStr {
case "":
// noop
case "0":
if opts.newCodec != 0 && opts.newCodec != cid.DagProtobuf {
return fmt.Errorf("cannot convert to CIDv0 with any codec other than DagPB")
}
opts.verConv = toCidV0
case "1":
opts.verConv = toCidV1
@ -101,7 +115,7 @@ The optional format string is a printf style format string:
type CidFormatRes struct {
CidStr string // Original Cid String passed in
Formatted string // Formated Result
Formatted string // Formatted Result
ErrorMsg string // Error
}
@ -125,9 +139,10 @@ var base32Cmd = &cmds.Command{
}
type cidFormatOpts struct {
fmtStr string
newBase mbase.Encoding
verConv func(cid cid.Cid) (cid.Cid, error)
fmtStr string
newBase mbase.Encoding
verConv func(cid cid.Cid) (cid.Cid, error)
newCodec uint64
}
type argumentIterator struct {
@ -169,10 +184,11 @@ func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts)
emitErr = resp.Emit(res)
continue
}
base := opts.newBase
if base == -1 {
base, _ = cid.ExtractEncoding(cidStr)
if opts.newCodec != 0 && opts.newCodec != c.Type() {
c = cid.NewCidV1(opts.newCodec, c.Hash())
}
if opts.verConv != nil {
c, err = opts.verConv(c)
if err != nil {
@ -181,6 +197,16 @@ func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts)
continue
}
}
base := opts.newBase
if base == -1 {
if c.Version() == 0 {
base = mbase.Base58BTC
} else {
base, _ = cid.ExtractEncoding(cidStr)
}
}
str, err := cidutil.Format(opts.fmtStr, base, c)
if _, ok := err.(cidutil.FormatStringError); ok {
// no point in continuing if there is a problem with the format string
@ -229,7 +255,7 @@ var basesCmd = &cmds.Command{
Tagline: "List available multibase encodings.",
},
Options: []cmds.Option{
cmds.BoolOption(prefixOptionName, "also include the single leter prefixes in addition to the code"),
cmds.BoolOption(prefixOptionName, "also include the single letter prefixes in addition to the code"),
cmds.BoolOption(numericOptionName, "also include numeric codes"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {

View File

@ -26,7 +26,7 @@ func (e *commandEncoder) Encode(v interface{}) error {
)
if cmd, ok = v.(*Command); !ok {
return fmt.Errorf(`core/commands: uenxpected type %T, expected *"core/commands".Command`, v)
return fmt.Errorf(`core/commands: unexpected type %T, expected *"core/commands".Command`, v)
}
for _, s := range cmdPathStrings(cmd, cmd.showOpts) {

View File

@ -95,7 +95,9 @@ func TestCommands(t *testing.T) {
"/config/profile/apply",
"/dag",
"/dag/get",
"/dag/export",
"/dag/put",
"/dag/import",
"/dag/resolve",
"/dht",
"/dht/findpeer",

View File

@ -1,29 +1,48 @@
package dagcmd
import (
"errors"
"fmt"
"io"
"math"
"os"
"strings"
"time"
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/core/coredag"
iface "github.com/ipfs/interface-go-ipfs-core"
cid "github.com/ipfs/go-cid"
cidenc "github.com/ipfs/go-cidutil/cidenc"
cmds "github.com/ipfs/go-ipfs-cmds"
files "github.com/ipfs/go-ipfs-files"
ipld "github.com/ipfs/go-ipld-format"
mdag "github.com/ipfs/go-merkledag"
ipfspath "github.com/ipfs/go-path"
"github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
mh "github.com/multiformats/go-multihash"
gocar "github.com/ipld/go-car"
//gipfree "github.com/ipld/go-ipld-prime/impl/free"
//gipselector "github.com/ipld/go-ipld-prime/traversal/selector"
//gipselectorbuilder "github.com/ipld/go-ipld-prime/traversal/selector/builder"
"gopkg.in/cheggaaa/pb.v1"
)
const (
progressOptionName = "progress"
silentOptionName = "silent"
pinRootsOptionName = "pin-roots"
)
var DagCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Interact with ipld dag objects.",
ShortDescription: `
'ipfs dag' is used for creating and manipulating dag objects.
'ipfs dag' is used for creating and manipulating dag objects/hierarchies.
This subcommand is currently an experimental feature, but it is intended
to deprecate and replace the existing 'ipfs object' command moving forward.
@ -33,6 +52,8 @@ to deprecate and replace the existing 'ipfs object' command moving forward.
"put": DagPutCmd,
"get": DagGetCmd,
"resolve": DagResolveCmd,
"import": DagImportCmd,
"export": DagExportCmd,
},
}
@ -47,6 +68,15 @@ type ResolveOutput struct {
RemPath string
}
// CarImportOutput is the output type of the 'dag import' commands
type CarImportOutput struct {
Root RootMeta
}
type RootMeta struct {
Cid cid.Cid
PinErrorMsg string
}
var DagPutCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Add a dag node to ipfs.",
@ -187,7 +217,7 @@ var DagResolveCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Resolve ipld block",
ShortDescription: `
'ipfs dag resolve' fetches a dag node from ipfs, prints it's address and remaining path.
'ipfs dag resolve' fetches a dag node from ipfs, prints its address and remaining path.
`,
},
Arguments: []cmds.Argument{
@ -241,3 +271,400 @@ var DagResolveCmd = &cmds.Command{
},
Type: ResolveOutput{},
}
type importResult struct {
roots map[cid.Cid]struct{}
err error
}
var DagImportCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Import the contents of .car files",
ShortDescription: `
'ipfs dag import' imports all blocks present in supplied .car
( Content Address aRchive ) files, recursively pinning any roots
specified in the CAR file headers, unless --pin-roots is set to false.
Note:
This command will import all blocks in the CAR file, not just those
reachable from the specified roots. However, these other blocks will
not be pinned and may be garbage collected later.
The pinning of the roots happens after all car files are processed,
permitting import of DAGs spanning multiple files.
Pinning takes place in offline-mode exclusively, one root at a time.
If the combination of blocks from the imported CAR files and what is
currently present in the blockstore does not represent a complete DAG,
pinning of that individual root will fail.
Maximum supported CAR version: 1
`,
},
Arguments: []cmds.Argument{
cmds.FileArg("path", true, true, "The path of a .car file.").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption(silentOptionName, "No output."),
cmds.BoolOption(pinRootsOptionName, "Pin optional roots listed in the .car headers after importing.").WithDefault(true),
},
Type: CarImportOutput{},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
node, err := cmdenv.GetNode(env)
if err != nil {
return err
}
api, err := cmdenv.GetApi(env, req)
if err != nil {
return err
}
// on import ensure we do not reach out to the network for any reason
// if a pin based on what is imported + what is in the blockstore
// isn't possible: tough luck
api, err = api.WithOptions(options.Api.Offline(true))
if err != nil {
return err
}
// grab a pinlock ( which doubles as a GC lock ) so that regardless of the
// size of the streamed-in cars nothing will disappear on us before we had
// a chance to roots that may show up at the very end
// This is especially important for use cases like dagger:
// ipfs dag import $( ... | ipfs-dagger --stdout=carfifos )
//
unlocker := node.Blockstore.PinLock()
defer unlocker.Unlock()
doPinRoots, _ := req.Options[pinRootsOptionName].(bool)
retCh := make(chan importResult, 1)
go importWorker(req, res, api, retCh)
done := <-retCh
if done.err != nil {
return done.err
}
// It is not guaranteed that a root in a header is actually present in the same ( or any )
// .car file. This is the case in version 1, and ideally in further versions too
// Accumulate any root CID seen in a header, and supplement its actual node if/when encountered
// We will attempt a pin *only* at the end in case all car files were well formed
//
// The boolean value indicates whether we have encountered the root within the car file's
roots := done.roots
// opportunistic pinning: try whatever sticks
if doPinRoots {
var failedPins int
for c := range roots {
// We need to re-retrieve a block, convert it to ipld, and feed it
// to the Pinning interface, sigh...
//
// If we didn't have the problem of inability to take multiple pinlocks,
// we could use the api directly like so (though internally it does the same):
//
// // not ideal, but the pinning api takes only paths :(
// rp := path.NewResolvedPath(
// ipfspath.FromCid(c),
// c,
// c,
// "",
// )
//
// if err := api.Pin().Add(req.Context, rp, options.Pin.Recursive(true)); err != nil {
ret := RootMeta{Cid: c}
if block, err := node.Blockstore.Get(c); err != nil {
ret.PinErrorMsg = err.Error()
} else if nd, err := ipld.Decode(block); err != nil {
ret.PinErrorMsg = err.Error()
} else if err := node.Pinning.Pin(req.Context, nd, true); err != nil {
ret.PinErrorMsg = err.Error()
} else if err := node.Pinning.Flush(req.Context); err != nil {
ret.PinErrorMsg = err.Error()
}
if ret.PinErrorMsg != "" {
failedPins++
}
if err := res.Emit(&CarImportOutput{Root: ret}); err != nil {
return err
}
}
if failedPins > 0 {
return fmt.Errorf(
"unable to pin all roots: %d out of %d failed",
failedPins,
len(roots),
)
}
}
return nil
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, event *CarImportOutput) error {
silent, _ := req.Options[silentOptionName].(bool)
if silent {
return nil
}
enc, err := cmdenv.GetLowLevelCidEncoder(req)
if err != nil {
return err
}
if event.Root.PinErrorMsg != "" {
event.Root.PinErrorMsg = fmt.Sprintf("FAILED: %s", event.Root.PinErrorMsg)
} else {
event.Root.PinErrorMsg = "success"
}
_, err = fmt.Fprintf(
w,
"Pinned root\t%s\t%s\n",
enc.Encode(event.Root.Cid),
event.Root.PinErrorMsg,
)
return err
}),
},
}
func importWorker(req *cmds.Request, re cmds.ResponseEmitter, api iface.CoreAPI, ret chan importResult) {
// this is *not* a transaction
// it is simply a way to relieve pressure on the blockstore
// similar to pinner.Pin/pinner.Flush
batch := ipld.NewBatch(req.Context, api.Dag())
roots := make(map[cid.Cid]struct{})
it := req.Files.Entries()
for it.Next() {
file := files.FileFromEntry(it)
if file == nil {
ret <- importResult{err: errors.New("expected a file handle")}
return
}
// wrap a defer-closer-scope
//
// every single file in it() is already open before we start
// just close here sooner rather than later for neatness
// and to surface potential errors writing on closed fifos
// this won't/can't help with not running out of handles
err := func() error {
defer file.Close()
car, err := gocar.NewCarReader(file)
if err != nil {
return err
}
// Be explicit here, until the spec is finished
if car.Header.Version != 1 {
return errors.New("only car files version 1 supported at present")
}
for _, c := range car.Header.Roots {
roots[c] = struct{}{}
}
for {
block, err := car.Next()
if err != nil && err != io.EOF {
return err
} else if block == nil {
break
}
// the double-decode is suboptimal, but we need it for batching
nd, err := ipld.Decode(block)
if err != nil {
return err
}
if err := batch.Add(req.Context, nd); err != nil {
return err
}
}
return nil
}()
if err != nil {
ret <- importResult{err: err}
return
}
}
if err := it.Err(); err != nil {
ret <- importResult{err: err}
return
}
if err := batch.Commit(); err != nil {
ret <- importResult{err: err}
return
}
ret <- importResult{roots: roots}
}
var DagExportCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Streams the selected DAG as a .car stream on stdout.",
ShortDescription: `
'ipfs dag export' fetches a dag and streams it out as a well-formed .car file.
Note that at present only single root selections / .car files are supported.
The output of blocks happens in strict DAG-traversal, first-seen, order.
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("root", true, false, "CID of a root to recursively export").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption(progressOptionName, "p", "Display progress on CLI. Defaults to true when STDERR is a TTY."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
c, err := cid.Decode(req.Arguments[0])
if err != nil {
return fmt.Errorf(
"unable to parse root specification (currently only bare CIDs are supported): %s",
err,
)
}
node, err := cmdenv.GetNode(env)
if err != nil {
return err
}
// Code disabled until descent-issue in go-ipld-prime is fixed
// https://github.com/ribasushi/gip-muddle-up
//
// sb := gipselectorbuilder.NewSelectorSpecBuilder(gipfree.NodeBuilder())
// car := gocar.NewSelectiveCar(
// req.Context,
// <needs to be fixed to take format.NodeGetter as well>,
// []gocar.Dag{gocar.Dag{
// Root: c,
// Selector: sb.ExploreRecursive(
// gipselector.RecursionLimitNone(),
// sb.ExploreAll(sb.ExploreRecursiveEdge()),
// ).Node(),
// }},
// )
// ...
// if err := car.Write(pipeW); err != nil {}
pipeR, pipeW := io.Pipe()
errCh := make(chan error, 2) // we only report the 1st error
go func() {
defer func() {
if err := pipeW.Close(); err != nil {
errCh <- fmt.Errorf("stream flush failed: %s", err)
}
close(errCh)
}()
if err := gocar.WriteCar(
req.Context,
mdag.NewSession(
req.Context,
node.DAG,
),
[]cid.Cid{c},
pipeW,
); err != nil {
errCh <- err
}
}()
if err := res.Emit(pipeR); err != nil {
pipeR.Close() // ignore the error if any
return err
}
err = <-errCh
// minimal user friendliness
if err != nil &&
!node.IsOnline &&
err == ipld.ErrNotFound {
err = fmt.Errorf("%s (currently offline, perhaps retry after attaching to the network)", err)
}
return err
},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
var showProgress bool
val, specified := res.Request().Options[progressOptionName]
if !specified {
// default based on TTY availability
errStat, _ := os.Stderr.Stat()
if 0 != (errStat.Mode() & os.ModeCharDevice) {
showProgress = true
}
} else if val.(bool) {
showProgress = true
}
// simple passthrough, no progress
if !showProgress {
return cmds.Copy(re, res)
}
bar := pb.New64(0).SetUnits(pb.U_BYTES)
bar.Output = os.Stderr
bar.ShowSpeed = true
bar.ShowElapsedTime = true
bar.RefreshRate = 500 * time.Millisecond
bar.Start()
var processedOneResponse bool
for {
v, err := res.Next()
if err == io.EOF {
// We only write the final bar update on success
// On error it looks too weird
bar.Finish()
return re.Close()
} else if err != nil {
return re.CloseWithError(err)
} else if processedOneResponse {
return re.CloseWithError(errors.New("unexpected multipart response during emit, please file a bugreport"))
}
r, ok := v.(io.Reader)
if !ok {
// some sort of encoded response, this should not be happening
return errors.New("unexpected non-stream passed to PostRun: please file a bugreport")
}
processedOneResponse = true
if err := re.Emit(bar.NewProxyReader(r)); err != nil {
return err
}
}
},
},
}

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"time"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
@ -15,10 +16,8 @@ import (
ipld "github.com/ipfs/go-ipld-format"
dag "github.com/ipfs/go-merkledag"
path "github.com/ipfs/go-path"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
routing "github.com/libp2p/go-libp2p-routing"
notif "github.com/libp2p/go-libp2p-routing/notifications"
peer "github.com/libp2p/go-libp2p-core/peer"
routing "github.com/libp2p/go-libp2p-core/routing"
b58 "github.com/mr-tron/base58/base58"
)
@ -69,27 +68,36 @@ var queryDhtCmd = &cmds.Command{
return ErrNotDHT
}
id, err := peer.IDB58Decode(req.Arguments[0])
id, err := peer.Decode(req.Arguments[0])
if err != nil {
return cmds.ClientError("invalid peer ID")
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
closestPeers, err := nd.DHT.GetClosestPeers(ctx, string(id))
if err != nil {
cancel()
return err
dht := nd.DHT.WAN
if !nd.DHT.WANActive() {
dht = nd.DHT.LAN
}
errCh := make(chan error, 1)
go func() {
defer close(errCh)
defer cancel()
for p := range closestPeers {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
ID: p,
Type: notif.FinalPeer,
})
closestPeers, err := dht.GetClosestPeers(ctx, string(id))
if closestPeers != nil {
for p := range closestPeers {
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
ID: p,
Type: routing.FinalPeer,
})
}
}
if err != nil {
errCh <- err
return
}
}()
@ -99,15 +107,13 @@ var queryDhtCmd = &cmds.Command{
}
}
return nil
return <-errCh
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.PeerResponse: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
for _, p := range obj.Responses {
fmt.Fprintf(out, "%s\n", p.ID.Pretty())
}
routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
fmt.Fprintf(out, "%s\n", obj.ID)
return nil
},
}
@ -115,7 +121,7 @@ var queryDhtCmd = &cmds.Command{
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
const (
@ -157,7 +163,7 @@ var findProvidersDhtCmd = &cmds.Command{
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
pchan := n.Routing.FindProvidersAsync(ctx, c, numProviders)
@ -165,9 +171,9 @@ var findProvidersDhtCmd = &cmds.Command{
defer cancel()
for p := range pchan {
np := p
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.Provider,
Responses: []*pstore.PeerInfo{&np},
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.Provider,
Responses: []*peer.AddrInfo{&np},
})
}
}()
@ -180,15 +186,15 @@ var findProvidersDhtCmd = &cmds.Command{
return nil
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
if verbose {
fmt.Fprintf(out, "* closest peer %s\n", obj.ID)
}
return nil
},
notif.Provider: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.Provider: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
prov := obj.Responses[0]
if verbose {
fmt.Fprintf(out, "provider: ")
@ -207,7 +213,7 @@ var findProvidersDhtCmd = &cmds.Command{
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
const (
@ -269,7 +275,7 @@ var provideRefDhtCmd = &cmds.Command{
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
var provideErr error
go func() {
@ -280,8 +286,8 @@ var provideRefDhtCmd = &cmds.Command{
provideErr = provideKeys(ctx, nd.Routing, cids)
}
if provideErr != nil {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.QueryError,
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.QueryError,
Extra: provideErr.Error(),
})
}
@ -296,9 +302,9 @@ var provideRefDhtCmd = &cmds.Command{
return provideErr
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
if verbose {
fmt.Fprintf(out, "sending provider record to peer %s\n", obj.ID)
}
@ -310,10 +316,10 @@ var provideRefDhtCmd = &cmds.Command{
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
func provideKeys(ctx context.Context, r routing.IpfsRouting, cids []cid.Cid) error {
func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
for _, c := range cids {
err := r.Provide(ctx, c, true)
if err != nil {
@ -323,12 +329,12 @@ func provideKeys(ctx context.Context, r routing.IpfsRouting, cids []cid.Cid) err
return nil
}
func provideKeysRec(ctx context.Context, r routing.IpfsRouting, dserv ipld.DAGService, cids []cid.Cid) error {
func provideKeysRec(ctx context.Context, r routing.Routing, dserv ipld.DAGService, cids []cid.Cid) error {
provided := cid.NewSet()
for _, c := range cids {
kset := cid.NewSet()
err := dag.EnumerateChildrenAsync(ctx, dag.GetLinksDirect(dserv), c, kset.Visit)
err := dag.Walk(ctx, dag.GetLinksDirect(dserv), c, kset.Visit)
if err != nil {
return err
}
@ -371,30 +377,30 @@ var findPeerDhtCmd = &cmds.Command{
return ErrNotOnline
}
pid, err := peer.IDB58Decode(req.Arguments[0])
pid, err := peer.Decode(req.Arguments[0])
if err != nil {
return err
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
var findPeerErr error
go func() {
defer cancel()
var pi pstore.PeerInfo
var pi peer.AddrInfo
pi, findPeerErr = nd.Routing.FindPeer(ctx, pid)
if findPeerErr != nil {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.QueryError,
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.QueryError,
Extra: findPeerErr.Error(),
})
return
}
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.FinalPeer,
Responses: []*pstore.PeerInfo{&pi},
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.FinalPeer,
Responses: []*peer.AddrInfo{&pi},
})
}()
@ -407,9 +413,9 @@ var findPeerDhtCmd = &cmds.Command{
return findPeerErr
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
pi := obj.Responses[0]
for _, a := range pi.Addrs {
fmt.Fprintf(out, "%s\n", a)
@ -422,7 +428,7 @@ var findPeerDhtCmd = &cmds.Command{
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
var getValueDhtCmd = &cmds.Command{
@ -461,7 +467,7 @@ Different key types can specify other 'best' rules.
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
var getErr error
go func() {
@ -469,13 +475,13 @@ Different key types can specify other 'best' rules.
var val []byte
val, getErr = nd.Routing.GetValue(ctx, dhtkey)
if getErr != nil {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.QueryError,
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.QueryError,
Extra: getErr.Error(),
})
} else {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.Value,
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.Value,
Extra: base64.StdEncoding.EncodeToString(val),
})
}
@ -490,9 +496,9 @@ Different key types can specify other 'best' rules.
return getErr
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.Value: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.Value: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
if verbose {
_, err := fmt.Fprintf(out, "got value: '%s'\n", obj.Extra)
return err
@ -510,15 +516,15 @@ Different key types can specify other 'best' rules.
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
var putValueDhtCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Write a key/value pair to the routing system.",
ShortDescription: `
Given a key of the form /foo/bar and a value of any form, this will write that
value to the routing system with that key.
Given a key of the form /foo/bar and a valid value for that key, this will write
that value to the routing system with that key.
Keys have two parts: a keytype (foo) and the key name (bar). IPNS uses the
/ipns keytype, and expects the key name to be a Peer ID. IPNS entries are
@ -529,15 +535,15 @@ this is only /ipns. Unless you have a relatively deep understanding of the
go-ipfs routing internals, you likely want to be using 'ipfs name publish' instead
of this.
Value is arbitrary text. Standard input can be used to provide value.
NOTE: A value may not exceed 2048 bytes.
The value must be a valid value for the given key type. For example, if the key
is /ipns/QmFoo, the value must be IPNS record (protobuf) signed with the key
identified by QmFoo.
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "The key to store the value at."),
cmds.StringArg("value", true, false, "The value to store.").EnableStdin(),
cmds.FileArg("value-file", true, false, "A path to a file containing the value to store.").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption(dhtVerboseOptionName, "v", "Print extra information."),
@ -548,12 +554,6 @@ NOTE: A value may not exceed 2048 bytes.
return err
}
// Needed to parse stdin args.
err = req.ParseBodyArgs()
if err != nil {
return err
}
if !nd.IsOnline {
return ErrNotOnline
}
@ -563,18 +563,27 @@ NOTE: A value may not exceed 2048 bytes.
return err
}
data := req.Arguments[1]
file, err := cmdenv.GetFileArg(req.Files.Entries())
if err != nil {
return err
}
defer file.Close()
data, err := ioutil.ReadAll(file)
if err != nil {
return err
}
ctx, cancel := context.WithCancel(req.Context)
ctx, events := notif.RegisterForQueryEvents(ctx)
ctx, events := routing.RegisterForQueryEvents(ctx)
var putErr error
go func() {
defer cancel()
putErr = nd.Routing.PutValue(ctx, key, []byte(data))
if putErr != nil {
notif.PublishQueryEvent(ctx, &notif.QueryEvent{
Type: notif.QueryError,
routing.PublishQueryEvent(ctx, &routing.QueryEvent{
Type: routing.QueryError,
Extra: putErr.Error(),
})
}
@ -589,15 +598,15 @@ NOTE: A value may not exceed 2048 bytes.
return putErr
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *notif.QueryEvent) error {
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *routing.QueryEvent) error {
pfm := pfuncMap{
notif.FinalPeer: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.FinalPeer: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
if verbose {
fmt.Fprintf(out, "* closest peer %s\n", obj.ID)
}
return nil
},
notif.Value: func(obj *notif.QueryEvent, out io.Writer, verbose bool) error {
routing.Value: func(obj *routing.QueryEvent, out io.Writer, verbose bool) error {
fmt.Fprintf(out, "%s\n", obj.ID.Pretty())
return nil
},
@ -608,13 +617,13 @@ NOTE: A value may not exceed 2048 bytes.
return printEvent(out, w, verbose, pfm)
}),
},
Type: notif.QueryEvent{},
Type: routing.QueryEvent{},
}
type printFunc func(obj *notif.QueryEvent, out io.Writer, verbose bool) error
type pfuncMap map[notif.QueryEventType]printFunc
type printFunc func(obj *routing.QueryEvent, out io.Writer, verbose bool) error
type pfuncMap map[routing.QueryEventType]printFunc
func printEvent(obj *notif.QueryEvent, out io.Writer, verbose bool, override pfuncMap) error {
func printEvent(obj *routing.QueryEvent, out io.Writer, verbose bool, override pfuncMap) error {
if verbose {
fmt.Fprintf(out, "%s: ", time.Now().Format("15:04:05.000"))
}
@ -626,17 +635,17 @@ func printEvent(obj *notif.QueryEvent, out io.Writer, verbose bool, override pfu
}
switch obj.Type {
case notif.SendingQuery:
case routing.SendingQuery:
if verbose {
fmt.Fprintf(out, "* querying %s\n", obj.ID)
}
case notif.Value:
case routing.Value:
if verbose {
fmt.Fprintf(out, "got value: '%s'\n", obj.Extra)
} else {
fmt.Fprint(out, obj.Extra)
}
case notif.PeerResponse:
case routing.PeerResponse:
if verbose {
fmt.Fprintf(out, "* %s says use ", obj.ID)
for _, p := range obj.Responses {
@ -644,19 +653,19 @@ func printEvent(obj *notif.QueryEvent, out io.Writer, verbose bool, override pfu
}
fmt.Fprintln(out)
}
case notif.QueryError:
case routing.QueryError:
if verbose {
fmt.Fprintf(out, "error: %s\n", obj.Extra)
}
case notif.DialingPeer:
case routing.DialingPeer:
if verbose {
fmt.Fprintf(out, "dialing peer: %s\n", obj.ID)
}
case notif.AddingPeer:
case routing.AddingPeer:
if verbose {
fmt.Fprintf(out, "adding peer to query: %s\n", obj.ID)
}
case notif.FinalPeer:
case routing.FinalPeer:
default:
if verbose {
fmt.Fprintf(out, "unrecognized event type: %d\n", obj.Type)

View File

@ -6,11 +6,11 @@ import (
"github.com/ipfs/go-ipfs/namesys"
ipns "github.com/ipfs/go-ipns"
tu "github.com/libp2p/go-testutil"
"github.com/libp2p/go-libp2p-core/test"
)
func TestKeyTranslation(t *testing.T) {
pid := tu.RandPeerIDFatal(t)
pid := test.RandPeerIDFatal(t)
pkname := namesys.PkKeyForID(pid)
ipnsname := ipns.RecordKey(pid)

View File

@ -64,12 +64,12 @@ The resolver can recursively resolve:
name := req.Arguments[0]
resolver := namesys.NewDNSResolver()
var ropts []nsopts.ResolveOpt
var routing []nsopts.ResolveOpt
if !recursive {
ropts = append(ropts, nsopts.Depth(1))
routing = append(routing, nsopts.Depth(1))
}
output, err := resolver.Resolve(req.Context, name, ropts...)
output, err := resolver.Resolve(req.Context, name, routing...)
if err != nil && (recursive || err != namesys.ErrResolveRecursion) {
return err
}

View File

@ -11,7 +11,7 @@ import (
cmds "github.com/ipfs/go-ipfs-cmds"
)
func ExternalBinary() *cmds.Command {
func ExternalBinary(instructions string) *cmds.Command {
return &cmds.Command{
Arguments: []cmds.Argument{
cmds.StringArg("args", false, true, "Arguments for subcommand."),
@ -27,7 +27,7 @@ func ExternalBinary() *cmds.Command {
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%s is an 'external' command.\n", binname)
fmt.Fprintf(buf, "It does not currently appear to be installed.\n")
fmt.Fprintf(buf, "Please refer to the ipfs documentation for instructions.\n")
fmt.Fprintf(buf, "%s\n", instructions)
return res.Emit(buf)
}
}

View File

@ -17,14 +17,14 @@ import (
bservice "github.com/ipfs/go-blockservice"
cid "github.com/ipfs/go-cid"
cidenc "github.com/ipfs/go-cidutil/cidenc"
"github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs-exchange-offline"
cmds "github.com/ipfs/go-ipfs-cmds"
offline "github.com/ipfs/go-ipfs-exchange-offline"
ipld "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log"
dag "github.com/ipfs/go-merkledag"
"github.com/ipfs/go-mfs"
ft "github.com/ipfs/go-unixfs"
"github.com/ipfs/interface-go-ipfs-core"
iface "github.com/ipfs/interface-go-ipfs-core"
path "github.com/ipfs/interface-go-ipfs-core/path"
mh "github.com/multiformats/go-multihash"
)
@ -36,16 +36,32 @@ var FilesCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Interact with unixfs files.",
ShortDescription: `
Files is an API for manipulating IPFS objects as if they were a unix
Files is an API for manipulating IPFS objects as if they were a Unix
filesystem.
The files facility interacts with MFS (Mutable File System). MFS acts as a
single, dynamic filesystem mount. MFS has a root CID that is transparently
updated when a change happens (and can be checked with "ipfs files stat /").
All files and folders within MFS are respected and will not be cleaned up
during garbage collections. MFS is independent from the list of pinned items
("ipfs pin ls"). Calls to "ipfs pin add" and "ipfs pin rm" will add and remove
pins independently of MFS. If MFS content that was
additionally pinned is removed by calling "ipfs files rm", it will still
remain pinned.
Content added with "ipfs add" (which by default also becomes pinned), is not
added to MFS. Any content can be put into MFS with the command "ipfs files cp
/ipfs/<cid> /some/path/".
NOTE:
Most of the subcommands of 'ipfs files' accept the '--flush' flag. It defaults
to true. Use caution when setting this flag to false. It will improve
performance for large numbers of file operations, but it does so at the cost
of consistency guarantees. If the daemon is unexpectedly killed before running
'ipfs files flush' on the files in question, then data may be lost. This also
applies to running 'ipfs repo gc' concurrently with '--flush=false'
applies to run 'ipfs repo gc' concurrently with '--flush=false'
operations.
`,
},
@ -305,11 +321,27 @@ func walkBlock(ctx context.Context, dagserv ipld.DAGService, nd ipld.Node) (bool
var filesCpCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Copy files into mfs.",
Tagline: "Copy any IPFS files and directories into MFS (or copy within MFS).",
ShortDescription: `
"ipfs files cp" can be used to copy any IPFS file or directory (usually in the
form /ipfs/<CID>, but also any resolvable path), into the Mutable File System
(MFS).
It can also be used to copy files within MFS, but in the case when an
IPFS-path matches an existing MFS path, the IPFS path wins.
In order to add content to MFS from disk, you can use "ipfs add" to obtain the
IPFS Content Identifier and then "ipfs files cp" to copy it into MFS:
$ ipfs add --quieter --pin=false <your file>
# ...
# ... outputs the root CID at the end
$ ipfs cp /ipfs/<CID> /your/desired/mfs/path
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("source", true, false, "Source object to copy."),
cmds.StringArg("dest", true, false, "Destination to copy object to."),
cmds.StringArg("source", true, false, "Source IPFS or MFS path to copy."),
cmds.StringArg("dest", true, false, "Destination within MFS."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
@ -379,7 +411,7 @@ type filesLsOutput struct {
}
const (
longOptionName = "l"
longOptionName = "long"
dontSortOptionName = "U"
)
@ -408,7 +440,7 @@ Examples:
cmds.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."),
},
Options: []cmds.Option{
cmds.BoolOption(longOptionName, "Use long listing format."),
cmds.BoolOption(longOptionName, "l", "Use long listing format."),
cmds.BoolOption(dontSortOptionName, "Do not sort; list entries in directory order."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
@ -520,10 +552,10 @@ const (
var filesReadCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Read a file in a given mfs.",
Tagline: "Read a file in a given MFS.",
ShortDescription: `
Read a specified number of bytes from a file at a given offset. By default,
will read the entire file similar to unix cat.
it will read the entire file similar to the Unix cat.
Examples:
@ -615,7 +647,7 @@ var filesMvCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Move files.",
ShortDescription: `
Move files around. Just like traditional unix mv.
Move files around. Just like the traditional Unix mv.
Example:
@ -670,22 +702,23 @@ a beginning offset to write to. The entire length of the input will be
written.
If the '--create' option is specified, the file will be created if it does not
exist. Nonexistant intermediate directories will not be created.
exist. Nonexistent intermediate directories will not be created unless the
'--parents' option is specified.
Newly created files will have the same CID version and hash function of the
parent directory unless the --cid-version and --hash options are used.
parent directory unless the '--cid-version' and '--hash' options are used.
Newly created leaves will be in the legacy format (Protobuf) if the
CID version is 0, or raw is the CID version is non-zero. Use of the
--raw-leaves option will override this behavior.
CID version is 0, or raw if the CID version is non-zero. Use of the
'--raw-leaves' option will override this behavior.
If the '--flush' option is set to false, changes will not be propogated to the
If the '--flush' option is set to false, changes will not be propagated to the
merkledag root. This can make operations much faster when doing a large number
of writes to a deeper directory structure.
EXAMPLE:
echo "hello world" | ipfs files write --create /myfs/a/b/file
echo "hello world" | ipfs files write --create --parents /myfs/a/b/file
echo "hello world" | ipfs files write --truncate /myfs/a/b/file
WARNING:
@ -762,7 +795,7 @@ stat' on the file or any of its ancestors.
if retErr == nil {
retErr = err
} else {
log.Error("files: error closing file mfs file descriptor", err)
flog.Error("files: error closing file mfs file descriptor", err)
}
}
}()
@ -862,7 +895,7 @@ var filesFlushCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Flush a given path's data to disk.",
ShortDescription: `
Flush a given path to disk. This is only useful when other commands
Flush a given path to the disk. This is only useful when other commands
are run with the '--flush=false'.
`,
},
@ -997,26 +1030,28 @@ Remove files or directories.
path = path[:len(path)-1]
}
dir, name := gopath.Split(path)
parent, err := mfs.Lookup(nd.FilesRoot, dir)
if err != nil {
return fmt.Errorf("parent lookup: %s", err)
}
pdir, ok := parent.(*mfs.Directory)
if !ok {
return fmt.Errorf("no such file or directory: %s", path)
}
// if '--force' specified, it will remove anything else,
// including file, directory, corrupted node, etc
force, _ := req.Options[forceOptionName].(bool)
dir, name := gopath.Split(path)
pdir, err := getParentDir(nd.FilesRoot, dir)
if err != nil {
if force && err == os.ErrNotExist {
return nil
}
return fmt.Errorf("parent lookup: %s", err)
}
if force {
err := pdir.Unlink(name)
if err != nil {
if err == os.ErrNotExist {
return nil
}
return err
}
return pdir.Flush()
}
@ -1131,17 +1166,13 @@ func getFileHandle(r *mfs.Root, path string, create bool, builder cid.Builder) (
return nil, err
}
// if create is specified and the file doesnt exist, we create the file
// if create is specified and the file doesn't exist, we create the file
dirname, fname := gopath.Split(path)
pdiri, err := mfs.Lookup(r, dirname)
pdir, err := getParentDir(r, dirname)
if err != nil {
flog.Error("lookupfail ", dirname)
return nil, err
}
pdir, ok := pdiri.(*mfs.Directory)
if !ok {
return nil, fmt.Errorf("%s was not a directory", dirname)
}
if builder == nil {
builder = pdir.GetCidBuilder()
}
@ -1160,7 +1191,7 @@ func getFileHandle(r *mfs.Root, path string, create bool, builder cid.Builder) (
fi, ok := fsn.(*mfs.File)
if !ok {
return nil, errors.New("expected *mfs.File, didnt get it. This is likely a race condition")
return nil, errors.New("expected *mfs.File, didn't get it. This is likely a race condition")
}
return fi, nil
@ -1184,3 +1215,16 @@ func checkPath(p string) (string, error) {
}
return cleaned, nil
}
func getParentDir(root *mfs.Root, dir string) (*mfs.Directory, error) {
parent, err := mfs.Lookup(root, dir)
if err != nil {
return nil, err
}
pdir, ok := parent.(*mfs.Directory)
if !ok {
return nil, errors.New("expected *mfs.Directory, didn't get it. This is likely a race condition")
}
return pdir, nil
}

View File

@ -5,10 +5,10 @@ import (
"io"
"os"
filestore "github.com/ipfs/go-filestore"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
filestore "github.com/ipfs/go-ipfs/filestore"
"github.com/ipfs/go-cid"
"github.com/ipfs/go-ipfs-cmds"

View File

@ -155,7 +155,7 @@ func makeProgressBar(out io.Writer, l int64) *pb.ProgressBar {
bar.Output = out
// the progress bar lib doesn't give us a way to get the width of the output,
// so as a hack we just use a callback to measure the output, then git rid of it
// so as a hack we just use a callback to measure the output, then get rid of it
bar.Callback = func(line string) {
terminalWidth := len(line)
bar.Callback = nil

View File

@ -8,14 +8,16 @@ import (
"io"
"strings"
version "github.com/ipfs/go-ipfs"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
cmds "github.com/ipfs/go-ipfs-cmds"
ic "github.com/libp2p/go-libp2p-crypto"
ic "github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/host"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
kb "github.com/libp2p/go-libp2p-kbucket"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
identify "github.com/libp2p/go-libp2p/p2p/protocol/identify"
)
@ -74,7 +76,7 @@ EXAMPLE:
var id peer.ID
if len(req.Arguments) > 0 {
var err error
id, err = peer.IDB58Decode(req.Arguments[0])
id, err = peer.Decode(req.Arguments[0])
if err != nil {
return fmt.Errorf("invalid peer id")
}
@ -183,12 +185,15 @@ func printSelf(node *core.IpfsNode) (interface{}, error) {
info.PublicKey = base64.StdEncoding.EncodeToString(pkb)
if node.PeerHost != nil {
for _, a := range node.PeerHost.Addrs() {
s := a.String() + "/ipfs/" + info.ID
info.Addresses = append(info.Addresses, s)
addrs, err := peer.AddrInfoToP2pAddrs(host.InfoFromHost(node.PeerHost))
if err != nil {
return nil, err
}
for _, a := range addrs {
info.Addresses = append(info.Addresses, a.String())
}
}
info.ProtocolVersion = identify.LibP2PVersion
info.AgentVersion = identify.ClientVersion
info.AgentVersion = version.UserAgent
return info, nil
}

View File

@ -63,7 +63,7 @@ var keyGenCmd = &cmds.Command{
Tagline: "Create a new keypair",
},
Options: []cmds.Option{
cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create [rsa, ed25519]"),
cmds.StringOption(keyStoreTypeOptionName, "t", "type of the key to create: rsa, ed25519").WithDefault("rsa"),
cmds.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"),
},
Arguments: []cmds.Argument{

View File

@ -24,8 +24,10 @@ output of a running daemon.
There are also two environmental variables that direct the logging
system (not just for the daemon logs, but all commands):
IPFS_LOGGING - sets the level of verbosity of the logging. One of: debug, info, warning, error, critical
IPFS_LOGGING_FMT - sets formatting of the log output. One of: color, nocolor
IPFS_LOGGING - sets the level of verbosity of the logging.
One of: debug, info, warn, error, dpanic, panic, fatal
IPFS_LOGGING_FMT - sets formatting of the log output.
One of: color, nocolor
`,
},
@ -49,8 +51,8 @@ the event log.
// TODO use a different keyword for 'all' because all can theoretically
// clash with a subsystem name
cmds.StringArg("subsystem", true, false, fmt.Sprintf("The subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
cmds.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'critical' the least verbose.
One of: debug, info, warning, error, critical.
cmds.StringArg("level", true, false, `The log level, with 'debug' the most verbose and 'fatal' the least verbose.
One of: debug, info, warn, error, dpanic, panic, fatal.
`),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {

View File

@ -65,7 +65,7 @@ The JSON output contains type information.
cmds.BoolOption(lsHeadersOptionNameTime, "v", "Print table headers (Hash, Size, Name)."),
cmds.BoolOption(lsResolveTypeOptionName, "Resolve linked objects to find out their types.").WithDefault(true),
cmds.BoolOption(lsSizeOptionName, "Resolve linked objects to find out their file size.").WithDefault(true),
cmds.BoolOption(lsStreamOptionName, "s", "Enable exprimental streaming of directory entries as they are traversed."),
cmds.BoolOption(lsStreamOptionName, "s", "Enable experimental streaming of directory entries as they are traversed."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env, req)

View File

@ -35,7 +35,7 @@ You may have to create /ipfs and /ipns before using 'ipfs mount':
`,
LongDescription: `
Mount IPFS at a read-only mountpoint on the OS. The default, /ipfs and /ipns,
are set in the configuration file, but can be overriden by the options.
are set in the configuration file, but can be overridden by the options.
All IPFS objects will be accessible under this directory. Note that the
root will not be listable, as it is virtual. Access known paths directly.

View File

@ -7,7 +7,7 @@ import (
"github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/libp2p/go-libp2p-peer"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p-record"
)
@ -93,7 +93,7 @@ var ipnspsSubsCmd = &cmds.Command{
log.Errorf("ipns key not a valid peer ID: %s", err)
continue
}
paths = append(paths, "/ipns/"+peer.IDB58Encode(pid))
paths = append(paths, "/ipns/"+peer.Encode(pid))
}
return cmds.EmitOnce(res, &stringList{paths})
@ -120,7 +120,7 @@ var ipnspsCancelCmd = &cmds.Command{
name := req.Arguments[0]
name = strings.TrimPrefix(name, "/ipns/")
pid, err := peer.IDB58Decode(name)
pid, err := peer.Decode(name)
if err != nil {
return cmds.Errorf(cmds.ErrClient, err.Error())
}

View File

@ -4,11 +4,11 @@ import (
"fmt"
"io"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/dagutils"
cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/ipfs/go-merkledag/dagutils"
path "github.com/ipfs/interface-go-ipfs-core/path"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
)
const (
@ -70,7 +70,7 @@ Example:
out := make([]*dagutils.Change, len(changes))
for i, change := range changes {
out[i] = &dagutils.Change{
Type: change.Type,
Type: dagutils.ChangeType(change.Type),
Path: change.Path,
}

View File

@ -34,7 +34,7 @@ type Object struct {
Links []Link `json:"Links,omitempty"`
}
var ErrDataEncoding = errors.New("unkown data field encoding")
var ErrDataEncoding = errors.New("unknown data field encoding")
const (
headersOptionName = "headers"
@ -197,7 +197,7 @@ This command outputs data in the following encodings:
* "xml"
(Specified by the "--encoding" or "--enc" flag)
The encoding of the object's data field can be specifed by using the
The encoding of the object's data field can be specified by using the
--data-encoding flag
Supported values are:

View File

@ -14,10 +14,10 @@ import (
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
p2p "github.com/ipfs/go-ipfs/p2p"
ipfsaddr "github.com/ipfs/go-ipfs-addr"
cmds "github.com/ipfs/go-ipfs-cmds"
pstore "github.com/libp2p/go-libp2p-peerstore"
protocol "github.com/libp2p/go-libp2p-protocol"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
protocol "github.com/libp2p/go-libp2p-core/protocol"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
)
@ -87,8 +87,8 @@ Forward connections made to <listen-address> to <target-address>.
connections and/or handlers. It must be prefixed with '` + P2PProtoPrefix + `'.
Example:
ipfs p2p forward ` + P2PProtoPrefix + `myproto /ip4/127.0.0.1/tcp/4567 /ipfs/QmPeer
- Forward connections to 127.0.0.1:4567 to '` + P2PProtoPrefix + `myproto' service on /ipfs/QmPeer
ipfs p2p forward ` + P2PProtoPrefix + `myproto /ip4/127.0.0.1/tcp/4567 /p2p/QmPeer
- Forward connections to 127.0.0.1:4567 to '` + P2PProtoPrefix + `myproto' service on /p2p/QmPeer
`,
},
@ -133,37 +133,49 @@ Example:
}
// parseIpfsAddr is a function that takes in addr string and return ipfsAddrs
func parseIpfsAddr(addr string) ([]ipfsaddr.IPFSAddr, error) {
mutiladdr, err := ma.NewMultiaddr(addr)
func parseIpfsAddr(addr string) (*peer.AddrInfo, error) {
multiaddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
if _, err := mutiladdr.ValueForProtocol(ma.P_IPFS); err == nil {
iaddrs := make([]ipfsaddr.IPFSAddr, 1)
iaddrs[0], err = ipfsaddr.ParseMultiaddr(mutiladdr)
if err != nil {
return nil, err
}
return iaddrs, nil
pi, err := peer.AddrInfoFromP2pAddr(multiaddr)
if err == nil {
return pi, nil
}
// resolve mutiladdr whose protocol is not ma.P_IPFS
// resolve multiaddr whose protocol is not ma.P_IPFS
ctx, cancel := context.WithTimeout(context.Background(), resolveTimeout)
defer cancel()
addrs, err := madns.Resolve(ctx, mutiladdr)
addrs, err := madns.Resolve(ctx, multiaddr)
if err != nil {
return nil, err
}
if len(addrs) == 0 {
return nil, errors.New("fail to resolve the multiaddr:" + mutiladdr.String())
return nil, errors.New("fail to resolve the multiaddr:" + multiaddr.String())
}
iaddrs := make([]ipfsaddr.IPFSAddr, len(addrs))
for i, addr := range addrs {
iaddrs[i], err = ipfsaddr.ParseMultiaddr(addr)
if err != nil {
return nil, err
var info peer.AddrInfo
for _, addr := range addrs {
taddr, id := peer.SplitAddr(addr)
if id == "" {
// not an ipfs addr, skipping.
continue
}
switch info.ID {
case "":
info.ID = id
case id:
default:
return nil, fmt.Errorf(
"ambiguous multiaddr %s could refer to %s or %s",
multiaddr,
info.ID,
id,
)
}
info.Addrs = append(info.Addrs, taddr)
}
return iaddrs, nil
return &info, nil
}
var p2pListenCmd = &cmds.Command{
@ -256,14 +268,10 @@ func checkPort(target ma.Multiaddr) error {
}
// forwardLocal forwards local connections to a libp2p service
func forwardLocal(ctx context.Context, p *p2p.P2P, ps pstore.Peerstore, proto protocol.ID, bindAddr ma.Multiaddr, addrs []ipfsaddr.IPFSAddr) error {
for _, addr := range addrs {
ps.AddAddr(addr.ID(), addr.Multiaddr(), pstore.TempAddrTTL)
}
func forwardLocal(ctx context.Context, p *p2p.P2P, ps pstore.Peerstore, proto protocol.ID, bindAddr ma.Multiaddr, addr *peer.AddrInfo) error {
ps.AddAddrs(addr.ID, addr.Addrs, pstore.TempAddrTTL)
// TODO: return some info
// the length of the addrs must large than 0
// peerIDs in addr must be the same and choose addr[0] to connect
_, err := p.ForwardLocal(ctx, addrs[0].ID(), proto, bindAddr)
_, err := p.ForwardLocal(ctx, addr.ID, proto, bindAddr)
return err
}

View File

@ -2,26 +2,29 @@ package commands
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"time"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
pin "github.com/ipfs/go-ipfs/pin"
bserv "github.com/ipfs/go-blockservice"
cid "github.com/ipfs/go-cid"
cidenc "github.com/ipfs/go-cidutil/cidenc"
cmds "github.com/ipfs/go-ipfs-cmds"
offline "github.com/ipfs/go-ipfs-exchange-offline"
pin "github.com/ipfs/go-ipfs-pinner"
ipld "github.com/ipfs/go-ipld-format"
dag "github.com/ipfs/go-merkledag"
verifcid "github.com/ipfs/go-verifcid"
coreiface "github.com/ipfs/interface-go-ipfs-core"
options "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/ipfs/interface-go-ipfs-core/path"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
)
var PinCmd = &cmds.Command{
@ -259,8 +262,9 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
}
const (
pinTypeOptionName = "type"
pinQuietOptionName = "quiet"
pinTypeOptionName = "type"
pinQuietOptionName = "quiet"
pinStreamOptionName = "stream"
)
var listPinCmd = &cmds.Command{
@ -313,6 +317,7 @@ Example:
Options: []cmds.Option{
cmds.StringOption(pinTypeOptionName, "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"),
cmds.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."),
cmds.BoolOption(pinStreamOptionName, "s", "Enable streaming of pins as they are discovered."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
@ -326,9 +331,7 @@ Example:
}
typeStr, _ := req.Options[pinTypeOptionName].(string)
if err != nil {
return err
}
stream, _ := req.Options[pinStreamOptionName].(bool)
switch typeStr {
case "all", "direct", "indirect", "recursive":
@ -337,34 +340,61 @@ Example:
return err
}
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
// For backward compatibility, we accumulate the pins in the same output type as before.
emit := res.Emit
lgcList := map[string]PinLsType{}
if !stream {
emit = func(v interface{}) error {
obj := v.(*PinLsOutputWrapper)
lgcList[obj.PinLsObject.Cid] = PinLsType{Type: obj.PinLsObject.Type}
return nil
}
}
var keys map[cid.Cid]RefKeyObject
if len(req.Arguments) > 0 {
keys, err = pinLsKeys(req.Context, req.Arguments, typeStr, n, api)
err = pinLsKeys(req, typeStr, n, api, emit)
} else {
keys, err = pinLsAll(req.Context, typeStr, n)
err = pinLsAll(req, typeStr, n.Pinning, n.DAG, emit)
}
if err != nil {
return err
}
refKeys := make(map[string]RefKeyObject, len(keys))
for k, v := range keys {
refKeys[enc.Encode(k)] = v
if !stream {
return cmds.EmitOnce(res, &PinLsOutputWrapper{
PinLsList: PinLsList{Keys: lgcList},
})
}
return cmds.EmitOnce(res, &RefKeyList{Keys: refKeys})
return nil
},
Type: RefKeyList{},
Type: &PinLsOutputWrapper{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *RefKeyList) error {
quiet, _ := req.Options[pinQuietOptionName].(bool)
cmds.JSON: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *PinLsOutputWrapper) error {
stream, _ := req.Options[pinStreamOptionName].(bool)
for k, v := range out.Keys {
enc := json.NewEncoder(w)
if stream {
return enc.Encode(out.PinLsObject)
}
return enc.Encode(out.PinLsList)
}),
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *PinLsOutputWrapper) error {
quiet, _ := req.Options[pinQuietOptionName].(bool)
stream, _ := req.Options[pinStreamOptionName].(bool)
if stream {
if quiet {
fmt.Fprintf(w, "%s\n", out.PinLsObject.Cid)
} else {
fmt.Fprintf(w, "%s %s\n", out.PinLsObject.Cid, out.PinLsObject.Type)
}
return nil
}
for k, v := range out.PinLsList.Keys {
if quiet {
fmt.Fprintf(w, "%s\n", k)
} else {
@ -377,6 +407,110 @@ Example:
},
}
// PinLsOutputWrapper is the output type of the pin ls command.
// Pin ls needs to output two different type depending on if it's streamed or not.
// We use this to bypass the cmds lib refusing to have interface{}
type PinLsOutputWrapper struct {
PinLsList
PinLsObject
}
// PinLsList is a set of pins with their type
type PinLsList struct {
Keys map[string]PinLsType
}
// PinLsType contains the type of a pin
type PinLsType struct {
Type string
}
// PinLsObject contains the description of a pin
type PinLsObject struct {
Cid string `json:",omitempty"`
Type string `json:",omitempty"`
}
func pinLsKeys(req *cmds.Request, typeStr string, n *core.IpfsNode, api coreiface.CoreAPI, emit func(value interface{}) error) error {
mode, ok := pin.StringToMode(typeStr)
if !ok {
return fmt.Errorf("invalid pin mode '%s'", typeStr)
}
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
for _, p := range req.Arguments {
c, err := api.ResolvePath(req.Context, path.New(p))
if err != nil {
return err
}
pinType, pinned, err := n.Pinning.IsPinnedWithType(req.Context, c.Cid(), mode)
if err != nil {
return err
}
if !pinned {
return fmt.Errorf("path '%s' is not pinned", p)
}
switch pinType {
case "direct", "indirect", "recursive", "internal":
default:
pinType = "indirect through " + pinType
}
err = emit(&PinLsOutputWrapper{
PinLsObject: PinLsObject{
Type: pinType,
Cid: enc.Encode(c.Cid()),
},
})
if err != nil {
return err
}
}
return nil
}
func pinLsAll(req *cmds.Request, typeStr string, pinning pin.Pinner, dag ipld.DAGService, emit func(value interface{}) error) error {
pinCh, errCh := coreapi.PinLsAll(req.Context, typeStr, pinning, dag)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
ctx := req.Context
loop:
for {
select {
case p, ok := <-pinCh:
if !ok {
break loop
}
if err := emit(&PinLsOutputWrapper{
PinLsObject: PinLsObject{
Type: p.Type(),
Cid: enc.Encode(p.Path().Cid()),
},
}); err != nil {
return err
}
case <-ctx.Done():
return ctx.Err()
}
}
err = <-errCh
return err
}
const (
pinUnpinOptionName = "unpin"
)
@ -385,15 +519,20 @@ var updatePinCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Update a recursive pin",
ShortDescription: `
Updates one pin to another, making sure that all objects in the new pin are
local. Then removes the old pin. This is an optimized version of adding the
new pin and removing the old one.
Efficiently pins a new object based on differences from an existing one and,
by default, removes the old pin.
This command is useful when the new pin contains many similarities or is a
derivative of an existing one, particularly for large objects. This allows a more
efficient DAG-traversal which fully skips already-pinned branches from the old
object. As a requirement, the old object needs to be an existing recursive
pin.
`,
},
Arguments: []cmds.Argument{
cmds.StringArg("from-path", true, false, "Path to old object."),
cmds.StringArg("to-path", true, false, "Path to new object to be pinned."),
cmds.StringArg("to-path", true, false, "Path to a new object to be pinned."),
},
Options: []cmds.Option{
cmds.BoolOption(pinUnpinOptionName, "Remove the old pin.").WithDefault(true),
@ -471,8 +610,10 @@ var verifyPinCmd = &cmds.Command{
explain: !quiet,
includeOk: verbose,
}
out := pinVerify(req.Context, n, opts, enc)
out, err := pinVerify(req.Context, n, opts, enc)
if err != nil {
return err
}
return res.Emit(out)
},
Type: PinVerifyRes{},
@ -491,83 +632,6 @@ var verifyPinCmd = &cmds.Command{
},
}
type RefKeyObject struct {
Type string
}
type RefKeyList struct {
Keys map[string]RefKeyObject
}
func pinLsKeys(ctx context.Context, args []string, typeStr string, n *core.IpfsNode, api coreiface.CoreAPI) (map[cid.Cid]RefKeyObject, error) {
mode, ok := pin.StringToMode(typeStr)
if !ok {
return nil, fmt.Errorf("invalid pin mode '%s'", typeStr)
}
keys := make(map[cid.Cid]RefKeyObject)
for _, p := range args {
c, err := api.ResolvePath(ctx, path.New(p))
if err != nil {
return nil, err
}
pinType, pinned, err := n.Pinning.IsPinnedWithType(c.Cid(), mode)
if err != nil {
return nil, err
}
if !pinned {
return nil, fmt.Errorf("path '%s' is not pinned", p)
}
switch pinType {
case "direct", "indirect", "recursive", "internal":
default:
pinType = "indirect through " + pinType
}
keys[c.Cid()] = RefKeyObject{
Type: pinType,
}
}
return keys, nil
}
func pinLsAll(ctx context.Context, typeStr string, n *core.IpfsNode) (map[cid.Cid]RefKeyObject, error) {
keys := make(map[cid.Cid]RefKeyObject)
AddToResultKeys := func(keyList []cid.Cid, typeStr string) {
for _, c := range keyList {
keys[c] = RefKeyObject{
Type: typeStr,
}
}
}
if typeStr == "direct" || typeStr == "all" {
AddToResultKeys(n.Pinning.DirectKeys(), "direct")
}
if typeStr == "indirect" || typeStr == "all" {
set := cid.NewSet()
for _, k := range n.Pinning.RecursiveKeys() {
err := dag.EnumerateChildren(ctx, dag.GetLinksWithDAG(n.DAG), k, set.Visit)
if err != nil {
return nil, err
}
}
AddToResultKeys(set.Keys(), "indirect")
}
if typeStr == "recursive" || typeStr == "all" {
AddToResultKeys(n.Pinning.RecursiveKeys(), "recursive")
}
return keys, nil
}
// PinVerifyRes is the result returned for each pin checked in "pin verify"
type PinVerifyRes struct {
Cid string
@ -591,13 +655,16 @@ type pinVerifyOpts struct {
includeOk bool
}
func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc cidenc.Encoder) <-chan interface{} {
func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc cidenc.Encoder) (<-chan interface{}, error) {
visited := make(map[cid.Cid]PinStatus)
bs := n.Blocks.Blockstore()
DAG := dag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
getLinks := dag.GetLinksWithDAG(DAG)
recPins := n.Pinning.RecursiveKeys()
recPins, err := n.Pinning.RecursiveKeys(ctx)
if err != nil {
return nil, err
}
var checkPin func(root cid.Cid) PinStatus
checkPin = func(root cid.Cid) PinStatus {
@ -653,7 +720,7 @@ func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc ci
}
}()
return out
return out, nil
}
// Format formats PinVerifyRes

View File

@ -10,10 +10,9 @@ import (
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
iaddr "github.com/ipfs/go-ipfs-addr"
cmds "github.com/ipfs/go-ipfs-cmds"
"github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
ping "github.com/libp2p/go-libp2p/p2p/protocol/ping"
ma "github.com/multiformats/go-multiaddr"
)
@ -207,13 +206,17 @@ trip latency information.
func ParsePeerParam(text string) (ma.Multiaddr, peer.ID, error) {
// Multiaddr
if strings.HasPrefix(text, "/") {
a, err := iaddr.ParseString(text)
maddr, err := ma.NewMultiaddr(text)
if err != nil {
return nil, "", err
}
return a.Transport(), a.ID(), nil
transport, id := peer.SplitAddr(maddr)
if id == "" {
return nil, "", peer.ErrInvalidAddr
}
return transport, id, nil
}
// Raw peer ID
p, err := peer.IDB58Decode(text)
p, err := peer.Decode(text)
return nil, p, err
}

View File

@ -7,15 +7,14 @@ import (
"io"
"strings"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/namesys/resolve"
cid "github.com/ipfs/go-cid"
cidenc "github.com/ipfs/go-cidutil/cidenc"
cmds "github.com/ipfs/go-ipfs-cmds"
ipld "github.com/ipfs/go-ipld-format"
path "github.com/ipfs/go-path"
iface "github.com/ipfs/interface-go-ipfs-core"
path "github.com/ipfs/interface-go-ipfs-core/path"
)
var refsEncoderMap = cmds.EncoderMap{
@ -75,7 +74,7 @@ NOTE: List all references recursively by using the flag '-r'.
}
ctx := req.Context
n, err := cmdenv.GetNode(env)
api, err := cmdenv.GetApi(env, req)
if err != nil {
return err
}
@ -103,14 +102,14 @@ NOTE: List all references recursively by using the flag '-r'.
format = "<src> -> <dst>"
}
objs, err := objectsForPaths(ctx, n, req.Arguments)
objs, err := objectsForPaths(ctx, api, req.Arguments)
if err != nil {
return err
}
rw := RefWriter{
res: res,
DAG: n.DAG,
DAG: api.Dag(),
Ctx: ctx,
Unique: unique,
PrintFmt: format,
@ -165,15 +164,10 @@ Displays the hashes of all local objects.
Type: RefWrapper{},
}
func objectsForPaths(ctx context.Context, n *core.IpfsNode, paths []string) ([]ipld.Node, error) {
func objectsForPaths(ctx context.Context, n iface.CoreAPI, paths []string) ([]ipld.Node, error) {
objects := make([]ipld.Node, len(paths))
for i, sp := range paths {
p, err := path.ParsePath(sp)
if err != nil {
return nil, err
}
o, err := resolve.Resolve(ctx, n.Namesys, n.Resolver, p)
o, err := n.ResolveNode(ctx, path.New(sp))
if err != nil {
return nil, err
}

View File

@ -6,7 +6,6 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"sync"
@ -20,7 +19,6 @@ import (
cid "github.com/ipfs/go-cid"
bstore "github.com/ipfs/go-ipfs-blockstore"
cmds "github.com/ipfs/go-ipfs-cmds"
config "github.com/ipfs/go-ipfs-config"
)
type RepoVersion struct {
@ -150,8 +148,8 @@ Version string The repo version.
`,
},
Options: []cmds.Option{
cmds.BoolOption(repoSizeOnlyOptionName, "Only report RepoSize and StorageMax."),
cmds.BoolOption(repoHumanOptionName, "Print sizes in human readable format (e.g., 1K 234M 2G)"),
cmds.BoolOption(repoSizeOnlyOptionName, "s", "Only report RepoSize and StorageMax."),
cmds.BoolOption(repoHumanOptionName, "H", "Print sizes in human readable format (e.g., 1K 234M 2G)"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
@ -216,44 +214,11 @@ var repoFsckCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Remove repo lockfiles.",
ShortDescription: `
'ipfs repo fsck' is a plumbing command that will remove repo and level db
lockfiles, as well as the api file. This command can only run when no ipfs
daemons are running.
'ipfs repo fsck' is now a no-op.
`,
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
configRoot, err := cmdenv.GetConfigRoot(env)
if err != nil {
return err
}
dsPath, err := config.DataStorePath(configRoot)
if err != nil {
return err
}
dsLockFile := filepath.Join(dsPath, "LOCK") // TODO: get this lockfile programmatically
repoLockFile := filepath.Join(configRoot, fsrepo.LockFile)
apiFile := filepath.Join(configRoot, "api") // TODO: get this programmatically
log.Infof("Removing repo lockfile: %s", repoLockFile)
log.Infof("Removing datastore lockfile: %s", dsLockFile)
log.Infof("Removing api file: %s", apiFile)
err = os.Remove(repoLockFile)
if err != nil && !os.IsNotExist(err) {
return err
}
err = os.Remove(dsLockFile)
if err != nil && !os.IsNotExist(err) {
return err
}
err = os.Remove(apiFile)
if err != nil && !os.IsNotExist(err) {
return err
}
return cmds.EmitOnce(res, &MessageOutput{"Lockfiles have been removed.\n"})
return cmds.EmitOnce(res, &MessageOutput{"`ipfs repo fsck` is deprecated and does nothing.\n"})
},
Type: MessageOutput{},
Encoders: cmds.EncoderMap{

View File

@ -144,7 +144,7 @@ var rootSubcommands = map[string]*cmds.Command{
"swarm": SwarmCmd,
"tar": TarCmd,
"file": unixfs.UnixFSCmd,
"update": ExternalBinary(),
"update": ExternalBinary("Please see https://git.io/fjylH for installation instructions."),
"urlstore": urlStoreCmd,
"version": VersionCmd,
"shutdown": daemonShutdownCmd,

View File

@ -10,9 +10,9 @@ import (
humanize "github.com/dustin/go-humanize"
cmds "github.com/ipfs/go-ipfs-cmds"
metrics "github.com/libp2p/go-libp2p-metrics"
peer "github.com/libp2p/go-libp2p-peer"
protocol "github.com/libp2p/go-libp2p-protocol"
metrics "github.com/libp2p/go-libp2p-core/metrics"
peer "github.com/libp2p/go-libp2p-core/peer"
protocol "github.com/libp2p/go-libp2p-core/protocol"
)
var StatsCmd = &cmds.Command{
@ -109,7 +109,7 @@ Example:
var pid peer.ID
if pfound {
checkpid, err := peer.IDB58Decode(pstr)
checkpid, err := peer.Decode(pstr)
if err != nil {
return err
}

View File

@ -15,12 +15,10 @@ import (
repo "github.com/ipfs/go-ipfs/repo"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
iaddr "github.com/ipfs/go-ipfs-addr"
cmds "github.com/ipfs/go-ipfs-cmds"
config "github.com/ipfs/go-ipfs-config"
inet "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
inet "github.com/libp2p/go-libp2p-core/network"
peer "github.com/libp2p/go-libp2p-core/peer"
swarm "github.com/libp2p/go-libp2p-swarm"
mafilter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
@ -300,10 +298,11 @@ var swarmAddrsLocalCmd = &cmds.Command{
}
var addrs []string
p2pProtocolName := ma.ProtocolWithCode(ma.P_P2P).Name
for _, addr := range maddrs {
saddr := addr.String()
if showid {
saddr = path.Join(saddr, "ipfs", self.ID().Pretty())
saddr = path.Join(saddr, p2pProtocolName, self.ID().Pretty())
}
addrs = append(addrs, saddr)
}
@ -356,7 +355,7 @@ var swarmConnectCmd = &cmds.Command{
The address format is an IPFS multiaddr:
ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
ipfs swarm connect /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
`,
},
Arguments: []cmds.Argument{
@ -370,7 +369,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3
addrs := req.Arguments
pis, err := peersWithAddresses(req.Context, addrs)
pis, err := parseAddresses(req.Context, addrs)
if err != nil {
return err
}
@ -401,7 +400,7 @@ var swarmDisconnectCmd = &cmds.Command{
'ipfs swarm disconnect' closes a connection to a peer address. The address
format is an IPFS multiaddr:
ipfs swarm disconnect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
ipfs swarm disconnect /ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
The disconnect is not permanent; if ipfs needs to talk to that address later,
it will reconnect.
@ -416,19 +415,34 @@ it will reconnect.
return err
}
iaddrs, err := parseAddresses(req.Arguments)
addrs, err := parseAddresses(req.Context, req.Arguments)
if err != nil {
return err
}
output := make([]string, len(iaddrs))
for i, addr := range iaddrs {
output[i] = "disconnect " + addr.ID().Pretty()
if err := api.Swarm().Disconnect(req.Context, addr.Multiaddr()); err != nil {
output[i] += " failure: " + err.Error()
} else {
output[i] += " success"
output := make([]string, 0, len(addrs))
for _, ainfo := range addrs {
maddrs, err := peer.AddrInfoToP2pAddrs(&ainfo)
if err != nil {
return err
}
// FIXME: This will print:
//
// disconnect QmFoo success
// disconnect QmFoo success
// ...
//
// Once per address specified. However, I'm not sure of
// a good backwards compat solution. Right now, I'm just
// preserving the current behavior.
for _, addr := range maddrs {
msg := "disconnect " + ainfo.ID.Pretty()
if err := api.Swarm().Disconnect(req.Context, addr); err != nil {
msg += " failure: " + err.Error()
} else {
msg += " success"
}
output = append(output, msg)
}
}
return cmds.EmitOnce(res, &stringList{output})
@ -440,63 +454,15 @@ it will reconnect.
}
// parseAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns slices of multiaddrs and peerids.
func parseAddresses(addrs []string) (iaddrs []iaddr.IPFSAddr, err error) {
iaddrs = make([]iaddr.IPFSAddr, len(addrs))
for i, saddr := range addrs {
iaddrs[i], err = iaddr.ParseString(saddr)
if err != nil {
return nil, cmds.ClientError("invalid peer address: " + err.Error())
}
}
return
}
// parseMultiaddrs is a function that takes in a slice of peer multiaddr
// and returns slices of multiaddrs and peerids
func parseMultiaddrs(maddrs []ma.Multiaddr) (iaddrs []iaddr.IPFSAddr, err error) {
iaddrs = make([]iaddr.IPFSAddr, len(maddrs))
for i, maddr := range maddrs {
iaddrs[i], err = iaddr.ParseMultiaddr(maddr)
if err != nil {
return nil, cmds.ClientError("invalid peer address: " + err.Error())
}
}
return
}
// peersWithAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns a slice of properly constructed peers
func peersWithAddresses(ctx context.Context, addrs []string) ([]pstore.PeerInfo, error) {
func parseAddresses(ctx context.Context, addrs []string) ([]peer.AddrInfo, error) {
// resolve addresses
maddrs, err := resolveAddresses(ctx, addrs)
if err != nil {
return nil, err
}
iaddrs, err := parseMultiaddrs(maddrs)
if err != nil {
return nil, err
}
peers := make(map[peer.ID][]ma.Multiaddr, len(iaddrs))
for _, iaddr := range iaddrs {
id := iaddr.ID()
current, ok := peers[id]
if tpt := iaddr.Transport(); tpt != nil {
peers[id] = append(current, tpt)
} else if !ok {
peers[id] = nil
}
}
pis := make([]pstore.PeerInfo, 0, len(peers))
for id, maddrs := range peers {
pis = append(pis, pstore.PeerInfo{
ID: id,
Addrs: maddrs,
})
}
return pis, nil
return peer.AddrInfosFromP2pAddrs(maddrs...)
}
// resolveAddresses resolves addresses parallelly
@ -532,7 +498,7 @@ func resolveAddresses(ctx context.Context, addrs []string) ([]ma.Multiaddr, erro
// filter out addresses that still doesn't end in `ipfs/Qm...`
found := 0
for _, raddr := range raddrs {
if _, last := ma.SplitLast(raddr); last.Protocol().Code == ma.P_IPFS {
if _, last := ma.SplitLast(raddr); last != nil && last.Protocol().Code == ma.P_IPFS {
maddrC <- raddr
found++
}
@ -620,8 +586,6 @@ var swarmFiltersAddCmd = &cmds.Command{
Tagline: "Add an address filter.",
ShortDescription: `
'ipfs swarm filters add' will add an address filter to the daemons swarm.
Filters applied this way will not persist daemon reboots, to achieve that,
add your filters to the ipfs config file.
`,
},
Arguments: []cmds.Argument{
@ -684,8 +648,6 @@ var swarmFiltersRmCmd = &cmds.Command{
Tagline: "Remove an address filter.",
ShortDescription: `
'ipfs swarm filters rm' will remove an address filter from the daemons swarm.
Filters removed this way will not persist daemon reboots, to achieve that,
remove your filters from the ipfs config file.
`,
},
Arguments: []cmds.Argument{

View File

@ -5,12 +5,11 @@ import (
"io"
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/namesys/resolve"
tar "github.com/ipfs/go-ipfs/tar"
"github.com/ipfs/go-ipfs-cmds"
dag "github.com/ipfs/go-merkledag"
"github.com/ipfs/go-path"
path "github.com/ipfs/interface-go-ipfs-core/path"
)
var TarCmd = &cmds.Command{
@ -37,7 +36,7 @@ represent it.
cmds.FileArg("file", true, false, "Tar file to add.").EnableStdin(),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
api, err := cmdenv.GetApi(env, req)
if err != nil {
return err
}
@ -53,7 +52,7 @@ represent it.
return err
}
node, err := tar.ImportTar(req.Context, file, nd.DAG)
node, err := tar.ImportTar(req.Context, file, api.Dag())
if err != nil {
return err
}
@ -86,17 +85,12 @@ var tarCatCmd = &cmds.Command{
cmds.StringArg("path", true, false, "ipfs path of archive to export.").EnableStdin(),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
nd, err := cmdenv.GetNode(env)
api, err := cmdenv.GetApi(env, req)
if err != nil {
return err
}
p, err := path.ParsePath(req.Arguments[0])
if err != nil {
return err
}
root, err := resolve.Resolve(req.Context, nd.Namesys, nd.Resolver, p)
root, err := api.ResolveNode(req.Context, path.New(req.Arguments[0]))
if err != nil {
return err
}
@ -106,7 +100,7 @@ var tarCatCmd = &cmds.Command{
return dag.ErrNotProtobuf
}
r, err := tar.ExportTar(req.Context, rootpb, nd.DAG)
r, err := tar.ExportTar(req.Context, rootpb, api.Dag())
if err != nil {
return err
}

View File

@ -5,8 +5,8 @@ import (
"io"
"net/url"
filestore "github.com/ipfs/go-filestore"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
filestore "github.com/ipfs/go-ipfs/filestore"
cmds "github.com/ipfs/go-ipfs-cmds"
files "github.com/ipfs/go-ipfs-files"

View File

@ -54,21 +54,25 @@ var VersionCmd = &cmds.Command{
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, version *VersionOutput) error {
commit, _ := req.Options[versionCommitOptionName].(bool)
commitTxt := ""
if commit {
commitTxt = "-" + version.Commit
}
all, _ := req.Options[versionAllOptionName].(bool)
if all {
out := fmt.Sprintf("go-ipfs version: %s-%s\n"+
ver := version.Version
if version.Commit != "" {
ver += "-" + version.Commit
}
out := fmt.Sprintf("go-ipfs version: %s\n"+
"Repo version: %s\nSystem version: %s\nGolang version: %s\n",
version.Version, version.Commit, version.Repo, version.System, version.Golang)
ver, version.Repo, version.System, version.Golang)
fmt.Fprint(w, out)
return nil
}
commit, _ := req.Options[versionCommitOptionName].(bool)
commitTxt := ""
if commit && version.Commit != "" {
commitTxt = "-" + version.Commit
}
repo, _ := req.Options[versionRepoOptionName].(bool)
if repo {
fmt.Fprintln(w, version.Repo)

View File

@ -13,51 +13,45 @@ import (
"context"
"io"
version "github.com/ipfs/go-ipfs"
"github.com/ipfs/go-filestore"
"github.com/ipfs/go-ipfs-pinner"
bserv "github.com/ipfs/go-blockservice"
"github.com/ipfs/go-graphsync"
bstore "github.com/ipfs/go-ipfs-blockstore"
exchange "github.com/ipfs/go-ipfs-exchange-interface"
"github.com/ipfs/go-ipfs-provider"
ipld "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log"
mfs "github.com/ipfs/go-mfs"
resolver "github.com/ipfs/go-path/resolver"
goprocess "github.com/jbenet/goprocess"
connmgr "github.com/libp2p/go-libp2p-core/connmgr"
ic "github.com/libp2p/go-libp2p-core/crypto"
p2phost "github.com/libp2p/go-libp2p-core/host"
metrics "github.com/libp2p/go-libp2p-core/metrics"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
routing "github.com/libp2p/go-libp2p-core/routing"
ddht "github.com/libp2p/go-libp2p-kad-dht/dual"
pubsub "github.com/libp2p/go-libp2p-pubsub"
psrouter "github.com/libp2p/go-libp2p-pubsub-router"
record "github.com/libp2p/go-libp2p-record"
"github.com/libp2p/go-libp2p/p2p/discovery"
p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
"github.com/ipfs/go-ipfs/core/bootstrap"
"github.com/ipfs/go-ipfs/core/node"
"github.com/ipfs/go-ipfs/core/node/libp2p"
"github.com/ipfs/go-ipfs/filestore"
"github.com/ipfs/go-ipfs/fuse/mount"
"github.com/ipfs/go-ipfs/namesys"
ipnsrp "github.com/ipfs/go-ipfs/namesys/republisher"
"github.com/ipfs/go-ipfs/p2p"
"github.com/ipfs/go-ipfs/pin"
"github.com/ipfs/go-ipfs/provider"
"github.com/ipfs/go-ipfs/repo"
rp "github.com/ipfs/go-ipfs/reprovide"
bserv "github.com/ipfs/go-blockservice"
bstore "github.com/ipfs/go-ipfs-blockstore"
exchange "github.com/ipfs/go-ipfs-exchange-interface"
ipld "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log"
"github.com/ipfs/go-mfs"
"github.com/ipfs/go-path/resolver"
"github.com/jbenet/goprocess"
autonat "github.com/libp2p/go-libp2p-autonat-svc"
ic "github.com/libp2p/go-libp2p-crypto"
p2phost "github.com/libp2p/go-libp2p-host"
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr"
dht "github.com/libp2p/go-libp2p-kad-dht"
metrics "github.com/libp2p/go-libp2p-metrics"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
pubsub "github.com/libp2p/go-libp2p-pubsub"
psrouter "github.com/libp2p/go-libp2p-pubsub-router"
record "github.com/libp2p/go-libp2p-record"
routing "github.com/libp2p/go-libp2p-routing"
"github.com/libp2p/go-libp2p/p2p/discovery"
p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
"github.com/libp2p/go-libp2p/p2p/protocol/identify"
)
var log = logging.Logger("core")
func init() {
identify.ClientVersion = "go-ipfs/" + version.CurrentVersionNumber + "/" + version.CurrentCommit
}
// IpfsNode is IPFS Core module. It represents an IPFS instance.
type IpfsNode struct {
@ -73,33 +67,32 @@ type IpfsNode struct {
PNetFingerprint libp2p.PNetFingerprint `optional:"true"` // fingerprint of private network
// Services
Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances
Blockstore bstore.GCBlockstore // the block store (lower level)
Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore
BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping
GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc
Blocks bserv.BlockService // the block service, get/add blocks.
DAG ipld.DAGService // the merkle dag service, get/add objects.
Resolver *resolver.Resolver // the path resolution system
Reporter metrics.Reporter `optional:"true"`
Discovery discovery.Service `optional:"true"`
Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances
Blockstore bstore.GCBlockstore // the block store (lower level)
Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore
BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping
GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc
Blocks bserv.BlockService // the block service, get/add blocks.
DAG ipld.DAGService // the merkle dag service, get/add objects.
Resolver *resolver.Resolver // the path resolution system
Reporter *metrics.BandwidthCounter `optional:"true"`
Discovery discovery.Service `optional:"true"`
FilesRoot *mfs.Root
RecordValidator record.Validator
// Online
PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
Routing routing.IpfsRouting `optional:"true"` // the routing system. recommend ipfs-dht
Exchange exchange.Interface // the block exchange + strategy (bitswap)
Namesys namesys.NameSystem // the name system, resolves paths to hashes
Provider provider.Provider // the value provider system
Reprovider *rp.Reprovider `optional:"true"` // the value reprovider system
IpnsRepub *ipnsrp.Republisher `optional:"true"`
PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
Routing routing.Routing `optional:"true"` // the routing system. recommend ipfs-dht
Exchange exchange.Interface // the block exchange + strategy (bitswap)
Namesys namesys.NameSystem // the name system, resolves paths to hashes
Provider provider.System // the value provider system
IpnsRepub *ipnsrp.Republisher `optional:"true"`
GraphExchange graphsync.GraphExchange `optional:"true"`
AutoNAT *autonat.AutoNATService `optional:"true"`
PubSub *pubsub.PubSub `optional:"true"`
PSRouter *psrouter.PubsubValueStore `optional:"true"`
DHT *dht.IpfsDHT `optional:"true"`
DHT *ddht.DHT `optional:"true"`
P2P *p2p.P2P `optional:"true"`
Process goprocess.Process
@ -147,10 +140,10 @@ func (n *IpfsNode) Bootstrap(cfg bootstrap.BootstrapConfig) error {
// if the caller did not specify a bootstrap peer function, get the
// freshest bootstrap peers from config. this responds to live changes.
if cfg.BootstrapPeers == nil {
cfg.BootstrapPeers = func() []pstore.PeerInfo {
cfg.BootstrapPeers = func() []peer.AddrInfo {
ps, err := n.loadBootstrapPeers()
if err != nil {
log.Warning("failed to parse bootstrap peers from config")
log.Warn("failed to parse bootstrap peers from config")
return nil
}
return ps
@ -162,17 +155,13 @@ func (n *IpfsNode) Bootstrap(cfg bootstrap.BootstrapConfig) error {
return err
}
func (n *IpfsNode) loadBootstrapPeers() ([]pstore.PeerInfo, error) {
func (n *IpfsNode) loadBootstrapPeers() ([]peer.AddrInfo, error) {
cfg, err := n.Repo.Config()
if err != nil {
return nil, err
}
parsed, err := cfg.BootstrapPeers()
if err != nil {
return nil, err
}
return bootstrap.Peers.ToPeerInfos(parsed), nil
return cfg.BootstrapPeers()
}
type ConstructPeerHostOpts struct {
@ -180,5 +169,5 @@ type ConstructPeerHostOpts struct {
DisableNatPortMap bool
DisableRelay bool
EnableRelayHop bool
ConnectionManager ifconnmgr.ConnManager
ConnectionManager connmgr.ConnManager
}

View File

@ -7,14 +7,14 @@ import (
"io"
"io/ioutil"
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
pin "github.com/ipfs/go-ipfs/pin"
blocks "github.com/ipfs/go-block-format"
cid "github.com/ipfs/go-cid"
pin "github.com/ipfs/go-ipfs-pinner"
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
)
type BlockAPI CoreAPI
@ -56,7 +56,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
if settings.Pin {
api.pinning.PinWithMode(b.Cid(), pin.Recursive)
if err := api.pinning.Flush(); err != nil {
if err := api.pinning.Flush(ctx); err != nil {
return nil, err
}
}
@ -91,7 +91,7 @@ func (api *BlockAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.BlockRm
cids := []cid.Cid{rp.Cid()}
o := util.RmBlocksOpts{Force: settings.Force}
out, err := util.RmBlocks(api.blockstore, api.pinning, cids, o)
out, err := util.RmBlocks(ctx, api.blockstore, api.pinning, cids, o)
if err != nil {
return err
}

View File

@ -18,30 +18,30 @@ import (
"errors"
"fmt"
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/core/node"
"github.com/ipfs/go-ipfs/namesys"
"github.com/ipfs/go-ipfs/pin"
"github.com/ipfs/go-ipfs/provider"
"github.com/ipfs/go-ipfs/repo"
bserv "github.com/ipfs/go-blockservice"
"github.com/ipfs/go-ipfs-blockstore"
"github.com/ipfs/go-ipfs-exchange-interface"
offlinexch "github.com/ipfs/go-ipfs-exchange-offline"
"github.com/ipfs/go-ipfs-pinner"
"github.com/ipfs/go-ipfs-provider"
offlineroute "github.com/ipfs/go-ipfs-routing/offline"
ipld "github.com/ipfs/go-ipld-format"
logging "github.com/ipfs/go-log"
dag "github.com/ipfs/go-merkledag"
coreiface "github.com/ipfs/interface-go-ipfs-core"
"github.com/ipfs/interface-go-ipfs-core/options"
ci "github.com/libp2p/go-libp2p-crypto"
p2phost "github.com/libp2p/go-libp2p-host"
"github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
ci "github.com/libp2p/go-libp2p-core/crypto"
p2phost "github.com/libp2p/go-libp2p-core/host"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
routing "github.com/libp2p/go-libp2p-core/routing"
pubsub "github.com/libp2p/go-libp2p-pubsub"
record "github.com/libp2p/go-libp2p-record"
"github.com/libp2p/go-libp2p-routing"
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/core/node"
"github.com/ipfs/go-ipfs/namesys"
"github.com/ipfs/go-ipfs/repo"
)
var log = logging.Logger("core/coreapi")
@ -66,9 +66,9 @@ type CoreAPI struct {
exchange exchange.Interface
namesys namesys.NameSystem
routing routing.IpfsRouting
routing routing.Routing
provider provider.Provider
provider provider.System
pubSub *pubsub.PubSub

View File

@ -3,9 +3,8 @@ package coreapi
import (
"context"
"github.com/ipfs/go-ipfs/pin"
cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-ipfs-pinner"
ipld "github.com/ipfs/go-ipld-format"
)
@ -26,7 +25,7 @@ func (adder *pinningAdder) Add(ctx context.Context, nd ipld.Node) error {
adder.pinning.PinWithMode(nd.Cid(), pin.Recursive)
return adder.pinning.Flush()
return adder.pinning.Flush(ctx)
}
func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
@ -45,7 +44,7 @@ func (adder *pinningAdder) AddMany(ctx context.Context, nds []ipld.Node) error {
}
}
return adder.pinning.Flush()
return adder.pinning.Flush(ctx)
}
func (api *dagAPI) Pinning() ipld.NodeAdder {

View File

@ -13,28 +13,27 @@ import (
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
routing "github.com/libp2p/go-libp2p-routing"
peer "github.com/libp2p/go-libp2p-core/peer"
routing "github.com/libp2p/go-libp2p-core/routing"
)
type DhtAPI CoreAPI
func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (pstore.PeerInfo, error) {
func (api *DhtAPI) FindPeer(ctx context.Context, p peer.ID) (peer.AddrInfo, error) {
err := api.checkOnline(false)
if err != nil {
return pstore.PeerInfo{}, err
return peer.AddrInfo{}, err
}
pi, err := api.routing.FindPeer(ctx, peer.ID(p))
if err != nil {
return pstore.PeerInfo{}, err
return peer.AddrInfo{}, err
}
return pi, nil
}
func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan pstore.PeerInfo, error) {
func (api *DhtAPI) FindProviders(ctx context.Context, p path.Path, opts ...caopts.DhtFindProvidersOption) (<-chan peer.AddrInfo, error) {
settings, err := caopts.DhtFindProvidersOptions(opts...)
if err != nil {
return nil, err
@ -98,7 +97,7 @@ func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.D
return nil
}
func provideKeys(ctx context.Context, r routing.IpfsRouting, cids []cid.Cid) error {
func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
for _, c := range cids {
err := r.Provide(ctx, c, true)
if err != nil {
@ -108,14 +107,14 @@ func provideKeys(ctx context.Context, r routing.IpfsRouting, cids []cid.Cid) err
return nil
}
func provideKeysRec(ctx context.Context, r routing.IpfsRouting, bs blockstore.Blockstore, cids []cid.Cid) error {
func provideKeysRec(ctx context.Context, r routing.Routing, bs blockstore.Blockstore, cids []cid.Cid) error {
provided := cidutil.NewStreamingSet()
errCh := make(chan error)
go func() {
dserv := dag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
for _, c := range cids {
err := dag.EnumerateChildrenAsync(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx))
err := dag.Walk(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx))
if err != nil {
errCh <- err
}

View File

@ -11,8 +11,8 @@ import (
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
crypto "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
crypto "github.com/libp2p/go-libp2p-core/crypto"
peer "github.com/libp2p/go-libp2p-core/peer"
)
type KeyAPI CoreAPI

View File

@ -13,9 +13,8 @@ import (
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/libp2p/go-libp2p-crypto"
ci "github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-libp2p-peer"
ci "github.com/libp2p/go-libp2p-core/crypto"
peer "github.com/libp2p/go-libp2p-core/peer"
)
type NameAPI CoreAPI
@ -139,11 +138,17 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
return p, err
}
func keylookup(self ci.PrivKey, kstore keystore.Keystore, k string) (crypto.PrivKey, error) {
func keylookup(self ci.PrivKey, kstore keystore.Keystore, k string) (ci.PrivKey, error) {
////////////////////
// Lookup by name //
////////////////////
// First, lookup self.
if k == "self" {
return self, nil
}
// Then, look in the keystore.
res, err := kstore.Get(k)
if res != nil {
return res, nil
@ -158,20 +163,36 @@ func keylookup(self ci.PrivKey, kstore keystore.Keystore, k string) (crypto.Priv
return nil, err
}
//////////////////
// Lookup by ID //
//////////////////
targetPid, err := peer.Decode(k)
if err != nil {
return nil, keystore.ErrNoSuchKey
}
// First, check self.
pid, err := peer.IDFromPrivateKey(self)
if err != nil {
return nil, fmt.Errorf("failed to determine peer ID for private key: %w", err)
}
if pid == targetPid {
return self, nil
}
// Then, look in the keystore.
for _, key := range keys {
privKey, err := kstore.Get(key)
if err != nil {
return nil, err
}
pubKey := privKey.GetPublic()
pid, err := peer.IDFromPublicKey(pubKey)
pid, err := peer.IDFromPrivateKey(privKey)
if err != nil {
return nil, err
}
if pid.Pretty() == k {
if targetPid == pid {
return privKey, nil
}
}

View File

@ -11,12 +11,11 @@ import (
"io"
"io/ioutil"
"github.com/ipfs/go-ipfs/dagutils"
"github.com/ipfs/go-ipfs/pin"
cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-ipfs-pinner"
ipld "github.com/ipfs/go-ipld-format"
dag "github.com/ipfs/go-merkledag"
"github.com/ipfs/go-merkledag/dagutils"
ft "github.com/ipfs/go-unixfs"
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
@ -119,7 +118,7 @@ func (api *ObjectAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Obj
if options.Pin {
api.pinning.PinWithMode(dagnode.Cid(), pin.Recursive)
err = api.pinning.Flush()
err = api.pinning.Flush(ctx)
if err != nil {
return nil, err
}
@ -307,7 +306,7 @@ func (api *ObjectAPI) Diff(ctx context.Context, before ipath.Path, after ipath.P
out := make([]coreiface.ObjectChange, len(changes))
for i, change := range changes {
out[i] = coreiface.ObjectChange{
Type: change.Type,
Type: coreiface.ChangeType(change.Type),
Path: change.Path,
}
@ -339,7 +338,7 @@ func deserializeNode(nd *Node, dataFieldEncoding string) (*dag.ProtoNode, error)
}
dagnode.SetData(data)
default:
return nil, fmt.Errorf("unkown data field encoding")
return nil, fmt.Errorf("unknown data field encoding")
}
links := make([]*ipld.Link, len(nd.Links))

View File

@ -3,14 +3,15 @@ package coreapi
import (
"context"
"fmt"
bserv "github.com/ipfs/go-blockservice"
cid "github.com/ipfs/go-cid"
"github.com/ipfs/go-cid"
offline "github.com/ipfs/go-ipfs-exchange-offline"
merkledag "github.com/ipfs/go-merkledag"
pin "github.com/ipfs/go-ipfs-pinner"
ipld "github.com/ipfs/go-ipld-format"
"github.com/ipfs/go-merkledag"
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
path "github.com/ipfs/interface-go-ipfs-core/path"
"github.com/ipfs/interface-go-ipfs-core/path"
)
type PinAPI CoreAPI
@ -37,7 +38,7 @@ func (api *PinAPI) Add(ctx context.Context, p path.Path, opts ...caopts.PinAddOp
return err
}
return api.pinning.Flush()
return api.pinning.Flush(ctx)
}
func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreiface.Pin, error) {
@ -75,7 +76,7 @@ func (api *PinAPI) Rm(ctx context.Context, p path.Path, opts ...caopts.PinRmOpti
return err
}
return api.pinning.Flush()
return api.pinning.Flush(ctx)
}
func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opts ...caopts.PinUpdateOption) error {
@ -101,7 +102,7 @@ func (api *PinAPI) Update(ctx context.Context, from path.Path, to path.Path, opt
return err
}
return api.pinning.Flush()
return api.pinning.Flush(ctx)
}
type pinStatus struct {
@ -137,7 +138,10 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
bs := api.blockstore
DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
getLinks := merkledag.GetLinksWithDAG(DAG)
recPins := api.pinning.RecursiveKeys()
recPins, err := api.pinning.RecursiveKeys(ctx)
if err != nil {
return nil, err
}
var checkPin func(root cid.Cid) *pinStatus
checkPin = func(root cid.Cid) *pinStatus {
@ -191,41 +195,122 @@ func (p *pinInfo) Type() string {
}
func (api *PinAPI) pinLsAll(typeStr string, ctx context.Context) ([]coreiface.Pin, error) {
pinCh, errCh := PinLsAll(ctx, typeStr, api.pinning, api.dag)
keys := make(map[cid.Cid]*pinInfo)
var pins []coreiface.Pin
loop:
for {
select {
case p, ok := <-pinCh:
if !ok {
break loop
}
pins = append(pins, p)
case <-ctx.Done():
return nil, ctx.Err()
}
}
err := <-errCh
if err != nil {
return nil, err
}
AddToResultKeys := func(keyList []cid.Cid, typeStr string) {
return pins, nil
}
// PinLsAll is an internal function for returning a list of pins
func PinLsAll(ctx context.Context, typeStr string, pin pin.Pinner, dag ipld.DAGService) (chan coreiface.Pin, chan error) {
ch := make(chan coreiface.Pin, 32)
errCh := make(chan error, 1)
keys := cid.NewSet()
AddToResultKeys := func(keyList []cid.Cid, typeStr string) error {
for _, c := range keyList {
keys[c] = &pinInfo{
pinType: typeStr,
path: path.IpldPath(c),
if keys.Visit(c) {
select {
case ch <- &pinInfo{
pinType: typeStr,
path: path.IpldPath(c),
}:
case <-ctx.Done():
return ctx.Err()
}
}
}
return nil
}
if typeStr == "direct" || typeStr == "all" {
AddToResultKeys(api.pinning.DirectKeys(), "direct")
}
if typeStr == "indirect" || typeStr == "all" {
set := cid.NewSet()
for _, k := range api.pinning.RecursiveKeys() {
err := merkledag.EnumerateChildren(ctx, merkledag.GetLinksWithDAG(api.dag), k, set.Visit)
go func() {
defer close(ch)
defer close(errCh)
if typeStr == "direct" || typeStr == "all" {
dkeys, err := pin.DirectKeys(ctx)
if err != nil {
return nil, err
errCh <- err
return
}
if err := AddToResultKeys(dkeys, "direct"); err != nil {
errCh <- err
return
}
}
AddToResultKeys(set.Keys(), "indirect")
}
if typeStr == "recursive" || typeStr == "all" {
AddToResultKeys(api.pinning.RecursiveKeys(), "recursive")
}
if typeStr == "recursive" || typeStr == "all" {
rkeys, err := pin.RecursiveKeys(ctx)
if err != nil {
errCh <- err
return
}
if err := AddToResultKeys(rkeys, "recursive"); err != nil {
errCh <- err
return
}
}
if typeStr == "indirect" || typeStr == "all" {
rkeys, err := pin.RecursiveKeys(ctx)
if err != nil {
errCh <- err
return
}
out := make([]coreiface.Pin, 0, len(keys))
for _, v := range keys {
out = append(out, v)
}
// If we're only listing indirect pins, we need to
// explicitly mark direct/recursive pins so we don't
// send them.
if typeStr == "indirect" {
dkeys, err := pin.DirectKeys(ctx)
if err != nil {
errCh <- err
return
}
return out, nil
for _, k := range dkeys {
keys.Add(k)
}
for _, k := range rkeys {
keys.Add(k)
}
}
indirectKeys := cid.NewSet()
for _, k := range rkeys {
err := merkledag.Walk(ctx, merkledag.GetLinksWithDAG(dag), k, func(c cid.Cid) bool {
r := indirectKeys.Visit(c)
if r {
if err := AddToResultKeys([]cid.Cid{c}, "indirect"); err != nil {
return false
}
}
return r
}, merkledag.SkipRoot(), merkledag.Concurrent())
if err != nil {
errCh <- err
return
}
}
}
}()
return ch, errCh
}
func (api *PinAPI) core() coreiface.CoreAPI {

View File

@ -10,11 +10,10 @@ import (
cid "github.com/ipfs/go-cid"
coreiface "github.com/ipfs/interface-go-ipfs-core"
caopts "github.com/ipfs/interface-go-ipfs-core/options"
p2phost "github.com/libp2p/go-libp2p-host"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
p2phost "github.com/libp2p/go-libp2p-core/host"
peer "github.com/libp2p/go-libp2p-core/peer"
routing "github.com/libp2p/go-libp2p-core/routing"
pubsub "github.com/libp2p/go-libp2p-pubsub"
routing "github.com/libp2p/go-libp2p-routing"
)
type PubSubAPI CoreAPI
@ -57,6 +56,7 @@ func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) er
return err
}
//nolint deprecated
return api.pubSub.Publish(topic, data)
}
@ -71,6 +71,7 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt
return nil, err
}
//nolint deprecated
sub, err := api.pubSub.Subscribe(topic)
if err != nil {
return nil, err
@ -93,7 +94,7 @@ func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopt
return &pubSubSubscription{cancel, sub}, nil
}
func connectToPubSubPeers(ctx context.Context, r routing.IpfsRouting, ph p2phost.Host, cid cid.Cid) {
func connectToPubSubPeers(ctx context.Context, r routing.Routing, ph p2phost.Host, cid cid.Cid) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
@ -101,7 +102,7 @@ func connectToPubSubPeers(ctx context.Context, r routing.IpfsRouting, ph p2phost
var wg sync.WaitGroup
for p := range provs {
wg.Add(1)
go func(pi pstore.PeerInfo) {
go func(pi peer.AddrInfo) {
defer wg.Done()
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
defer cancel()
@ -117,7 +118,7 @@ func connectToPubSubPeers(ctx context.Context, r routing.IpfsRouting, ph p2phost
wg.Wait()
}
func (api *PubSubAPI) checkNode() (routing.IpfsRouting, error) {
func (api *PubSubAPI) checkNode() (routing.Routing, error) {
if api.pubSub == nil {
return nil, errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
}

View File

@ -5,13 +5,11 @@ import (
"sort"
"time"
iaddr "github.com/ipfs/go-ipfs-addr"
coreiface "github.com/ipfs/interface-go-ipfs-core"
inet "github.com/libp2p/go-libp2p-net"
net "github.com/libp2p/go-libp2p-net"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
protocol "github.com/libp2p/go-libp2p-protocol"
inet "github.com/libp2p/go-libp2p-core/network"
peer "github.com/libp2p/go-libp2p-core/peer"
pstore "github.com/libp2p/go-libp2p-core/peerstore"
protocol "github.com/libp2p/go-libp2p-core/protocol"
swarm "github.com/libp2p/go-libp2p-swarm"
ma "github.com/multiformats/go-multiaddr"
)
@ -20,8 +18,8 @@ type SwarmAPI CoreAPI
type connInfo struct {
peerstore pstore.Peerstore
conn net.Conn
dir net.Direction
conn inet.Conn
dir inet.Direction
addr ma.Multiaddr
peer peer.ID
@ -31,7 +29,7 @@ type connInfo struct {
const connectionManagerTag = "user-connect"
const connectionManagerWeight = 100
func (api *SwarmAPI) Connect(ctx context.Context, pi pstore.PeerInfo) error {
func (api *SwarmAPI) Connect(ctx context.Context, pi peer.AddrInfo) error {
if api.peerHost == nil {
return coreiface.ErrOffline
}
@ -53,34 +51,29 @@ func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
return coreiface.ErrOffline
}
ia, err := iaddr.ParseMultiaddr(ma.Multiaddr(addr))
if err != nil {
return err
taddr, id := peer.SplitAddr(addr)
if id == "" {
return peer.ErrInvalidAddr
}
taddr := ia.Transport()
id := ia.ID()
net := api.peerHost.Network()
if taddr == nil {
if net.Connectedness(id) != inet.Connected {
return coreiface.ErrNotConnected
} else if err := net.ClosePeer(id); err != nil {
}
if err := net.ClosePeer(id); err != nil {
return err
}
} else {
for _, conn := range net.ConnsToPeer(id) {
if !conn.RemoteMultiaddr().Equal(taddr) {
continue
}
return conn.Close()
return nil
}
for _, conn := range net.ConnsToPeer(id) {
if !conn.RemoteMultiaddr().Equal(taddr) {
continue
}
return coreiface.ErrConnNotFound
return conn.Close()
}
return nil
return coreiface.ErrConnNotFound
}
func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, error) {
@ -159,7 +152,7 @@ func (ci *connInfo) Address() ma.Multiaddr {
return ci.addr
}
func (ci *connInfo) Direction() net.Direction {
func (ci *connInfo) Direction() inet.Direction {
return ci.dir
}

View File

@ -8,12 +8,12 @@ import (
"path/filepath"
"testing"
"github.com/ipfs/go-ipfs/core/bootstrap"
"github.com/ipfs/go-ipfs/filestore"
"github.com/ipfs/go-filestore"
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/core/bootstrap"
"github.com/ipfs/go-ipfs/core/coreapi"
mock "github.com/ipfs/go-ipfs/core/mock"
"github.com/ipfs/go-ipfs/core/node/libp2p"
"github.com/ipfs/go-ipfs/keystore"
"github.com/ipfs/go-ipfs/repo"
@ -22,9 +22,8 @@ import (
"github.com/ipfs/go-ipfs-config"
coreiface "github.com/ipfs/interface-go-ipfs-core"
"github.com/ipfs/interface-go-ipfs-core/tests"
ci "github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
ci "github.com/libp2p/go-libp2p-core/crypto"
peer "github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p/p2p/net/mock"
)
@ -41,7 +40,7 @@ func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
for i := 0; i < n; i++ {
var ident config.Identity
if fullIdentity {
sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
sk, pk, err := ci.GenerateKeyPair(ci.RSA, 2048)
if err != nil {
return nil, err
}
@ -67,7 +66,7 @@ func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
}
c := config.Config{}
c.Addresses.Swarm = []string{fmt.Sprintf("/ip4/127.0.%d.1/tcp/4001", i)}
c.Addresses.Swarm = []string{fmt.Sprintf("/ip4/18.0.%d.1/tcp/4001", i)}
c.Identity = ident
c.Experimental.FilestoreEnabled = true
@ -80,9 +79,10 @@ func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
}
node, err := core.NewNode(ctx, &core.BuildCfg{
Repo: r,
Host: mock.MockHostOption(mn),
Online: fullIdentity,
Routing: libp2p.DHTServerOption,
Repo: r,
Host: mock.MockHostOption(mn),
Online: fullIdentity,
ExtraOpts: map[string]bool{
"pubsub": true,
},
@ -103,7 +103,7 @@ func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
}
bsinf := bootstrap.BootstrapConfigWithPeers(
[]pstore.PeerInfo{
[]peer.AddrInfo{
nodes[0].Peerstore.PeerInfo(nodes[0].Identity),
},
)

Some files were not shown because too many files have changed in this diff Show More