From 13d79381fe90a99441b5888c5aaa709b9acf4f39 Mon Sep 17 00:00:00 2001 From: Lars Gierth Date: Fri, 24 Jun 2016 23:01:56 +0200 Subject: [PATCH] WIP License: MIT Signed-off-by: Lars Gierth --- core/coreapi/coreapi.go | 48 +++++++++++++++++++++++++---- core/coreapi/coreapi_test.go | 12 ++++++++ core/coreapi/interface/interface.go | 30 ++++++++++-------- core/corehttp/gateway_handler.go | 46 +++++++++++++-------------- path/path.go | 1 + 5 files changed, 93 insertions(+), 44 deletions(-) create mode 100644 core/coreapi/coreapi_test.go diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go index 55c71318eab..877093235b2 100644 --- a/core/coreapi/coreapi.go +++ b/core/coreapi/coreapi.go @@ -3,18 +3,31 @@ package coreapi import ( core "github.com/ipfs/go-ipfs/core" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" + importer "github.com/ipfs/go-ipfs/importer" + chunk "github.com/ipfs/go-ipfs/importer/chunk" dag "github.com/ipfs/go-ipfs/merkledag" path "github.com/ipfs/go-ipfs/path" uio "github.com/ipfs/go-ipfs/unixfs/io" + mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash" context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) +type Link struct { + name string + size uint64 + hash mh.Multihash +} + +func (l *Link) Name() string { return l.name } +func (l *Link) Size() uint64 { return l.size } +func (l *Link) Hash() mh.Multihash { return l.hash } + type CoreAPI struct { ctx context.Context node *core.IpfsNode } -func NewCoreAPI(ctx context.Context, node *core.IpfsNode) (*CoreAPI, error) { +func NewCoreAPI(ctx context.Context, node *core.IpfsNode) (coreiface.CoreAPI, error) { api := &CoreAPI{ctx: ctx, node: node} return api, nil } @@ -27,8 +40,8 @@ func (api *CoreAPI) IpfsNode() *core.IpfsNode { return api.node } -func (api *CoreAPI) resolve(p string) (*dag.Node, error) { - dagnode, err := core.Resolve(api.ctx, api.node, path.Path(p)) +func (api *CoreAPI) resolve(p coreiface.Path) (*dag.Node, error) { + dagnode, err := core.Resolve(api.ctx, api.node, p.(path.Path)) if err == core.ErrNoNamesys && !api.node.OnlineMode() { return nil, coreiface.ErrOffline } else if err != nil { @@ -37,7 +50,12 @@ func (api *CoreAPI) resolve(p string) (*dag.Node, error) { return dagnode, nil } -func (api *CoreAPI) Cat(p string) (coreiface.Data, error) { +func (api *CoreAPI) Cat(p coreiface.Path) (coreiface.Data, error) { + // special case for the empty unixfs directory + if p.String() == "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn" { + return nil, coreiface.ErrDir + } + dagnode, err := api.resolve(p) if err != nil { return nil, err @@ -51,14 +69,32 @@ func (api *CoreAPI) Cat(p string) (coreiface.Data, error) { return r, nil } -func (api *CoreAPI) Ls(p string) ([]coreiface.Link, error) { +func (api *CoreAPI) Ls(p coreiface.Path) ([]coreiface.Link, error) { + // special case for the empty unixfs directory + if p.String() == "/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn" { + return make([]coreiface.Link, 0), nil + } + dagnode, err := api.resolve(p) if err != nil { return nil, err } links := make([]coreiface.Link, len(dagnode.Links)) for i, l := range dagnode.Links { - links[i] = coreiface.Link{Name: l.Name, Size: l.Size, Hash: l.Hash} + links[i] = &Link{l.Name, l.Size, l.Hash} } return links, nil } + +func (api *CoreAPI) Add(data coreiface.DataForAdd) (coreiface.Path, error) { + splitter := chunk.DefaultSplitter(data) + dagnode, err := importer.BuildDagFromReader(api.node.DAG, splitter) + if err != nil { + return path.Path(""), err + } + k, err := api.node.DAG.Add(dagnode) + if err != nil { + return path.Path(""), err + } + return path.Path("/ipfs/" + k.String()), nil +} diff --git a/core/coreapi/coreapi_test.go b/core/coreapi/coreapi_test.go new file mode 100644 index 00000000000..f989335a011 --- /dev/null +++ b/core/coreapi/coreapi_test.go @@ -0,0 +1,12 @@ +package coreapi_test + +import ( + "testing" + + coreapi "github.com/ipfs/go-ipfs/core/coreapi" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" +) + +func TestImplementsInterface(t *testing.T) { + +} diff --git a/core/coreapi/interface/interface.go b/core/coreapi/interface/interface.go index 4c40cc456c1..612471cdb47 100644 --- a/core/coreapi/interface/interface.go +++ b/core/coreapi/interface/interface.go @@ -6,32 +6,36 @@ import ( core "github.com/ipfs/go-ipfs/core" - mh "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash" + mhash "gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash" context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context" ) type CoreAPI interface { Context() context.Context - IpfsNode() *core.IpfsNode // XXX temporary - Cat(string) (Data, error) - Ls(string) ([]Link, error) + IpfsNode() *core.IpfsNode // XXX temporary + Cat(Path) (Data, error) // http GET + Ls(Path) ([]Link, error) // http GET + Add(DataForAdd) (Path, error) // http POST } -type Object struct { - Links []Link - Data Data +type Path interface { + String() string + Segments() []string } -type Link struct { - Name string // utf-8 - Size uint64 - Hash mh.Multihash +type Link interface { + Name() string + Size() uint64 + Hash() mhash.Multihash +} + +type DataForAdd interface { + io.ReadCloser } type Data interface { - io.Reader + DataForAdd io.Seeker - io.Closer } var ErrDir = errors.New("object is a directory") diff --git a/core/corehttp/gateway_handler.go b/core/corehttp/gateway_handler.go index d0ca447e08b..7c946448765 100644 --- a/core/corehttp/gateway_handler.go +++ b/core/corehttp/gateway_handler.go @@ -46,15 +46,6 @@ func newGatewayHandler(api coreiface.CoreAPI, conf GatewayConfig) *gatewayHandle return i } -// TODO(cryptix): find these helpers somewhere else -func (i *gatewayHandler) newDagFromReader(r io.Reader) (*dag.Node, error) { - // TODO(cryptix): change and remove this helper once PR1136 is merged - // return ufs.AddFromReader(i.api.IpfsNode(), r.Body) - return importer.BuildDagFromReader( - i.api.IpfsNode().DAG, - chunk.DefaultSplitter(r)) -} - // TODO(btc): break this apart into separate handlers using a more expressive muxer func (i *gatewayHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer func() { @@ -154,7 +145,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request ipnsHostname = true } - dr, err := i.api.Cat(urlPath) + dr, err := i.api.Cat(path.Path(urlPath)) dir := false if err == coreiface.ErrOffline { w.WriteHeader(http.StatusServiceUnavailable) @@ -215,7 +206,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request return } - links, err := i.api.Ls(urlPath) + links, err := i.api.Ls(path.Path(urlPath)) if err != nil { internalWebError(w, err) return @@ -226,7 +217,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request // loop through files foundIndex := false for _, link := range links { - if link.Name == "index.html" { + if link.Name() == "index.html" { log.Debugf("found index.html link for %s", urlPath) foundIndex = true @@ -238,7 +229,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } // return index page instead. - ir, err := i.api.Cat(urlPath + "/index.html") + ir, err := i.api.Cat(path.Path(urlPath + "/index.html")) if err != nil { internalWebError(w, err) return @@ -251,8 +242,11 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } // See comment above where originalUrlPath is declared. - di := directoryItem{humanize.Bytes(link.Size), link.Name, gopath.Join(originalUrlPath, link.Name)} - dirListing = append(dirListing, di) + dirListing = append(dirListing, directoryItem{ + humanize.Bytes(link.Size()), + link.Name(), + gopath.Join(originalUrlPath, link.Name()), + }) } if !foundIndex { @@ -304,22 +298,24 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request } } -func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { - nd, err := i.newDagFromReader(r.Body) - if err != nil { - internalWebError(w, err) - return - } +// TODO(cryptix): find these helpers somewhere else +func (i *gatewayHandler) newDagFromReader(r io.Reader) (*dag.Node, error) { + // TODO(cryptix): change and remove this helper once PR1136 is merged + // return ufs.AddFromReader(i.api.IpfsNode(), r.Body) + return importer.BuildDagFromReader( + i.api.IpfsNode().DAG, + chunk.DefaultSplitter(r)) +} - k, err := i.api.IpfsNode().DAG.Add(nd) +func (i *gatewayHandler) postHandler(w http.ResponseWriter, r *http.Request) { + p, err := i.api.Add(r.Body) if err != nil { internalWebError(w, err) - return } i.addUserHeaders(w) // ok, _now_ write user's headers. - w.Header().Set("IPFS-Hash", k.String()) - http.Redirect(w, r, ipfsPathPrefix+k.String(), http.StatusCreated) + w.Header().Set("X-IPFS-Path", p.String()) + http.Redirect(w, r, ipfsPathPrefix+p.String(), http.StatusCreated) } func (i *gatewayHandler) putHandler(w http.ResponseWriter, r *http.Request) { diff --git a/path/path.go b/path/path.go index 790168de092..eb056db14b8 100644 --- a/path/path.go +++ b/path/path.go @@ -45,6 +45,7 @@ func (p Path) String() string { } // IsJustAKey returns true if the path is of the form or /ipfs/. +// TODO: this relies on using ParsePath() for instantiating func (p Path) IsJustAKey() bool { parts := p.Segments() return (len(parts) == 2 && parts[0] == "ipfs")