@cryptotaxi247 / kubo / commits / 529f84726

coreapi: Basic object API implementation

License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>

Łukasz Magiera committed Dec 14, 2017 at 23:55 UTC 529f84726e8705947adad4bdac9af1196bea841a
3 files changed +217 -21
core/coreapi/coreapi.go
+4
@@ -41,6 +41,10 @@ func (api *CoreAPI) Key() coreiface.KeyAPI {
41 return &KeyAPI{api, nil}
42 }
43
44 +func (api *CoreAPI) Object() coreiface.ObjectAPI {
45 + return (*ObjectAPI)(api)
46 +}
47 +
48 // ResolveNode resolves the path `p` using Unixfx resolver, gets and returns the
49 // resolved Node.
50 func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (coreiface.Node, error) {
core/coreapi/interface/interface.go
+23 -21
@@ -191,27 +191,29 @@ type KeyAPI interface {
191 Remove(ctx context.Context, name string) (Path, error)
192 }
193
194 -// type ObjectAPI interface {
195 -// New() (cid.Cid, Object)
196 -// Get(string) (Object, error)
197 -// Links(string) ([]*Link, error)
198 -// Data(string) (Reader, error)
199 -// Stat(string) (ObjectStat, error)
200 -// Put(Object) (cid.Cid, error)
201 -// SetData(string, Reader) (cid.Cid, error)
202 -// AppendData(string, Data) (cid.Cid, error)
203 -// AddLink(string, string, string) (cid.Cid, error)
204 -// RmLink(string, string) (cid.Cid, error)
205 -// }
206 -
207 -// type ObjectStat struct {
208 -// Cid cid.Cid
209 -// NumLinks int
210 -// BlockSize int
211 -// LinksSize int
212 -// DataSize int
213 -// CumulativeSize int
214 -// }
194 +//TODO: Should this use paths instead of cids?
195 +type ObjectAPI interface {
196 + New(ctx context.Context) (Node, error)
197 + Put(context.Context, Node) error
198 + Get(context.Context, Path) (Node, error)
199 + Data(context.Context, Path) (io.Reader, error)
200 + Links(context.Context, Path) ([]*Link, error)
201 + Stat(context.Context, Path) (*ObjectStat, error)
202 +
203 + AddLink(ctx context.Context, base Path, name string, child Path, create bool) (Node, error) //TODO: make create optional
204 + RmLink(context.Context, Path, string) (Node, error)
205 + AppendData(context.Context, Path, io.Reader) (Node, error)
206 + SetData(context.Context, Path, io.Reader) (Node, error)
207 +}
208 +
209 +type ObjectStat struct {
210 + Cid *cid.Cid
211 + NumLinks int
212 + BlockSize int
213 + LinksSize int
214 + DataSize int
215 + CumulativeSize int
216 +}
217
218 var ErrIsDir = errors.New("object is a directory")
219 var ErrOffline = errors.New("can't resolve, ipfs node is offline")
core/coreapi/object.go new
+190
@@ -0,0 +1,190 @@
1 +package coreapi
2 +
3 +import (
4 + "bytes"
5 + "context"
6 + "errors"
7 + "io"
8 + "io/ioutil"
9 +
10 + "github.com/ipfs/go-ipfs/merkledag/utils"
11 +
12 + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
13 + dag "github.com/ipfs/go-ipfs/merkledag"
14 + ft "github.com/ipfs/go-ipfs/unixfs"
15 +)
16 +
17 +type ObjectAPI CoreAPI
18 +
19 +func (api *ObjectAPI) New(ctx context.Context) (coreiface.Node, error) {
20 + node := new(dag.ProtoNode)
21 +
22 + _, err := api.node.DAG.Add(node)
23 + if err != nil {
24 + return nil, err
25 + }
26 + return node, nil
27 +}
28 +
29 +func (api *ObjectAPI) Put(context.Context, coreiface.Node) error {
30 + return errors.New("todo") // TODO: what should this method take? Should we just redir to dag-put?f
31 +}
32 +
33 +func (api *ObjectAPI) Get(ctx context.Context, path coreiface.Path) (coreiface.Node, error) {
34 + return api.core().ResolveNode(ctx, path)
35 +}
36 +
37 +func (api *ObjectAPI) Data(ctx context.Context, path coreiface.Path) (io.Reader, error) {
38 + nd, err := api.core().ResolveNode(ctx, path)
39 + if err != nil {
40 + return nil, err
41 + }
42 +
43 + pbnd, ok := nd.(*dag.ProtoNode)
44 + if !ok {
45 + return nil, dag.ErrNotProtobuf
46 + }
47 +
48 + return bytes.NewReader(pbnd.Data()), nil
49 +}
50 +
51 +func (api *ObjectAPI) Links(ctx context.Context, path coreiface.Path) ([]*coreiface.Link, error) {
52 + nd, err := api.core().ResolveNode(ctx, path)
53 + if err != nil {
54 + return nil, err
55 + }
56 +
57 + links := nd.Links()
58 + out := make([]*coreiface.Link, len(links))
59 + for n, l := range links {
60 + out[n] = (*coreiface.Link)(l)
61 + }
62 +
63 + return out, nil
64 +}
65 +
66 +func (api *ObjectAPI) Stat(ctx context.Context, path coreiface.Path) (*coreiface.ObjectStat, error) {
67 + nd, err := api.core().ResolveNode(ctx, path)
68 + if err != nil {
69 + return nil, err
70 + }
71 +
72 + stat, err := nd.Stat()
73 + if err != nil {
74 + return nil, err
75 + }
76 +
77 + out := &coreiface.ObjectStat{
78 + Cid: nd.Cid(),
79 + NumLinks: stat.NumLinks,
80 + BlockSize: stat.BlockSize,
81 + LinksSize: stat.LinksSize,
82 + DataSize: stat.DataSize,
83 + CumulativeSize: stat.CumulativeSize,
84 + }
85 +
86 + return out, nil
87 +}
88 +
89 +func (api *ObjectAPI) AddLink(ctx context.Context, base coreiface.Path, name string, child coreiface.Path, create bool) (coreiface.Node, error) {
90 + rootNd, err := api.core().ResolveNode(ctx, base)
91 + if err != nil {
92 + return nil, err
93 + }
94 +
95 + childNd, err := api.core().ResolveNode(ctx, child)
96 + if err != nil {
97 + return nil, err
98 + }
99 +
100 + rootPb, ok := rootNd.(*dag.ProtoNode)
101 + if !ok {
102 + return nil, dag.ErrNotProtobuf
103 + }
104 +
105 + var createfunc func() *dag.ProtoNode
106 + if create {
107 + createfunc = ft.EmptyDirNode
108 + }
109 +
110 + e := dagutils.NewDagEditor(rootPb, api.node.DAG)
111 +
112 + err = e.InsertNodeAtPath(ctx, name, childNd, createfunc)
113 + if err != nil {
114 + return nil, err
115 + }
116 +
117 + nnode, err := e.Finalize(api.node.DAG)
118 + if err != nil {
119 + return nil, err
120 + }
121 +
122 + return nnode, nil
123 +}
124 +
125 +func (api *ObjectAPI) RmLink(ctx context.Context, root coreiface.Path, link string) (coreiface.Node, error) {
126 + rootNd, err := api.core().ResolveNode(ctx, root)
127 + if err != nil {
128 + return nil, err
129 + }
130 +
131 + rootPb, ok := rootNd.(*dag.ProtoNode)
132 + if !ok {
133 + return nil, dag.ErrNotProtobuf
134 + }
135 +
136 + e := dagutils.NewDagEditor(rootPb, api.node.DAG)
137 +
138 + err = e.RmLink(ctx, link)
139 + if err != nil {
140 + return nil, err
141 + }
142 +
143 + nnode, err := e.Finalize(api.node.DAG)
144 + if err != nil {
145 + return nil, err
146 + }
147 +
148 + return nnode, nil
149 +}
150 +
151 +func (api *ObjectAPI) AppendData(ctx context.Context, path coreiface.Path, r io.Reader) (coreiface.Node, error) {
152 + return api.patchData(ctx, path, r, true)
153 +}
154 +
155 +func (api *ObjectAPI) SetData(ctx context.Context, path coreiface.Path, r io.Reader) (coreiface.Node, error) {
156 + return api.patchData(ctx, path, r, false)
157 +}
158 +
159 +func (api *ObjectAPI) patchData(ctx context.Context, path coreiface.Path, r io.Reader, appendData bool) (coreiface.Node, error) {
160 + nd, err := api.core().ResolveNode(ctx, path)
161 + if err != nil {
162 + return nil, err
163 + }
164 +
165 + pbnd, ok := nd.(*dag.ProtoNode)
166 + if !ok {
167 + return nil, dag.ErrNotProtobuf
168 + }
169 +
170 + data, err := ioutil.ReadAll(r)
171 + if err != nil {
172 + return nil, err
173 + }
174 +
175 + if appendData {
176 + data = append(pbnd.Data(), data...)
177 + }
178 + pbnd.SetData(data)
179 +
180 + _, err = api.node.DAG.Add(pbnd)
181 + if err != nil {
182 + return nil, err
183 + }
184 +
185 + return pbnd, nil
186 +}
187 +
188 +func (api *ObjectAPI) core() coreiface.CoreAPI {
189 + return (*CoreAPI)(api)
190 +}