OSDN Git Service

add ipfs package
authormars <mars@bytom.io>
Fri, 22 Feb 2019 07:21:31 +0000 (15:21 +0800)
committermars <mars@bytom.io>
Fri, 22 Feb 2019 07:21:31 +0000 (15:21 +0800)
27 files changed:
vendor/github.com/ipfs/go-ipfs-api/.gx/lastpubver [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/.travis.yml [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/LICENSE [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/Makefile [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/README.md [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/add.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/bootstrap.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/dag.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/ipns.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/ipns_test.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/options/dag.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/package.json [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/pubsub.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/request.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/requestbuilder.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/requestbuilder_test.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/shell.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/shell_test.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/about [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/contact [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/help [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/ping [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/quick-start [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/readme [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/testdata/security-notes [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/tests/main.go [new file with mode: 0644]
vendor/github.com/ipfs/go-ipfs-api/unixfs.go [new file with mode: 0644]

diff --git a/vendor/github.com/ipfs/go-ipfs-api/.gx/lastpubver b/vendor/github.com/ipfs/go-ipfs-api/.gx/lastpubver
new file mode 100644 (file)
index 0000000..198a9b7
--- /dev/null
@@ -0,0 +1 @@
+1.4.7: QmZs5KbsFE53hpGKhKdrYb9j5iRgMhLSsYBF7w8d6wuJHW
diff --git a/vendor/github.com/ipfs/go-ipfs-api/.travis.yml b/vendor/github.com/ipfs/go-ipfs-api/.travis.yml
new file mode 100644 (file)
index 0000000..0499f01
--- /dev/null
@@ -0,0 +1,35 @@
+sudo: required
+
+language: go
+
+go:
+  - 1.11.x
+
+env:
+  - IPFS_PATH=/tmp/ipfs
+
+matrix:
+  allow_failures:
+    - go: tip
+
+services:
+  - docker
+
+before_install:
+- docker pull ipfs/go-ipfs:master
+- mkdir /tmp/ipfs && chmod 0777 /tmp/ipfs
+- docker run -d -v /tmp/ipfs:/data/ipfs -p 8080:8080 -p 4001:4001 -p 5001:5001 ipfs/go-ipfs:master --enable-pubsub-experiment
+
+install:
+  - make deps
+  - go get -t -v ./...
+
+script:
+  - bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
+
+notifications:
+  email: false
+
+cache:
+  directories:
+    - $GOPATH/src/gx
\ No newline at end of file
diff --git a/vendor/github.com/ipfs/go-ipfs-api/LICENSE b/vendor/github.com/ipfs/go-ipfs-api/LICENSE
new file mode 100644 (file)
index 0000000..2610033
--- /dev/null
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Jeromy Johnson
+
+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.
diff --git a/vendor/github.com/ipfs/go-ipfs-api/Makefile b/vendor/github.com/ipfs/go-ipfs-api/Makefile
new file mode 100644 (file)
index 0000000..be18a03
--- /dev/null
@@ -0,0 +1,8 @@
+all: deps
+gx:
+       go get github.com/whyrusleeping/gx
+       go get github.com/whyrusleeping/gx-go
+deps: gx
+       gx --verbose install --global
+       gx-go rewrite
+.PHONY: all gx deps
diff --git a/vendor/github.com/ipfs/go-ipfs-api/README.md b/vendor/github.com/ipfs/go-ipfs-api/README.md
new file mode 100644 (file)
index 0000000..89dbb4b
--- /dev/null
@@ -0,0 +1,65 @@
+# go-ipfs-api
+
+[![](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)
+[![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-api?status.svg)](https://godoc.org/github.com/ipfs/go-ipfs-api)
+[![Build Status](https://travis-ci.org/ipfs/go-ipfs-api.svg)](https://travis-ci.org/ipfs/go-ipfs-api) 
+
+![](https://camo.githubusercontent.com/651f7045071c78042fec7f5b9f015e12589af6d5/68747470733a2f2f697066732e696f2f697066732f516d514a363850464d4464417367435a76413155567a7a6e3138617356636637485676434467706a695343417365)
+
+> An unofficial go interface to ipfs's HTTP API
+
+## Install
+
+```sh
+go get -u github.com/ipfs/go-ipfs-api
+```
+
+This will download the source into `$GOPATH/src/github.com/ipfs/go-ipfs-api`.
+
+## Usage
+
+See [the godocs](https://godoc.org/github.com/ipfs/go-ipfs-api) for details on available methods. This should match the specs at [ipfs/specs](https://github.com/ipfs/specs/tree/master/public-api); however, there are still some methods which are not accounted for. If you would like to add any of them, see the contribute section below.
+
+### Example
+
+Add a file with the contents "hello world!":
+
+```go
+package main
+
+import (
+       "fmt"
+       "strings"
+       "os"
+
+       shell "github.com/ipfs/go-ipfs-api"
+)
+
+func main() {
+       // Where your local node is running on localhost:5001
+       sh := shell.NewShell("localhost:5001")
+       cid, err := sh.Add(strings.NewReader("hello world!"))
+       if err != nil {
+        fmt.Fprintf(os.Stderr, "error: %s", err)
+        os.Exit(1)
+       }
+    fmt.Printf("added %s", cid)
+}
+```
+
+For a more complete example, please see: https://github.com/ipfs/go-ipfs-api/blob/master/tests/main.go
+
+## Contribute
+
+Contributions are welcome! Please check out the [issues](https://github.com/ipfs/go-ipfs-api/issues).
+
+### Want to hack on IPFS?
+
+[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md)
+
+## License
+
+MIT
diff --git a/vendor/github.com/ipfs/go-ipfs-api/add.go b/vendor/github.com/ipfs/go-ipfs-api/add.go
new file mode 100644 (file)
index 0000000..b441629
--- /dev/null
@@ -0,0 +1,129 @@
+package shell
+
+import (
+       "context"
+       "encoding/json"
+       "errors"
+       "io"
+       "os"
+       "path"
+
+       "github.com/ipfs/go-ipfs-files"
+)
+
+type object struct {
+       Hash string
+}
+
+type AddOpts = func(*RequestBuilder) error
+
+func OnlyHash(enabled bool) AddOpts {
+       return func(rb *RequestBuilder) error {
+               rb.Option("only-hash", enabled)
+               return nil
+       }
+}
+
+func Pin(enabled bool) AddOpts {
+       return func(rb *RequestBuilder) error {
+               rb.Option("pin", enabled)
+               return nil
+       }
+}
+
+func Progress(enabled bool) AddOpts {
+       return func(rb *RequestBuilder) error {
+               rb.Option("progress", enabled)
+               return nil
+       }
+}
+
+func RawLeaves(enabled bool) AddOpts {
+       return func(rb *RequestBuilder) error {
+               rb.Option("raw-leaves", enabled)
+               return nil
+       }
+}
+
+func (s *Shell) Add(r io.Reader, options ...AddOpts) (string, error) {
+       fr := files.NewReaderFile(r)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
+       fileReader := files.NewMultiFileReader(slf, true)
+
+       var out object
+       rb := s.Request("add")
+       for _, option := range options {
+               option(rb)
+       }
+       return out.Hash, rb.Body(fileReader).Exec(context.Background(), &out)
+}
+
+// AddNoPin adds a file to ipfs without pinning it
+// Deprecated: Use Add() with option functions instead
+func (s *Shell) AddNoPin(r io.Reader) (string, error) {
+       return s.Add(r, Pin(false))
+}
+
+// AddWithOpts adds a file to ipfs with some additional options
+// Deprecated: Use Add() with option functions instead
+func (s *Shell) AddWithOpts(r io.Reader, pin bool, rawLeaves bool) (string, error) {
+       return s.Add(r, Pin(pin), RawLeaves(rawLeaves))
+}
+
+func (s *Shell) AddLink(target string) (string, error) {
+       link := files.NewLinkFile(target, nil)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", link)})
+       reader := files.NewMultiFileReader(slf, true)
+
+       var out object
+       return out.Hash, s.Request("add").Body(reader).Exec(context.Background(), &out)
+}
+
+// AddDir adds a directory recursively with all of the files under it
+func (s *Shell) AddDir(dir string) (string, error) {
+       stat, err := os.Lstat(dir)
+       if err != nil {
+               return "", err
+       }
+
+       sf, err := files.NewSerialFile(dir, false, stat)
+       if err != nil {
+               return "", err
+       }
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry(path.Base(dir), sf)})
+       reader := files.NewMultiFileReader(slf, true)
+
+       resp, err := s.Request("add").
+               Option("recursive", true).
+               Body(reader).
+               Send(context.Background())
+       if err != nil {
+               return "", nil
+       }
+
+       defer resp.Close()
+
+       if resp.Error != nil {
+               return "", resp.Error
+       }
+
+       dec := json.NewDecoder(resp.Output)
+       var final string
+       for {
+               var out object
+               err = dec.Decode(&out)
+               if err != nil {
+                       if err == io.EOF {
+                               break
+                       }
+                       return "", err
+               }
+               final = out.Hash
+       }
+
+       if final == "" {
+               return "", errors.New("no results received")
+       }
+
+       return final, nil
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/bootstrap.go b/vendor/github.com/ipfs/go-ipfs-api/bootstrap.go
new file mode 100644 (file)
index 0000000..e28eef0
--- /dev/null
@@ -0,0 +1,27 @@
+package shell
+
+import (
+       "context"
+)
+
+type PeersList struct {
+       Peers []string
+}
+
+func (s *Shell) BootstrapAdd(peers []string) ([]string, error) {
+       var addOutput PeersList
+       err := s.Request("bootstrap/add", peers...).Exec(context.Background(), &addOutput)
+       return addOutput.Peers, err
+}
+
+func (s *Shell) BootstrapAddDefault() ([]string, error) {
+       var addOutput PeersList
+       err := s.Request("bootstrap/add/default").Exec(context.Background(), &addOutput)
+       return addOutput.Peers, err
+}
+
+func (s *Shell) BootstrapRmAll() ([]string, error) {
+       var rmAllOutput PeersList
+       err := s.Request("bootstrap/rm/all").Exec(context.Background(), &rmAllOutput)
+       return rmAllOutput.Peers, err
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/dag.go b/vendor/github.com/ipfs/go-ipfs-api/dag.go
new file mode 100644 (file)
index 0000000..edfcbac
--- /dev/null
@@ -0,0 +1,57 @@
+package shell
+
+import (
+       "bytes"
+       "context"
+       "fmt"
+       "io"
+       "strings"
+
+       "github.com/ipfs/go-ipfs-api/options"
+       "github.com/ipfs/go-ipfs-files"
+)
+
+func (s *Shell) DagGet(ref string, out interface{}) error {
+       return s.Request("dag/get", ref).Exec(context.Background(), out)
+}
+
+func (s *Shell) DagPut(data interface{}, ienc, kind string) (string, error) {
+       return s.DagPutWithOpts(data, options.Dag.InputEnc(ienc), options.Dag.Kind(kind))
+}
+
+func (s *Shell) DagPutWithOpts(data interface{}, opts ...options.DagPutOption) (string, error) {
+       cfg, err := options.DagPutOptions(opts...)
+       if err != nil {
+               return "", err
+       }
+
+       var r io.Reader
+       switch data := data.(type) {
+       case string:
+               r = strings.NewReader(data)
+       case []byte:
+               r = bytes.NewReader(data)
+       case io.Reader:
+               r = data
+       default:
+               return "", fmt.Errorf("cannot current handle putting values of type %T", data)
+       }
+
+       fr := files.NewReaderFile(r)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
+       fileReader := files.NewMultiFileReader(slf, true)
+
+       var out struct {
+               Cid struct {
+                       Target string `json:"/"`
+               }
+       }
+
+       return out.Cid.Target, s.
+               Request("dag/put").
+               Option("input-enc", cfg.InputEnc).
+               Option("format", cfg.Kind).
+               Option("pin", cfg.Pin).
+               Body(fileReader).
+               Exec(context.Background(), &out)
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/ipns.go b/vendor/github.com/ipfs/go-ipfs-api/ipns.go
new file mode 100644 (file)
index 0000000..7903096
--- /dev/null
@@ -0,0 +1,55 @@
+package shell
+
+import (
+       "context"
+       "time"
+)
+
+type PublishResponse struct {
+       Name  string `json:"name"`
+       Value string `json:"value"`
+}
+
+// Publish updates a mutable name to point to a given value
+func (s *Shell) Publish(node string, value string) error {
+       var pubResp PublishResponse
+       req := s.Request("name/publish")
+       if node != "" {
+               req.Arguments(node)
+       }
+       req.Arguments(value)
+
+       return req.Exec(context.Background(), &pubResp)
+}
+
+// PublishWithDetails is used for fine grained control over record publishing
+func (s *Shell) PublishWithDetails(contentHash, key string, lifetime, ttl time.Duration, resolve bool) (*PublishResponse, error) {
+       var pubResp PublishResponse
+       req := s.Request("name/publish", contentHash).Option("resolve", resolve)
+       if key != "" {
+               req.Option("key", key)
+       }
+       if lifetime != 0 {
+               req.Option("lifetime", lifetime)
+       }
+       if ttl.Seconds() > 0 {
+               req.Option("ttl", ttl)
+       }
+       err := req.Exec(context.Background(), &pubResp)
+       if err != nil {
+               return nil, err
+       }
+       return &pubResp, nil
+}
+
+// Resolve gets resolves the string provided to an /ipns/[name]. If asked to
+// resolve an empty string, resolve instead resolves the node's own /ipns value.
+func (s *Shell) Resolve(id string) (string, error) {
+       req := s.Request("name/resolve")
+       if id != "" {
+               req.Arguments(id)
+       }
+       var out struct{ Path string }
+       err := req.Exec(context.Background(), &out)
+       return out.Path, err
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/ipns_test.go b/vendor/github.com/ipfs/go-ipfs-api/ipns_test.go
new file mode 100644 (file)
index 0000000..7137f1d
--- /dev/null
@@ -0,0 +1,38 @@
+package shell
+
+import (
+       "fmt"
+       "testing"
+       "time"
+)
+
+var examplesHashForIPNS = "/ipfs/Qmbu7x6gJbsKDcseQv66pSbUcAA3Au6f7MfTYVXwvBxN2K"
+var testKey = "self" // feel free to change to whatever key you have locally
+
+func TestPublishDetailsWithKey(t *testing.T) {
+       t.Skip()
+       shell := NewShell("localhost:5001")
+
+       resp, err := shell.PublishWithDetails(examplesHashForIPNS, testKey, time.Second, time.Second, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if resp.Value != examplesHashForIPNS {
+               t.Fatalf(fmt.Sprintf("Expected to receive %s but got %s", examplesHash, resp.Value))
+       }
+}
+
+func TestPublishDetailsWithoutKey(t *testing.T) {
+       t.Skip()
+       shell := NewShell("localhost:5001")
+
+       resp, err := shell.PublishWithDetails(examplesHashForIPNS, "", time.Second, time.Second, false)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       if resp.Value != examplesHashForIPNS {
+               t.Fatalf(fmt.Sprintf("Expected to receive %s but got %s", examplesHash, resp.Value))
+       }
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/options/dag.go b/vendor/github.com/ipfs/go-ipfs-api/options/dag.go
new file mode 100644 (file)
index 0000000..a7ecfce
--- /dev/null
@@ -0,0 +1,59 @@
+package options
+
+// DagPutSettings is a set of DagPut options.
+type DagPutSettings struct {
+       InputEnc string
+       Kind     string
+       Pin      string
+}
+
+// DagPutOption is a single DagPut option.
+type DagPutOption func(opts *DagPutSettings) error
+
+// DagPutOptions applies the given options to a DagPutSettings instance.
+func DagPutOptions(opts ...DagPutOption) (*DagPutSettings, error) {
+       options := &DagPutSettings{
+               InputEnc: "json",
+               Kind:     "cbor",
+               Pin:      "false",
+       }
+
+       for _, opt := range opts {
+               err := opt(options)
+               if err != nil {
+                       return nil, err
+               }
+       }
+       return options, nil
+}
+
+type dagOpts struct{}
+
+var Dag dagOpts
+
+// Pin is an option for Dag.Put which specifies whether to pin the added
+// dags. Default is "false".
+func (dagOpts) Pin(pin string) DagPutOption {
+       return func(opts *DagPutSettings) error {
+               opts.Pin = pin
+               return nil
+       }
+}
+
+// InputEnc is an option for Dag.Put which specifies the input encoding of the
+// data. Default is "json", most formats/codecs support "raw".
+func (dagOpts) InputEnc(enc string) DagPutOption {
+       return func(opts *DagPutSettings) error {
+               opts.InputEnc = enc
+               return nil
+       }
+}
+
+// Kind is an option for Dag.Put which specifies the format that the dag
+// will be added as. Default is "cbor".
+func (dagOpts) Kind(kind string) DagPutOption {
+       return func(opts *DagPutSettings) error {
+               opts.Kind = kind
+               return nil
+       }
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/package.json b/vendor/github.com/ipfs/go-ipfs-api/package.json
new file mode 100644 (file)
index 0000000..3d42025
--- /dev/null
@@ -0,0 +1,66 @@
+{
+  "author": "ipfs",
+  "bugs": {
+    "url": "https://github.com/ipfs/go-ipfs-api/issues"
+  },
+  "gx": {
+    "dvcsimport": "github.com/ipfs/go-ipfs-api"
+  },
+  "gxDependencies": [
+    {
+      "author": "whyrusleeping",
+      "hash": "QmTu65MVbemtUxJEWgsTtzv9Zv9P8rvmqNA4eG9TrTRGYc",
+      "name": "go-libp2p-peer",
+      "version": "3.1.1"
+    },
+    {
+      "author": "multiformats",
+      "hash": "QmNTCey11oxhb1AxDnQBRHtdhap6Ctud872NjAYPYYXPuc",
+      "name": "go-multiaddr",
+      "version": "1.4.0"
+    },
+    {
+      "author": "multiformats",
+      "hash": "QmZcLBXKaFe8ND5YHPkJRAwmhJGrVsi1JqDZNyJ4nRK5Mj",
+      "name": "go-multiaddr-net",
+      "version": "1.7.1"
+    },
+    {
+      "author": "mitchellh",
+      "hash": "QmdcULN1WCzgoQmcCaUAmEhwcxHYsDrbZ2LvRJKCL8dMrK",
+      "name": "go-homedir",
+      "version": "1.0.0"
+    },
+    {
+      "author": "whyrusleeping",
+      "hash": "QmNohiVssaPw3KVLZik59DBVGTSm2dGvYT9eoXt5DQ36Yz",
+      "name": "go-ipfs-util",
+      "version": "1.2.9"
+    },
+    {
+      "author": "whyrusleeping",
+      "hash": "QmQine7gvHncNevKtG9QXxf3nXcwSj6aDDmMm52mHofEEp",
+      "name": "tar-utils",
+      "version": "0.0.3"
+    },
+    {
+      "author": "whyrusleeping",
+      "hash": "QmZZseAa9xcK6tT3YpaShNUAEpyRAoWmUL5ojH3uGNepAc",
+      "name": "go-libp2p-metrics",
+      "version": "2.1.13"
+    },
+    {
+      "author": "magik6k",
+      "hash": "QmQmhotPUzVrMEWNK3x1R5jQ5ZHWyL7tVUrmRPjrBrvyCb",
+      "name": "go-ipfs-files",
+      "version": "2.0.6"
+    }
+  ],
+  "gxVersion": "0.7.0",
+  "language": "go",
+  "license": "MIT",
+  "name": "go-ipfs-api",
+  "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
+  "version": "1.4.7"
+}
+
diff --git a/vendor/github.com/ipfs/go-ipfs-api/pubsub.go b/vendor/github.com/ipfs/go-ipfs-api/pubsub.go
new file mode 100644 (file)
index 0000000..be6f4a0
--- /dev/null
@@ -0,0 +1,69 @@
+package shell
+
+import (
+       "encoding/json"
+
+       "github.com/libp2p/go-libp2p-peer"
+)
+
+// Message is a pubsub message.
+type Message struct {
+       From     peer.ID
+       Data     []byte
+       Seqno    []byte
+       TopicIDs []string
+}
+
+// PubSubSubscription allow you to receive pubsub records that where published on the network.
+type PubSubSubscription struct {
+       resp *Response
+}
+
+func newPubSubSubscription(resp *Response) *PubSubSubscription {
+       sub := &PubSubSubscription{
+               resp: resp,
+       }
+
+       return sub
+}
+
+// Next waits for the next record and returns that.
+func (s *PubSubSubscription) Next() (*Message, error) {
+       if s.resp.Error != nil {
+               return nil, s.resp.Error
+       }
+
+       d := json.NewDecoder(s.resp.Output)
+
+       var r struct {
+               From     []byte   `json:"from,omitempty"`
+               Data     []byte   `json:"data,omitempty"`
+               Seqno    []byte   `json:"seqno,omitempty"`
+               TopicIDs []string `json:"topicIDs,omitempty"`
+       }
+
+       err := d.Decode(&r)
+       if err != nil {
+               return nil, err
+       }
+
+       from, err := peer.IDFromBytes(r.From)
+       if err != nil {
+               return nil, err
+       }
+       return &Message{
+               From:     from,
+               Data:     r.Data,
+               Seqno:    r.Seqno,
+               TopicIDs: r.TopicIDs,
+       }, nil
+}
+
+// Cancel cancels the given subscription.
+func (s *PubSubSubscription) Cancel() error {
+       if s.resp.Output == nil {
+               return nil
+       }
+
+       return s.resp.Output.Close()
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/request.go b/vendor/github.com/ipfs/go-ipfs-api/request.go
new file mode 100644 (file)
index 0000000..a87d8a3
--- /dev/null
@@ -0,0 +1,185 @@
+package shell
+
+import (
+       "context"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "net/http"
+       "net/url"
+       "os"
+       "strings"
+
+       files "github.com/ipfs/go-ipfs-files"
+)
+
+type Request struct {
+       ApiBase string
+       Command string
+       Args    []string
+       Opts    map[string]string
+       Body    io.Reader
+       Headers map[string]string
+}
+
+func NewRequest(ctx context.Context, url, command string, args ...string) *Request {
+       if !strings.HasPrefix(url, "http") {
+               url = "http://" + url
+       }
+
+       opts := map[string]string{
+               "encoding":        "json",
+               "stream-channels": "true",
+       }
+       return &Request{
+               ApiBase: url + "/api/v0",
+               Command: command,
+               Args:    args,
+               Opts:    opts,
+               Headers: make(map[string]string),
+       }
+}
+
+type trailerReader struct {
+       resp *http.Response
+}
+
+func (r *trailerReader) Read(b []byte) (int, error) {
+       n, err := r.resp.Body.Read(b)
+       if err != nil {
+               if e := r.resp.Trailer.Get("X-Stream-Error"); e != "" {
+                       err = errors.New(e)
+               }
+       }
+       return n, err
+}
+
+func (r *trailerReader) Close() error {
+       return r.resp.Body.Close()
+}
+
+type Response struct {
+       Output io.ReadCloser
+       Error  *Error
+}
+
+func (r *Response) Close() error {
+       if r.Output != nil {
+               // always drain output (response body)
+               _, err1 := io.Copy(ioutil.Discard, r.Output)
+               err2 := r.Output.Close()
+               if err1 != nil {
+                       return err1
+               }
+               if err2 != nil {
+                       return err2
+               }
+       }
+       return nil
+}
+
+func (r *Response) Decode(dec interface{}) error {
+       defer r.Close()
+       if r.Error != nil {
+               return r.Error
+       }
+
+       return json.NewDecoder(r.Output).Decode(dec)
+}
+
+type Error struct {
+       Command string
+       Message string
+       Code    int
+}
+
+func (e *Error) Error() string {
+       var out string
+       if e.Command != "" {
+               out = e.Command + ": "
+       }
+       if e.Code != 0 {
+               out = fmt.Sprintf("%s%d: ", out, e.Code)
+       }
+       return out + e.Message
+}
+
+func (r *Request) Send(c *http.Client) (*Response, error) {
+       url := r.getURL()
+       req, err := http.NewRequest("POST", url, r.Body)
+       if err != nil {
+               return nil, err
+       }
+
+       // Add any headers that were supplied via the RequestBuilder.
+       for k, v := range r.Headers {
+               req.Header.Add(k, v)
+       }
+
+       if fr, ok := r.Body.(*files.MultiFileReader); ok {
+               req.Header.Set("Content-Type", "multipart/form-data; boundary="+fr.Boundary())
+               req.Header.Set("Content-Disposition", "form-data; name=\"files\"")
+       }
+
+       resp, err := c.Do(req)
+       if err != nil {
+               return nil, err
+       }
+
+       contentType := resp.Header.Get("Content-Type")
+       parts := strings.Split(contentType, ";")
+       contentType = parts[0]
+
+       nresp := new(Response)
+
+       nresp.Output = &trailerReader{resp}
+       if resp.StatusCode >= http.StatusBadRequest {
+               e := &Error{
+                       Command: r.Command,
+               }
+               switch {
+               case resp.StatusCode == http.StatusNotFound:
+                       e.Message = "command not found"
+               case contentType == "text/plain":
+                       out, err := ioutil.ReadAll(resp.Body)
+                       if err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) read error: %s\n", resp.StatusCode, err)
+                       }
+                       e.Message = string(out)
+               case contentType == "application/json":
+                       if err = json.NewDecoder(resp.Body).Decode(e); err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) unmarshall error: %s\n", resp.StatusCode, err)
+                       }
+               default:
+                       fmt.Fprintf(os.Stderr, "ipfs-shell: warning! unhandled response (%d) encoding: %s", resp.StatusCode, contentType)
+                       out, err := ioutil.ReadAll(resp.Body)
+                       if err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: response (%d) read error: %s\n", resp.StatusCode, err)
+                       }
+                       e.Message = fmt.Sprintf("unknown ipfs-shell error encoding: %q - %q", contentType, out)
+               }
+               nresp.Error = e
+               nresp.Output = nil
+
+               // drain body and close
+               io.Copy(ioutil.Discard, resp.Body)
+               resp.Body.Close()
+       }
+
+       return nresp, nil
+}
+
+func (r *Request) getURL() string {
+
+       values := make(url.Values)
+       for _, arg := range r.Args {
+               values.Add("arg", arg)
+       }
+       for k, v := range r.Opts {
+               values.Add(k, v)
+       }
+
+       return fmt.Sprintf("%s/%s?%s", r.ApiBase, r.Command, values.Encode())
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/requestbuilder.go b/vendor/github.com/ipfs/go-ipfs-api/requestbuilder.go
new file mode 100644 (file)
index 0000000..5bef855
--- /dev/null
@@ -0,0 +1,100 @@
+package shell
+
+import (
+       "bytes"
+       "context"
+       "fmt"
+       "io"
+       "strconv"
+       "strings"
+)
+
+// RequestBuilder is an IPFS commands request builder.
+type RequestBuilder struct {
+       command string
+       args    []string
+       opts    map[string]string
+       headers map[string]string
+       body    io.Reader
+
+       shell *Shell
+}
+
+// Arguments adds the arguments to the args.
+func (r *RequestBuilder) Arguments(args ...string) *RequestBuilder {
+       r.args = append(r.args, args...)
+       return r
+}
+
+// BodyString sets the request body to the given string.
+func (r *RequestBuilder) BodyString(body string) *RequestBuilder {
+       return r.Body(strings.NewReader(body))
+}
+
+// BodyBytes sets the request body to the given buffer.
+func (r *RequestBuilder) BodyBytes(body []byte) *RequestBuilder {
+       return r.Body(bytes.NewReader(body))
+}
+
+// Body sets the request body to the given reader.
+func (r *RequestBuilder) Body(body io.Reader) *RequestBuilder {
+       r.body = body
+       return r
+}
+
+// Option sets the given option.
+func (r *RequestBuilder) Option(key string, value interface{}) *RequestBuilder {
+       var s string
+       switch v := value.(type) {
+       case bool:
+               s = strconv.FormatBool(v)
+       case string:
+               s = v
+       case []byte:
+               s = string(v)
+       default:
+               // slow case.
+               s = fmt.Sprint(value)
+       }
+       if r.opts == nil {
+               r.opts = make(map[string]string, 1)
+       }
+       r.opts[key] = s
+       return r
+}
+
+// Header sets the given header.
+func (r *RequestBuilder) Header(name, value string) *RequestBuilder {
+       if r.headers == nil {
+               r.headers = make(map[string]string, 1)
+       }
+       r.headers[name] = value
+       return r
+}
+
+// Send sends the request and return the response.
+func (r *RequestBuilder) Send(ctx context.Context) (*Response, error) {
+       req := NewRequest(ctx, r.shell.url, r.command, r.args...)
+       req.Opts = r.opts
+       req.Headers = r.headers
+       req.Body = r.body
+       return req.Send(&r.shell.httpcli)
+}
+
+// Exec sends the request a request and decodes the response.
+func (r *RequestBuilder) Exec(ctx context.Context, res interface{}) error {
+       httpRes, err := r.Send(ctx)
+       if err != nil {
+               return err
+       }
+
+       if res == nil {
+               lateErr := httpRes.Close()
+               if httpRes.Error != nil {
+                       return httpRes.Error
+               }
+               return lateErr
+       }
+
+       return httpRes.Decode(res)
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/requestbuilder_test.go b/vendor/github.com/ipfs/go-ipfs-api/requestbuilder_test.go
new file mode 100644 (file)
index 0000000..7950d46
--- /dev/null
@@ -0,0 +1,35 @@
+package shell
+
+import (
+       "testing"
+       "time"
+
+       "github.com/cheekybits/is"
+)
+
+func TestRequestBuilder(t *testing.T) {
+       is := is.New(t)
+
+       now := time.Now()
+       r := RequestBuilder{}
+       r.Arguments("1", "2", "3")
+       r.Arguments("4")
+       r.Option("stringkey", "stringvalue")
+       r.Option("bytekey", []byte("bytevalue"))
+       r.Option("boolkey", true)
+       r.Option("otherkey", now)
+       r.Header("some-header", "header-value")
+       r.Header("some-header-2", "header-value-2")
+
+       is.Equal(r.args, []string{"1", "2", "3", "4"})
+       is.Equal(r.opts, map[string]string{
+               "stringkey": "stringvalue",
+               "bytekey":   "bytevalue",
+               "boolkey":   "true",
+               "otherkey":  now.String(),
+       })
+       is.Equal(r.headers, map[string]string{
+               "some-header":   "header-value",
+               "some-header-2": "header-value-2",
+       })
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/shell.go b/vendor/github.com/ipfs/go-ipfs-api/shell.go
new file mode 100644 (file)
index 0000000..f0b24f8
--- /dev/null
@@ -0,0 +1,517 @@
+// package shell implements a remote API interface for a running ipfs daemon
+package shell
+
+import (
+       "bytes"
+       "context"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io"
+       "io/ioutil"
+       gohttp "net/http"
+       "os"
+       "path"
+       "strings"
+       "time"
+
+       files "github.com/ipfs/go-ipfs-files"
+       homedir "github.com/mitchellh/go-homedir"
+       ma "github.com/multiformats/go-multiaddr"
+       manet "github.com/multiformats/go-multiaddr-net"
+       tar "github.com/whyrusleeping/tar-utils"
+
+       p2pmetrics "github.com/libp2p/go-libp2p-metrics"
+)
+
+const (
+       DefaultPathName = ".ipfs"
+       DefaultPathRoot = "~/" + DefaultPathName
+       DefaultApiFile  = "api"
+       EnvDir          = "IPFS_PATH"
+)
+
+type Shell struct {
+       url     string
+       httpcli gohttp.Client
+}
+
+func NewLocalShell() *Shell {
+       baseDir := os.Getenv(EnvDir)
+       if baseDir == "" {
+               baseDir = DefaultPathRoot
+       }
+
+       baseDir, err := homedir.Expand(baseDir)
+       if err != nil {
+               return nil
+       }
+
+       apiFile := path.Join(baseDir, DefaultApiFile)
+
+       if _, err := os.Stat(apiFile); err != nil {
+               return nil
+       }
+
+       api, err := ioutil.ReadFile(apiFile)
+       if err != nil {
+               return nil
+       }
+
+       return NewShell(strings.TrimSpace(string(api)))
+}
+
+func NewShell(url string) *Shell {
+       c := &gohttp.Client{
+               Transport: &gohttp.Transport{
+                       Proxy:             gohttp.ProxyFromEnvironment,
+                       DisableKeepAlives: true,
+               },
+       }
+
+       return NewShellWithClient(url, c)
+}
+
+func NewShellWithClient(url string, c *gohttp.Client) *Shell {
+       if a, err := ma.NewMultiaddr(url); err == nil {
+               _, host, err := manet.DialArgs(a)
+               if err == nil {
+                       url = host
+               }
+       }
+       var sh Shell
+       sh.url = url
+       sh.httpcli = *c
+       // We don't support redirects.
+       sh.httpcli.CheckRedirect = func(_ *gohttp.Request, _ []*gohttp.Request) error {
+               return fmt.Errorf("unexpected redirect")
+       }
+       return &sh
+}
+
+func (s *Shell) SetTimeout(d time.Duration) {
+       s.httpcli.Timeout = d
+}
+
+func (s *Shell) Request(command string, args ...string) *RequestBuilder {
+       return &RequestBuilder{
+               command: command,
+               args:    args,
+               shell:   s,
+       }
+}
+
+type IdOutput struct {
+       ID              string
+       PublicKey       string
+       Addresses       []string
+       AgentVersion    string
+       ProtocolVersion string
+}
+
+// ID gets information about a given peer.  Arguments:
+//
+// peer: peer.ID of the node to look up.  If no peer is specified,
+//   return information about the local peer.
+func (s *Shell) ID(peer ...string) (*IdOutput, error) {
+       if len(peer) > 1 {
+               return nil, fmt.Errorf("Too many peer arguments")
+       }
+
+       var out IdOutput
+       if err := s.Request("id", peer...).Exec(context.Background(), &out); err != nil {
+               return nil, err
+       }
+       return &out, nil
+}
+
+// Cat the content at the given path. Callers need to drain and close the returned reader after usage.
+func (s *Shell) Cat(path string) (io.ReadCloser, error) {
+       resp, err := s.Request("cat", path).Send(context.Background())
+       if err != nil {
+               return nil, err
+       }
+       if resp.Error != nil {
+               return nil, resp.Error
+       }
+
+       return resp.Output, nil
+}
+
+const (
+       TRaw = iota
+       TDirectory
+       TFile
+       TMetadata
+       TSymlink
+)
+
+// List entries at the given path
+func (s *Shell) List(path string) ([]*LsLink, error) {
+       var out struct{ Objects []LsObject }
+       err := s.Request("ls", path).Exec(context.Background(), &out)
+       if err != nil {
+               return nil, err
+       }
+       if len(out.Objects) != 1 {
+               return nil, errors.New("bad response from server")
+       }
+       return out.Objects[0].Links, nil
+}
+
+type LsLink struct {
+       Hash string
+       Name string
+       Size uint64
+       Type int
+}
+
+type LsObject struct {
+       Links []*LsLink
+       LsLink
+}
+
+// Pin the given path
+func (s *Shell) Pin(path string) error {
+       return s.Request("pin/add", path).
+               Option("recursive", true).
+               Exec(context.Background(), nil)
+}
+
+// Unpin the given path
+func (s *Shell) Unpin(path string) error {
+       return s.Request("pin/rm", path).
+               Option("recursive", true).
+               Exec(context.Background(), nil)
+}
+
+const (
+       DirectPin    = "direct"
+       RecursivePin = "recursive"
+       IndirectPin  = "indirect"
+)
+
+type PinInfo struct {
+       Type string
+}
+
+// Pins returns a map of the pin hashes to their info (currently just the
+// pin type, one of DirectPin, RecursivePin, or IndirectPin. A map is returned
+// instead of a slice because it is easier to do existence lookup by map key
+// than unordered array searching. The map is likely to be more useful to a
+// client than a flat list.
+func (s *Shell) Pins() (map[string]PinInfo, error) {
+       var raw struct{ Keys map[string]PinInfo }
+       return raw.Keys, s.Request("pin/ls").Exec(context.Background(), &raw)
+}
+
+type PeerInfo struct {
+       Addrs []string
+       ID    string
+}
+
+func (s *Shell) FindPeer(peer string) (*PeerInfo, error) {
+       var peers struct{ Responses []PeerInfo }
+       err := s.Request("dht/findpeer", peer).Exec(context.Background(), &peers)
+       if err != nil {
+               return nil, err
+       }
+       if len(peers.Responses) == 0 {
+               return nil, errors.New("peer not found")
+       }
+       return &peers.Responses[0], nil
+}
+
+func (s *Shell) Refs(hash string, recursive bool) (<-chan string, error) {
+       resp, err := s.Request("refs", hash).
+               Option("recursive", recursive).
+               Send(context.Background())
+       if err != nil {
+               return nil, err
+       }
+
+       if resp.Error != nil {
+               resp.Close()
+               return nil, resp.Error
+       }
+
+       out := make(chan string)
+       go func() {
+               defer resp.Close()
+               var ref struct {
+                       Ref string
+               }
+               defer close(out)
+               dec := json.NewDecoder(resp.Output)
+               for {
+                       err := dec.Decode(&ref)
+                       if err != nil {
+                               return
+                       }
+                       if len(ref.Ref) > 0 {
+                               out <- ref.Ref
+                       }
+               }
+       }()
+
+       return out, nil
+}
+
+func (s *Shell) Patch(root, action string, args ...string) (string, error) {
+       var out object
+       return out.Hash, s.Request("object/patch/"+action, root).
+               Arguments(args...).
+               Exec(context.Background(), &out)
+}
+
+func (s *Shell) PatchData(root string, set bool, data interface{}) (string, error) {
+       var read io.Reader
+       switch d := data.(type) {
+       case io.Reader:
+               read = d
+       case []byte:
+               read = bytes.NewReader(d)
+       case string:
+               read = strings.NewReader(d)
+       default:
+               return "", fmt.Errorf("unrecognized type: %#v", data)
+       }
+
+       cmd := "append-data"
+       if set {
+               cmd = "set-data"
+       }
+
+       fr := files.NewReaderFile(read)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
+       fileReader := files.NewMultiFileReader(slf, true)
+
+       var out object
+       return out.Hash, s.Request("object/patch/"+cmd, root).
+               Body(fileReader).
+               Exec(context.Background(), &out)
+}
+
+func (s *Shell) PatchLink(root, path, childhash string, create bool) (string, error) {
+       var out object
+       return out.Hash, s.Request("object/patch/add-link", root, path, childhash).
+               Option("create", create).
+               Exec(context.Background(), &out)
+}
+
+func (s *Shell) Get(hash, outdir string) error {
+       resp, err := s.Request("get", hash).Option("create", true).Send(context.Background())
+       if err != nil {
+               return err
+       }
+       defer resp.Close()
+
+       if resp.Error != nil {
+               return resp.Error
+       }
+
+       extractor := &tar.Extractor{Path: outdir}
+       return extractor.Extract(resp.Output)
+}
+
+func (s *Shell) NewObject(template string) (string, error) {
+       var out object
+       req := s.Request("object/new")
+       if template != "" {
+               req.Arguments(template)
+       }
+       return out.Hash, req.Exec(context.Background(), &out)
+}
+
+func (s *Shell) ResolvePath(path string) (string, error) {
+       var out struct {
+               Path string
+       }
+       err := s.Request("resolve", path).Exec(context.Background(), &out)
+       if err != nil {
+               return "", err
+       }
+
+       return strings.TrimPrefix(out.Path, "/ipfs/"), nil
+}
+
+// returns ipfs version and commit sha
+func (s *Shell) Version() (string, string, error) {
+       ver := struct {
+               Version string
+               Commit  string
+       }{}
+
+       if err := s.Request("version").Exec(context.Background(), &ver); err != nil {
+               return "", "", err
+       }
+       return ver.Version, ver.Commit, nil
+}
+
+func (s *Shell) IsUp() bool {
+       _, _, err := s.Version()
+       return err == nil
+}
+
+func (s *Shell) BlockStat(path string) (string, int, error) {
+       var inf struct {
+               Key  string
+               Size int
+       }
+
+       if err := s.Request("block/stat", path).Exec(context.Background(), &inf); err != nil {
+               return "", 0, err
+       }
+       return inf.Key, inf.Size, nil
+}
+
+func (s *Shell) BlockGet(path string) ([]byte, error) {
+       resp, err := s.Request("block/get", path).Send(context.Background())
+       if err != nil {
+               return nil, err
+       }
+       defer resp.Close()
+
+       if resp.Error != nil {
+               return nil, resp.Error
+       }
+
+       return ioutil.ReadAll(resp.Output)
+}
+
+func (s *Shell) BlockPut(block []byte, format, mhtype string, mhlen int) (string, error) {
+       var out struct {
+               Key string
+       }
+
+       fr := files.NewBytesFile(block)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
+       fileReader := files.NewMultiFileReader(slf, true)
+
+       return out.Key, s.Request("block/put").
+               Option("mhtype", mhtype).
+               Option("format", format).
+               Option("mhlen", mhlen).
+               Body(fileReader).
+               Exec(context.Background(), &out)
+}
+
+type IpfsObject struct {
+       Links []ObjectLink
+       Data  string
+}
+
+type ObjectLink struct {
+       Name, Hash string
+       Size       uint64
+}
+
+func (s *Shell) ObjectGet(path string) (*IpfsObject, error) {
+       var obj IpfsObject
+       if err := s.Request("object/get", path).Exec(context.Background(), &obj); err != nil {
+               return nil, err
+       }
+       return &obj, nil
+}
+
+func (s *Shell) ObjectPut(obj *IpfsObject) (string, error) {
+       var data bytes.Buffer
+       err := json.NewEncoder(&data).Encode(obj)
+       if err != nil {
+               return "", err
+       }
+
+       fr := files.NewReaderFile(&data)
+       slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
+       fileReader := files.NewMultiFileReader(slf, true)
+
+       var out object
+       return out.Hash, s.Request("object/put").
+               Body(fileReader).
+               Exec(context.Background(), &out)
+}
+
+func (s *Shell) PubSubSubscribe(topic string) (*PubSubSubscription, error) {
+       // connect
+       resp, err := s.Request("pubsub/sub", topic).Send(context.Background())
+       if err != nil {
+               return nil, err
+       }
+       return newPubSubSubscription(resp), nil
+}
+
+func (s *Shell) PubSubPublish(topic, data string) (err error) {
+       resp, err := s.Request("pubsub/pub", topic, data).Send(context.Background())
+       if err != nil {
+               return err
+       }
+       defer resp.Close()
+       if resp.Error != nil {
+               return resp.Error
+       }
+       return nil
+}
+
+type ObjectStats struct {
+       Hash           string
+       BlockSize      int
+       CumulativeSize int
+       DataSize       int
+       LinksSize      int
+       NumLinks       int
+}
+
+// ObjectStat gets stats for the DAG object named by key. It returns
+// the stats of the requested Object or an error.
+func (s *Shell) ObjectStat(key string) (*ObjectStats, error) {
+       var stat ObjectStats
+       err := s.Request("object/stat", key).Exec(context.Background(), &stat)
+       if err != nil {
+               return nil, err
+       }
+       return &stat, nil
+}
+
+// ObjectStat gets stats for the DAG object named by key. It returns
+// the stats of the requested Object or an error.
+func (s *Shell) StatsBW(ctx context.Context) (*p2pmetrics.Stats, error) {
+       v := &p2pmetrics.Stats{}
+       err := s.Request("stats/bw").Exec(ctx, &v)
+       return v, err
+}
+
+type SwarmStreamInfo struct {
+       Protocol string
+}
+
+type SwarmConnInfo struct {
+       Addr    string
+       Peer    string
+       Latency string
+       Muxer   string
+       Streams []SwarmStreamInfo
+}
+
+type SwarmConnInfos struct {
+       Peers []SwarmConnInfo
+}
+
+// SwarmPeers gets all the swarm peers
+func (s *Shell) SwarmPeers(ctx context.Context) (*SwarmConnInfos, error) {
+       v := &SwarmConnInfos{}
+       err := s.Request("swarm/peers").Exec(ctx, &v)
+       return v, err
+}
+
+type swarmConnection struct {
+       Strings []string
+}
+
+// SwarmConnect opens a swarm connection to a specific address.
+func (s *Shell) SwarmConnect(ctx context.Context, addr ...string) error {
+       var conn *swarmConnection
+       err := s.Request("swarm/connect").
+               Arguments(addr...).
+               Exec(ctx, &conn)
+       return err
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/shell_test.go b/vendor/github.com/ipfs/go-ipfs-api/shell_test.go
new file mode 100644 (file)
index 0000000..18b2c3c
--- /dev/null
@@ -0,0 +1,409 @@
+package shell
+
+import (
+       "bytes"
+       "context"
+       "crypto/md5"
+       "fmt"
+       "io"
+       "math/rand"
+       "sort"
+       "strings"
+       "testing"
+       "time"
+
+       "github.com/cheekybits/is"
+       "github.com/ipfs/go-ipfs-api/options"
+)
+
+const (
+       examplesHash = "QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv"
+       shellUrl     = "localhost:5001"
+)
+
+func TestAdd(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       mhash, err := s.Add(bytes.NewBufferString("Hello IPFS Shell tests"))
+       is.Nil(err)
+       is.Equal(mhash, "QmUfZ9rAdhV5ioBzXKdUTh2ZNsz9bzbkaLVyQ8uc8pj21F")
+}
+
+func TestRedirect(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       err := s.
+               Request("/version").
+               Exec(context.Background(), nil)
+       is.NotNil(err)
+       is.True(strings.Contains(err.Error(), "unexpected redirect"))
+}
+
+func TestAddWithCat(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       s.SetTimeout(1 * time.Second)
+
+       rand := randString(32)
+
+       mhash, err := s.Add(bytes.NewBufferString(rand))
+       is.Nil(err)
+
+       reader, err := s.Cat(mhash)
+       is.Nil(err)
+
+       buf := new(bytes.Buffer)
+       buf.ReadFrom(reader)
+       catRand := buf.String()
+
+       is.Equal(rand, catRand)
+}
+
+func TestAddOnlyHash(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       s.SetTimeout(1 * time.Second)
+
+       rand := randString(32)
+
+       mhash, err := s.Add(bytes.NewBufferString(rand), OnlyHash(true))
+       is.Nil(err)
+
+       _, err = s.Cat(mhash)
+       is.Err(err) // we expect an http timeout error because `cat` won't find the `rand` string
+}
+
+func TestAddNoPin(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       h, err := s.Add(bytes.NewBufferString(randString(32)), Pin(false))
+       is.Nil(err)
+
+       pins, err := s.Pins()
+       is.Nil(err)
+
+       _, ok := pins[h]
+       is.False(ok)
+}
+
+func TestAddNoPinDeprecated(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       h, err := s.AddNoPin(bytes.NewBufferString(randString(32)))
+       is.Nil(err)
+
+       pins, err := s.Pins()
+       is.Nil(err)
+
+       _, ok := pins[h]
+       is.False(ok)
+}
+
+func TestAddDir(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       cid, err := s.AddDir("./testdata")
+       is.Nil(err)
+       is.Equal(cid, "QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv")
+}
+
+func TestLocalShell(t *testing.T) {
+       is := is.New(t)
+       s := NewLocalShell()
+       is.NotNil(s)
+
+       mhash, err := s.Add(bytes.NewBufferString("Hello IPFS Shell tests"))
+       is.Nil(err)
+       is.Equal(mhash, "QmUfZ9rAdhV5ioBzXKdUTh2ZNsz9bzbkaLVyQ8uc8pj21F")
+}
+
+func TestCat(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       rc, err := s.Cat(fmt.Sprintf("/ipfs/%s/readme", examplesHash))
+       is.Nil(err)
+
+       md5 := md5.New()
+       _, err = io.Copy(md5, rc)
+       is.Nil(err)
+       is.Equal(fmt.Sprintf("%x", md5.Sum(nil)), "3fdcaad186e79983a6920b4c7eeda949")
+}
+
+func TestList(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       list, err := s.List(fmt.Sprintf("/ipfs/%s", examplesHash))
+       is.Nil(err)
+
+       is.Equal(len(list), 7)
+
+       // TODO: document difference in size between 'ipfs ls' and 'ipfs file ls -v'. additional object encoding in data block?
+       expected := map[string]LsLink{
+               "about":          {Type: TFile, Hash: "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V", Name: "about", Size: 1677},
+               "contact":        {Type: TFile, Hash: "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", Name: "contact", Size: 189},
+               "help":           {Type: TFile, Hash: "QmY5heUM5qgRubMDD1og9fhCPA6QdkMp3QCwd4s7gJsyE7", Name: "help", Size: 311},
+               "ping":           {Type: TFile, Hash: "QmejvEPop4D7YUadeGqYWmZxHhLc4JBUCzJJHWMzdcMe2y", Name: "ping", Size: 4},
+               "quick-start":    {Type: TFile, Hash: "QmXgqKTbzdh83pQtKFb19SpMCpDDcKR2ujqk3pKph9aCNF", Name: "quick-start", Size: 1681},
+               "readme":         {Type: TFile, Hash: "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", Name: "readme", Size: 1091},
+               "security-notes": {Type: TFile, Hash: "QmQ5vhrL7uv6tuoN9KeVBwd4PwfQkXdVVmDLUZuTNxqgvm", Name: "security-notes", Size: 1162},
+       }
+       for _, l := range list {
+               el, ok := expected[l.Name]
+               is.True(ok)
+               is.NotNil(el)
+               is.Equal(*l, el)
+       }
+}
+
+func TestFileList(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       list, err := s.FileList(fmt.Sprintf("/ipfs/%s", examplesHash))
+       is.Nil(err)
+
+       is.Equal(list.Type, "Directory")
+       is.Equal(list.Size, 0)
+       is.Equal(len(list.Links), 7)
+
+       // TODO: document difference in sice betwen 'ipfs ls' and 'ipfs file ls -v'. additional object encoding in data block?
+       expected := map[string]UnixLsLink{
+               "about":          {Type: "File", Hash: "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V", Name: "about", Size: 1677},
+               "contact":        {Type: "File", Hash: "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y", Name: "contact", Size: 189},
+               "help":           {Type: "File", Hash: "QmY5heUM5qgRubMDD1og9fhCPA6QdkMp3QCwd4s7gJsyE7", Name: "help", Size: 311},
+               "ping":           {Type: "File", Hash: "QmejvEPop4D7YUadeGqYWmZxHhLc4JBUCzJJHWMzdcMe2y", Name: "ping", Size: 4},
+               "quick-start":    {Type: "File", Hash: "QmXgqKTbzdh83pQtKFb19SpMCpDDcKR2ujqk3pKph9aCNF", Name: "quick-start", Size: 1681},
+               "readme":         {Type: "File", Hash: "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB", Name: "readme", Size: 1091},
+               "security-notes": {Type: "File", Hash: "QmQ5vhrL7uv6tuoN9KeVBwd4PwfQkXdVVmDLUZuTNxqgvm", Name: "security-notes", Size: 1162},
+       }
+       for _, l := range list.Links {
+               el, ok := expected[l.Name]
+               is.True(ok)
+               is.NotNil(el)
+               is.Equal(*l, el)
+       }
+}
+
+func TestPins(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       // Add a thing, which pins it by default
+       h, err := s.Add(bytes.NewBufferString("go-ipfs-api pins test 9F3D1F30-D12A-4024-9477-8F0C8E4B3A63"))
+       is.Nil(err)
+
+       pins, err := s.Pins()
+       is.Nil(err)
+
+       _, ok := pins[h]
+       is.True(ok)
+
+       err = s.Unpin(h)
+       is.Nil(err)
+
+       pins, err = s.Pins()
+       is.Nil(err)
+
+       _, ok = pins[h]
+       is.False(ok)
+
+       err = s.Pin(h)
+       is.Nil(err)
+
+       pins, err = s.Pins()
+       is.Nil(err)
+
+       info, ok := pins[h]
+       is.True(ok)
+       is.Equal(info.Type, RecursivePin)
+}
+
+func TestPatch_rmLink(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       newRoot, err := s.Patch(examplesHash, "rm-link", "about")
+       is.Nil(err)
+       is.Equal(newRoot, "QmPmCJpciopaZnKcwymfQyRAEjXReR6UL2rdSfEscZfzcp")
+}
+
+func TestPatchLink(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       newRoot, err := s.PatchLink(examplesHash, "about", "QmUXTtySmd7LD4p6RG6rZW6RuUuPZXTtNMmRQ6DSQo3aMw", true)
+       is.Nil(err)
+       is.Equal(newRoot, "QmVfe7gesXf4t9JzWePqqib8QSifC1ypRBGeJHitSnF7fA")
+       newRoot, err = s.PatchLink(examplesHash, "about", "QmUXTtySmd7LD4p6RG6rZW6RuUuPZXTtNMmRQ6DSQo3aMw", false)
+       is.Nil(err)
+       is.Equal(newRoot, "QmVfe7gesXf4t9JzWePqqib8QSifC1ypRBGeJHitSnF7fA")
+       newHash, err := s.NewObject("unixfs-dir")
+       is.Nil(err)
+       _, err = s.PatchLink(newHash, "a/b/c", newHash, false)
+       is.NotNil(err)
+       newHash, err = s.PatchLink(newHash, "a/b/c", newHash, true)
+       is.Nil(err)
+       is.Equal(newHash, "QmQ5D3xbMWFQRC9BKqbvnSnHri31GqvtWG1G6rE8xAZf1J")
+}
+
+func TestResolvePath(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       childHash, err := s.ResolvePath(fmt.Sprintf("/ipfs/%s/about", examplesHash))
+       is.Nil(err)
+       is.Equal(childHash, "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V")
+}
+
+func TestPubSub(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       var (
+               topic = "test"
+
+               sub *PubSubSubscription
+               err error
+       )
+
+       t.Log("subscribing...")
+       sub, err = s.PubSubSubscribe(topic)
+       is.Nil(err)
+       is.NotNil(sub)
+       t.Log("sub: done")
+
+       time.Sleep(10 * time.Millisecond)
+
+       t.Log("publishing...")
+       is.Nil(s.PubSubPublish(topic, "Hello World!"))
+       t.Log("pub: done")
+
+       t.Log("next()...")
+       r, err := sub.Next()
+       t.Log("next: done. ")
+
+       is.Nil(err)
+       is.NotNil(r)
+       is.Equal(r.Data, "Hello World!")
+
+       sub2, err := s.PubSubSubscribe(topic)
+       is.Nil(err)
+       is.NotNil(sub2)
+
+       is.Nil(s.PubSubPublish(topic, "Hallo Welt!"))
+
+       r, err = sub2.Next()
+       is.Nil(err)
+       is.NotNil(r)
+       is.Equal(r.Data, "Hallo Welt!")
+
+       r, err = sub.Next()
+       is.NotNil(r)
+       is.Nil(err)
+       is.Equal(r.Data, "Hallo Welt!")
+
+       is.Nil(sub.Cancel())
+}
+
+func TestObjectStat(t *testing.T) {
+       obj := "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V"
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       stat, err := s.ObjectStat("QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V")
+       is.Nil(err)
+       is.Equal(stat.Hash, obj)
+       is.Equal(stat.LinksSize, 3)
+       is.Equal(stat.CumulativeSize, 1688)
+}
+
+func TestDagPut(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       c, err := s.DagPut(`{"x": "abc","y":"def"}`, "json", "cbor")
+       is.Nil(err)
+       is.Equal(c, "zdpuAt47YjE9XTgSxUBkiYCbmnktKajQNheQBGASHj3FfYf8M")
+}
+
+func TestDagPutWithOpts(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       c, err := s.DagPutWithOpts(`{"x": "abc","y":"def"}`, options.Dag.Pin("true"))
+       is.Nil(err)
+       is.Equal(c, "zdpuAt47YjE9XTgSxUBkiYCbmnktKajQNheQBGASHj3FfYf8M")
+}
+
+func TestStatsBW(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       _, err := s.StatsBW(context.Background())
+       is.Nil(err)
+}
+
+func TestSwarmPeers(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+       _, err := s.SwarmPeers(context.Background())
+       is.Nil(err)
+}
+
+const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+const (
+       letterIdxBits = 6                    // 6 bits to represent a letter index
+       letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
+       letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
+)
+
+var src = rand.NewSource(time.Now().UnixNano())
+
+func randString(n int) string {
+       b := make([]byte, n)
+       // A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
+       for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
+               if remain == 0 {
+                       cache, remain = src.Int63(), letterIdxMax
+               }
+               if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
+                       b[i] = letterBytes[idx]
+                       i--
+               }
+               cache >>= letterIdxBits
+               remain--
+       }
+
+       return string(b)
+}
+
+func TestRefs(t *testing.T) {
+       is := is.New(t)
+       s := NewShell(shellUrl)
+
+       cid, err := s.AddDir("./testdata")
+       is.Nil(err)
+       is.Equal(cid, "QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv")
+       refs, err := s.Refs(cid, false)
+       is.Nil(err)
+       expected := []string{
+               "QmZTR5bcpQD7cFgTorqxZDYaew1Wqgfbd2ud9QqGPAkK2V",
+               "QmYCvbfNbCwFR45HiNP45rwJgvatpiW38D961L5qAhUM5Y",
+               "QmY5heUM5qgRubMDD1og9fhCPA6QdkMp3QCwd4s7gJsyE7",
+               "QmejvEPop4D7YUadeGqYWmZxHhLc4JBUCzJJHWMzdcMe2y",
+               "QmXgqKTbzdh83pQtKFb19SpMCpDDcKR2ujqk3pKph9aCNF",
+               "QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB",
+               "QmQ5vhrL7uv6tuoN9KeVBwd4PwfQkXdVVmDLUZuTNxqgvm",
+       }
+       var actual []string
+       for r := range refs {
+               actual = append(actual, r)
+       }
+
+       sort.Strings(expected)
+       sort.Strings(actual)
+       is.Equal(expected, actual)
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/about b/vendor/github.com/ipfs/go-ipfs-api/testdata/about
new file mode 100644 (file)
index 0000000..eaa644b
--- /dev/null
@@ -0,0 +1,53 @@
+
+                  IPFS -- Inter-Planetary File system
+
+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 bit-
+torrent 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 protocol:
+- defines a content-addressed file system
+- coordinates content delivery
+- combines Kademlia + BitTorrent + Git
+
+IPFS is a filesystem:
+- has directories and files
+- mountable filesystem (via FUSE)
+
+IPFS is a web:
+- can be used to view documents like the web
+- files accessible via HTTP at `http://ipfs.io/<path>`
+- browsers or extensions can learn to use `ipfs://` directly
+- hash-addressed content guarantees authenticity
+
+IPFS is modular:
+- connection layer over any network protocol
+- routing layer
+- uses a routing layer DHT (kademlia/coral)
+- uses a path-based naming service
+- uses bittorrent-inspired block exchange
+
+IPFS uses crypto:
+- cryptographic-hash content addressing
+- block-level deduplication
+- file integrity + versioning
+- filesystem-level encryption + signing support
+
+IPFS is p2p:
+- worldwide peer-to-peer file transfers
+- completely decentralized architecture
+- **no** central point of failure
+
+IPFS is a cdn:
+- add a file to the filesystem locally, and it's now available to the world
+- caching-friendly (content-hash naming)
+- bittorrent-based bandwidth distribution
+
+IPFS has a name service:
+- IPNS, an SFS inspired name system
+- global namespace based on PKI
+- serves to build trust chains
+- compatible with other NSes
+- can map DNS, .onion, .bit, etc to IPNS
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/contact b/vendor/github.com/ipfs/go-ipfs-api/testdata/contact
new file mode 100644 (file)
index 0000000..965de02
--- /dev/null
@@ -0,0 +1,6 @@
+Come hang out in our IRC chat room if you have any questions.
+
+Contact the ipfs dev team:
+- Bugs: https://github.com/ipfs/go-ipfs/issues
+- Help: irc.freenode.org/#ipfs
+- Email: dev@ipfs.io
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/help b/vendor/github.com/ipfs/go-ipfs-api/testdata/help
new file mode 100644 (file)
index 0000000..d069d6b
--- /dev/null
@@ -0,0 +1,7 @@
+Some helpful resources for finding your way around ipfs:
+
+- quick-start: a quick show of various ipfs features.
+- ipfs commands: a list of all commands
+- ipfs --help: every command describes itself
+- https://github.com/ipfs/go-ipfs -- the src repository
+- #ipfs on irc.freenode.org -- the community irc channel
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/ping b/vendor/github.com/ipfs/go-ipfs-api/testdata/ping
new file mode 100644 (file)
index 0000000..911dd04
--- /dev/null
@@ -0,0 +1 @@
+ipfs
\ No newline at end of file
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/quick-start b/vendor/github.com/ipfs/go-ipfs-api/testdata/quick-start
new file mode 100644 (file)
index 0000000..9de9835
--- /dev/null
@@ -0,0 +1,113 @@
+# 0.1 - Quick Start
+
+This is a set of short examples with minimal explanation. It is meant as
+a "quick start".
+
+
+Add a file to ipfs:
+
+  echo "hello world" >hello
+  ipfs add hello
+
+
+View it:
+
+  ipfs cat <the-hash-you-got-here>
+
+
+Try a directory:
+
+  mkdir foo
+  mkdir foo/bar
+  echo "baz" > foo/baz
+  echo "baz" > foo/bar/baz
+  ipfs add -r foo
+
+
+View things:
+
+  ipfs ls <the-hash-here>
+  ipfs ls <the-hash-here>/bar
+  ipfs cat <the-hash-here>/baz
+  ipfs cat <the-hash-here>/bar/baz
+  ipfs cat <the-hash-here>/bar
+  ipfs ls <the-hash-here>/baz
+
+
+References:
+
+  ipfs refs <the-hash-here>
+  ipfs refs -r <the-hash-here>
+  ipfs refs --help
+
+
+Get:
+
+  ipfs get <the-hash-here> -o foo2
+  diff foo foo2
+
+
+Objects:
+
+  ipfs object get <the-hash-here>
+  ipfs object get <the-hash-here>/foo2
+  ipfs object --help
+
+
+Pin + GC:
+
+  ipfs pin add <the-hash-here>
+  ipfs repo gc
+  ipfs ls <the-hash-here>
+  ipfs pin rm <the-hash-here>
+  ipfs repo gc
+
+
+Daemon:
+
+  ipfs daemon  (in another terminal)
+  ipfs id
+
+
+Network:
+
+  (must be online)
+  ipfs swarm peers
+  ipfs id
+  ipfs cat <hash-of-remote-object>
+
+
+Mount:
+
+  (warning: fuse is finicky!)
+  ipfs mount
+  cd /ipfs/<the-hash-here>
+  ls
+
+
+Tool:
+
+  ipfs version
+  ipfs update
+  ipfs commands
+  ipfs config --help
+  open http://localhost:5001/webui
+
+
+Browse:
+
+  webui:
+
+    http://localhost:5001/webui
+
+  video:
+
+    http://localhost:8080/ipfs/QmVc6zuAneKJzicnJpfrqCH9gSy6bz54JhcypfJYhGUFQu/play#/ipfs/QmTKZgRNwDNZwHtJSjCp6r5FYefzpULfy37JvMt9DwvXse
+
+  images:
+
+    http://localhost:8080/ipfs/QmZpc3HvfjEXvLWGQPWbHk3AjD5j8NEN4gmFN8Jmrd5g83/cs
+
+  markdown renderer app:
+
+    http://localhost:8080/ipfs/QmX7M9CiYXjVeFnkfVGf3y5ixTZ2ACeSGyL1vBJY1HvQPp/mdown
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/readme b/vendor/github.com/ipfs/go-ipfs-api/testdata/readme
new file mode 100644 (file)
index 0000000..eeade66
--- /dev/null
@@ -0,0 +1,26 @@
+Hello and Welcome to IPFS!
+
+██╗██████╗ ███████╗███████╗
+██║██╔══██╗██╔════╝██╔════╝
+██║██████╔╝█████╗  ███████╗
+██║██╔═══╝ ██╔══╝  ╚════██║
+██║██║     ██║     ███████║
+╚═╝╚═╝     ╚═╝     ╚══════╝
+
+If you're seeing this, you have successfully installed
+IPFS and are now interfacing with the ipfs merkledag!
+
+ -------------------------------------------------------
+| Warning:                                              |
+|   This is alpha software. Use at your own discretion! |
+|   Much is missing or lacking polish. There are bugs.  |
+|   Not yet secure. Read the security notes for more.   |
+ -------------------------------------------------------
+
+Check out some of the other files in this directory:
+
+  ./about
+  ./help
+  ./quick-start     <-- usage examples
+  ./readme          <-- this file
+  ./security-notes
diff --git a/vendor/github.com/ipfs/go-ipfs-api/testdata/security-notes b/vendor/github.com/ipfs/go-ipfs-api/testdata/security-notes
new file mode 100644 (file)
index 0000000..00b70b6
--- /dev/null
@@ -0,0 +1,25 @@
+                    IPFS Alpha Security Notes
+
+We try hard to ensure our system is safe and robust, but all software
+has bugs, especially new software. This distribution is meant to be an
+alpha preview, don't use it for anything mission critical.
+
+Please note the following:
+
+- This is alpha software and has not been audited. It is our goal
+  to conduct a proper security audit once we close in on a 1.0 release.
+
+- ipfs is a networked program, and may have serious undiscovered
+  vulnerabilities. It is written in Go, and we do not execute any
+  user provided data. But please point any problems out to us in a
+  github issue, or email security@ipfs.io privately.
+
+- security@ipfs.io GPG key:
+  - 4B9665FB 92636D17 7C7A86D3 50AAE8A9 59B13AF3
+  - https://pgp.mit.edu/pks/lookup?op=get&search=0x50AAE8A959B13AF3
+
+- ipfs uses encryption for all communication, but it's NOT PROVEN SECURE
+  YET!  It may be totally broken. For now, the code is included to make
+  sure we benchmark our operations with encryption in mind. In the future,
+  there will be an "unsafe" mode for high performance intranet apps.
+  If this is a blocking feature for you, please contact us.
diff --git a/vendor/github.com/ipfs/go-ipfs-api/tests/main.go b/vendor/github.com/ipfs/go-ipfs-api/tests/main.go
new file mode 100644 (file)
index 0000000..7784a95
--- /dev/null
@@ -0,0 +1,106 @@
+package main
+
+import (
+       "fmt"
+       "io"
+       "math/rand"
+       "time"
+
+       "github.com/ipfs/go-ipfs-api"
+
+       u "github.com/ipfs/go-ipfs-util"
+)
+
+var sh *shell.Shell
+var ncalls int
+
+var _ = time.ANSIC
+
+func sleep() {
+       ncalls++
+       //time.Sleep(time.Millisecond * 5)
+}
+
+func randString() string {
+       alpha := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
+       l := rand.Intn(10) + 2
+
+       var s string
+       for i := 0; i < l; i++ {
+               s += string([]byte{alpha[rand.Intn(len(alpha))]})
+       }
+       return s
+}
+
+func makeRandomObject() (string, error) {
+       // do some math to make a size
+       x := rand.Intn(120) + 1
+       y := rand.Intn(120) + 1
+       z := rand.Intn(120) + 1
+       size := x * y * z
+
+       r := io.LimitReader(u.NewTimeSeededRand(), int64(size))
+       sleep()
+       return sh.Add(r)
+}
+
+func makeRandomDir(depth int) (string, error) {
+       if depth <= 0 {
+               return makeRandomObject()
+       }
+       sleep()
+       empty, err := sh.NewObject("unixfs-dir")
+       if err != nil {
+               return "", err
+       }
+
+       curdir := empty
+       for i := 0; i < rand.Intn(8)+2; i++ {
+               var obj string
+               if rand.Intn(2) == 1 {
+                       obj, err = makeRandomObject()
+                       if err != nil {
+                               return "", err
+                       }
+               } else {
+                       obj, err = makeRandomDir(depth - 1)
+                       if err != nil {
+                               return "", err
+                       }
+               }
+
+               name := randString()
+               sleep()
+               nobj, err := sh.PatchLink(curdir, name, obj, true)
+               if err != nil {
+                       return "", err
+               }
+               curdir = nobj
+       }
+
+       return curdir, nil
+}
+
+func main() {
+       sh = shell.NewShell("localhost:5001")
+       for i := 0; i < 200; i++ {
+               _, err := makeRandomObject()
+               if err != nil {
+                       fmt.Println("err: ", err)
+                       return
+               }
+       }
+       fmt.Println("we're okay")
+
+       out, err := makeRandomDir(10)
+       fmt.Printf("%d calls\n", ncalls)
+       if err != nil {
+               fmt.Println(err)
+               return
+       }
+
+       fmt.Println(out)
+       for {
+               time.Sleep(time.Second * 1000)
+       }
+}
diff --git a/vendor/github.com/ipfs/go-ipfs-api/unixfs.go b/vendor/github.com/ipfs/go-ipfs-api/unixfs.go
new file mode 100644 (file)
index 0000000..bc862a3
--- /dev/null
@@ -0,0 +1,38 @@
+package shell
+
+import (
+       "context"
+       "fmt"
+)
+
+type UnixLsObject struct {
+       Hash  string
+       Size  uint64
+       Type  string
+       Links []*UnixLsLink
+}
+
+type UnixLsLink struct {
+       Hash string
+       Name string
+       Size uint64
+       Type string
+}
+
+type lsOutput struct {
+       Objects map[string]*UnixLsObject
+}
+
+// FileList entries at the given path using the UnixFS commands
+func (s *Shell) FileList(path string) (*UnixLsObject, error) {
+       var out lsOutput
+       if err := s.Request("file/ls", path).Exec(context.Background(), &out); err != nil {
+               return nil, err
+       }
+
+       for _, object := range out.Objects {
+               return object, nil
+       }
+
+       return nil, fmt.Errorf("no object in results")
+}