Block API
This commit was moved from ipfs/go-ipfs-http-client@d0c98b870e55bed78fa777793e520f08157deb4f
Łukasz Magiera committed
Jan 7, 2019 at 23:44 UTC
e8da6e2cf9a8fd40c5fd960a60ce1b1b27ada713
4 files changed
+121
-13
client/httpapi/api.go
+1
-1
@@ -118,7 +118,7 @@ func (api *HttpApi) Dag() iface.DagAPI {
118
}
119
120
func (api *HttpApi) Name() iface.NameAPI {
121
- return (*NameAPI)(api)
121
+ return nil
122
}
123
124
func (api *HttpApi) Key() iface.KeyAPI {
client/httpapi/api_test.go
+9
-2
@@ -3,7 +3,6 @@ package httpapi
3
import (
4
"context"
5
"fmt"
6
- "github.com/ipfs/iptb/testbed/interfaces"
6
"io/ioutil"
7
"os"
8
"path"
@@ -16,6 +15,7 @@ import (
15
local "github.com/ipfs/iptb-plugins/local"
16
"github.com/ipfs/iptb/cli"
17
"github.com/ipfs/iptb/testbed"
18
+ "github.com/ipfs/iptb/testbed/interfaces"
19
)
20
21
type NodeProvider struct{}
@@ -39,7 +39,14 @@ func (NodeProvider) MakeAPISwarm(ctx context.Context, fullIdentity bool, n int)
39
}
40
41
c := cli.NewCli()
42
- if err := c.Run([]string{"iptb", "--IPTB_ROOT", dir, "auto", "-type", "localipfs", "-count", strconv.FormatInt(int64(n), 10), "--start"}); err != nil {
42
+
43
+ initArgs := []string{"iptb", "--IPTB_ROOT", dir, "auto", "-type", "localipfs", "-count", strconv.FormatInt(int64(n), 10)}
44
+ if err := c.Run(initArgs); err != nil {
45
+ return nil, err
46
+ }
47
+
48
+ startArgs := []string{"iptb", "--IPTB_ROOT", dir, "start", "-wait", "--", "--offline=" + strconv.FormatBool(n == 1)}
49
+ if err := c.Run(startArgs); err != nil {
50
return nil, err
51
}
52
client/httpapi/block.go
+99
-10
@@ -1,17 +1,69 @@
1
package httpapi
2
3
import (
4
+ "bytes"
5
"context"
6
+ "errors"
7
+ "fmt"
8
"io"
9
10
+ "github.com/ipfs/go-cid"
11
"github.com/ipfs/go-ipfs/core/coreapi/interface"
8
- "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
12
+ caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
13
+ mh "github.com/multiformats/go-multihash"
14
)
15
16
type BlockAPI HttpApi
17
13
-func (api *BlockAPI) Put(ctx context.Context, r io.Reader, opts ...options.BlockPutOption) (iface.BlockStat, error) {
14
- return nil, ErrNotImplemented
18
+type blockStat struct {
19
+ Key string
20
+ BSize int `json:"Size"`
21
+}
22
+
23
+func (s *blockStat) Size() int {
24
+ return s.BSize
25
+}
26
+
27
+func (s *blockStat) valid() (iface.ResolvedPath, error) {
28
+ c, err := cid.Parse(s.Key)
29
+ if err != nil {
30
+ return nil, err
31
+ }
32
+
33
+ return iface.IpldPath(c), nil
34
+}
35
+
36
+func (s *blockStat) Path() iface.ResolvedPath {
37
+ p, _ := s.valid()
38
+ return p
39
+}
40
+
41
+func (api *BlockAPI) Put(ctx context.Context, r io.Reader, opts ...caopts.BlockPutOption) (iface.BlockStat, error) {
42
+ options, _, err := caopts.BlockPutOptions(opts...)
43
+ if err != nil {
44
+ return nil, err
45
+ }
46
+
47
+ mht, ok := mh.Codes[options.MhType]
48
+ if !ok {
49
+ return nil, fmt.Errorf("unknowm mhType %d", options.MhType)
50
+ }
51
+
52
+ req := api.core().request("block/put").
53
+ Option("mhtype", mht).
54
+ Option("mhlen", options.MhLength).
55
+ Option("format", options.Codec).
56
+ FileBody(r)
57
+
58
+ var out blockStat
59
+ if err := req.Exec(ctx, &out); err != nil {
60
+ return nil, err
61
+ }
62
+ if _, err := out.valid(); err != nil {
63
+ return nil, err
64
+ }
65
+
66
+ return &out, nil
67
}
68
69
func (api *BlockAPI) Get(ctx context.Context, p iface.Path) (io.Reader, error) {
@@ -19,20 +71,57 @@ func (api *BlockAPI) Get(ctx context.Context, p iface.Path) (io.Reader, error) {
71
if err != nil {
72
return nil, err
73
}
74
+ if resp.Error != nil {
75
+ return nil, resp.Error
76
+ }
77
23
- //TODO: is close on the reader enough?
24
- //defer resp.Close()
78
+ //TODO: make get return ReadCloser to avoid copying
79
+ defer resp.Close()
80
+ b := new(bytes.Buffer)
81
+ if _, err := io.Copy(b, resp.Output); err != nil {
82
+ return nil, err
83
+ }
84
26
- //TODO: make blockApi return ReadCloser
27
- return resp.Output, resp.Error
85
+ return b, nil
86
}
87
30
-func (api *BlockAPI) Rm(ctx context.Context, p iface.Path, opts ...options.BlockRmOption) error {
31
- return ErrNotImplemented
88
+func (api *BlockAPI) Rm(ctx context.Context, p iface.Path, opts ...caopts.BlockRmOption) error {
89
+ options, err := caopts.BlockRmOptions(opts...)
90
+ if err != nil {
91
+ return err
92
+ }
93
+
94
+ removedBlock := struct {
95
+ Hash string `json:",omitempty"`
96
+ Error string `json:",omitempty"`
97
+ }{}
98
+
99
+ req := api.core().request("block/rm").
100
+ Option("force", options.Force).
101
+ Arguments(p.String())
102
+
103
+ if err := req.Exec(ctx, &removedBlock); err != nil {
104
+ return err
105
+ }
106
+
107
+ if removedBlock.Error != "" {
108
+ return errors.New(removedBlock.Error)
109
+ }
110
+
111
+ return nil
112
}
113
114
func (api *BlockAPI) Stat(ctx context.Context, p iface.Path) (iface.BlockStat, error) {
35
- return nil, ErrNotImplemented
115
+ var out blockStat
116
+ err := api.core().request("block/stat", p.String()).Exec(ctx, &out)
117
+ if err != nil {
118
+ return nil, err
119
+ }
120
+ if _, err := out.valid(); err != nil {
121
+ return nil, err
122
+ }
123
+
124
+ return &out, nil
125
}
126
127
func (api *BlockAPI) core() *HttpApi {
client/httpapi/requestbuilder.go
+12
@@ -5,8 +5,11 @@ import (
5
"context"
6
"fmt"
7
"io"
8
+ "io/ioutil"
9
"strconv"
10
"strings"
11
+
12
+ "github.com/ipfs/go-ipfs-files"
13
)
14
15
// RequestBuilder is an IPFS commands request builder.
@@ -42,6 +45,15 @@ func (r *RequestBuilder) Body(body io.Reader) *RequestBuilder {
45
return r
46
}
47
48
+// FileBody sets the request body to the given reader wrapped into multipartreader.
49
+func (r *RequestBuilder) FileBody(body io.Reader) *RequestBuilder {
50
+ pr, _ := files.NewReaderPathFile("/dev/stdin", ioutil.NopCloser(body), nil)
51
+ d := files.NewMapDirectory(map[string]files.Node{"": pr})
52
+ r.body = files.NewMultiFileReader(d, false)
53
+
54
+ return r
55
+}
56
+
57
// Option sets the given option.
58
func (r *RequestBuilder) Option(key string, value interface{}) *RequestBuilder {
59
var s string