Skip to content

Commit

Permalink
refactor: further simplify node api
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Jan 31, 2023
1 parent 71f5952 commit b4a01af
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 88 deletions.
3 changes: 1 addition & 2 deletions gateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ conf := gateway.Config{
// Initialize a NodeAPI interface for both an online and offline versions.
// The offline version should not make any network request for missing content.
ipfs := ...
offlineIPFS := ...

// Create http mux and setup path gateway handler.
mux := http.NewServeMux()
gwHandler := gateway.NewHandler(conf, ipfs, offlineIPFS)
gwHandler := gateway.NewHandler(conf, ipfs)
mux.Handle("/ipfs/", gwHandler)
mux.Handle("/ipns/", gwHandler)

Expand Down
61 changes: 0 additions & 61 deletions gateway/api.go

This file was deleted.

36 changes: 36 additions & 0 deletions gateway/gateway.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package gateway

import (
"context"
"io"
"net/http"
"sort"

cid "github.com/ipfs/go-cid"
ipld "github.com/ipfs/go-ipld-format"
"github.com/ipfs/go-libipfs/files"
iface "github.com/ipfs/interface-go-ipfs-core"
options "github.com/ipfs/interface-go-ipfs-core/options"
"github.com/ipfs/interface-go-ipfs-core/path"
)

// Config is the configuration that will be applied when creating a new gateway
Expand All @@ -11,6 +20,33 @@ type Config struct {
Headers map[string][]string
}

// NodeAPI defines the minimal set of API services required for a read-only
// gateway handler. These are, for the most part, subsets of the core interface.

type NodeAPI interface {
// GetUnixFs returns a read-only handle to a file tree referenced by a path.
GetUnixFs(context.Context, path.Path) (files.Node, error)

// LsUnixFs returns the list of links in a directory.
LsUnixFs(context.Context, path.Path, ...options.UnixfsLsOption) (<-chan iface.DirEntry, error)

// GetBlock attempts to resolve the path and return a reader for data in the block.
GetBlock(context.Context, path.Path) (io.Reader, error)

// StatBlockOffline returns information on a block without making any network
// connection. In case the block does not exist locally, an error should be returned.
StatBlockOffline(context.Context, path.Path) (iface.BlockStat, error)

// GetNode returns the IPLD node for the path.
GetNode(context.Context, cid.Cid) (ipld.Node, error)

// GetRouting retrieves the best value for a given key from the routing system.
GetRouting(context.Context, string) ([]byte, error)

// ResolvePath resolves the path using UnixFS resolver
ResolvePath(context.Context, path.Path) (path.Resolved, error)
}

// A helper function to clean up a set of headers:
// 1. Canonicalizes.
// 2. Deduplicates.
Expand Down
20 changes: 9 additions & 11 deletions gateway/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,8 @@ type redirectTemplateData struct {
// handler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
type handler struct {
config Config
api ReaderAPI
offlineAPI OfflineAPI
config Config
api NodeAPI

// generic metrics
firstContentBlockGetMetric *prometheus.HistogramVec
Expand Down Expand Up @@ -214,15 +213,14 @@ func newHistogramMetric(name string, help string) *prometheus.HistogramVec {

// NewHandler returns an http.Handler that can act as a gateway to IPFS content
// offlineApi is a version of the API that should not make network requests for missing data
func NewHandler(c Config, api ReaderAPI, offlineAPI OfflineAPI) http.Handler {
return newHandler(c, api, offlineAPI)
func NewHandler(c Config, api NodeAPI) http.Handler {
return newHandler(c, api)
}

func newHandler(c Config, api ReaderAPI, offlineAPI OfflineAPI) *handler {
func newHandler(c Config, api NodeAPI) *handler {
i := &handler{
config: c,
api: api,
offlineAPI: offlineAPI,
config: c,
api: api,
// Improved Metrics
// ----------------------------
// Time till the first content block (bar in /ipfs/cid/foo/bar)
Expand Down Expand Up @@ -748,7 +746,7 @@ func (i *handler) handlePathResolution(w http.ResponseWriter, r *http.Request, r
// https://github.com/ipfs/specs/blob/main/http-gateways/PATH_GATEWAY.md#cache-control-request-header
func (i *handler) handleOnlyIfCached(w http.ResponseWriter, r *http.Request, contentPath ipath.Path, logger *zap.SugaredLogger) (requestHandled bool) {
if r.Header.Get("Cache-Control") == "only-if-cached" {
_, err := i.offlineAPI.Block().Stat(r.Context(), contentPath)
_, err := i.api.StatBlockOffline(r.Context(), contentPath)
if err != nil {
if r.Method == http.MethodHead {
w.WriteHeader(http.StatusPreconditionFailed)
Expand Down Expand Up @@ -866,7 +864,7 @@ func handleSuperfluousNamespace(w http.ResponseWriter, r *http.Request, contentP
func (i *handler) handleGettingFirstBlock(r *http.Request, begin time.Time, contentPath ipath.Path, resolvedPath ipath.Resolved) *requestError {
// Update the global metric of the time it takes to read the final root block of the requested resource
// NOTE: for legacy reasons this happens before we go into content-type specific code paths
_, err := i.api.Block().Get(r.Context(), resolvedPath)
_, err := i.api.GetBlock(r.Context(), resolvedPath)
if err != nil {
return newRequestError("ipfs block get "+resolvedPath.Cid().String(), err, http.StatusInternalServerError)
}
Expand Down
2 changes: 1 addition & 1 deletion gateway/handler_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (i *handler) serveRawBlock(ctx context.Context, w http.ResponseWriter, r *h
ctx, span := spanTrace(ctx, "ServeRawBlock", trace.WithAttributes(attribute.String("path", resolvedPath.String())))
defer span.End()
blockCid := resolvedPath.Cid()
blockReader, err := i.api.Block().Get(ctx, resolvedPath)
blockReader, err := i.api.GetBlock(ctx, resolvedPath)
if err != nil {
webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
return
Expand Down
6 changes: 3 additions & 3 deletions gateway/handler_car.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (i *handler) serveCAR(ctx context.Context, w http.ResponseWriter, r *http.R
w.Header().Set("X-Content-Type-Options", "nosniff") // no funny business in the browsers :^)

// Same go-car settings as dag.export command
store := dagStore{dag: i.api.Dag(), ctx: ctx}
store := dagStore{api: i.api, ctx: ctx}

// TODO: support selectors passed as request param: https://github.com/ipfs/kubo/issues/8769
dag := gocar.Dag{Root: rootCid, Selector: selectorparse.CommonSelector_ExploreAllRecursively}
Expand All @@ -88,10 +88,10 @@ func (i *handler) serveCAR(ctx context.Context, w http.ResponseWriter, r *http.R

// FIXME(@Jorropo): https://github.com/ipld/go-car/issues/315
type dagStore struct {
dag ReaderDagAPI
api NodeAPI
ctx context.Context
}

func (ds dagStore) Get(_ context.Context, c cid.Cid) (blocks.Block, error) {
return ds.dag.Get(ds.ctx, c)
return ds.api.GetNode(ds.ctx, c)
}
4 changes: 2 additions & 2 deletions gateway/handler_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func (i *handler) serveCodecHTML(ctx context.Context, w http.ResponseWriter, r *
// serveCodecRaw returns the raw block without any conversion
func (i *handler) serveCodecRaw(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, name string, modtime time.Time) {
blockCid := resolvedPath.Cid()
blockReader, err := i.api.Block().Get(ctx, resolvedPath)
blockReader, err := i.api.GetBlock(ctx, resolvedPath)
if err != nil {
webError(w, "ipfs block get "+blockCid.String(), err, http.StatusInternalServerError)
return
Expand All @@ -182,7 +182,7 @@ func (i *handler) serveCodecRaw(ctx context.Context, w http.ResponseWriter, r *h

// serveCodecConverted returns payload converted to codec specified in toCodec
func (i *handler) serveCodecConverted(ctx context.Context, w http.ResponseWriter, r *http.Request, resolvedPath ipath.Resolved, contentPath ipath.Path, toCodec mc.Code, modtime time.Time) {
obj, err := i.api.Dag().Get(ctx, resolvedPath.Cid())
obj, err := i.api.GetNode(ctx, resolvedPath.Cid())
if err != nil {
webError(w, "ipfs dag get "+html.EscapeString(resolvedPath.String()), err, http.StatusInternalServerError)
return
Expand Down
2 changes: 1 addition & 1 deletion gateway/handler_ipns_record.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (i *handler) serveIpnsRecord(ctx context.Context, w http.ResponseWriter, r
return
}

rawRecord, err := i.api.Routing().Get(ctx, key)
rawRecord, err := i.api.GetRouting(ctx, key)
if err != nil {
webError(w, err.Error(), err, http.StatusInternalServerError)
return
Expand Down
2 changes: 1 addition & 1 deletion gateway/handler_tar.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (i *handler) serveTAR(ctx context.Context, w http.ResponseWriter, r *http.R
defer cancel()

// Get Unixfs file
file, err := i.api.UnixFs().Get(ctx, resolvedPath)
file, err := i.api.GetUnixFs(ctx, resolvedPath)
if err != nil {
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
return
Expand Down
2 changes: 1 addition & 1 deletion gateway/handler_unixfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func (i *handler) serveUnixFS(ctx context.Context, w http.ResponseWriter, r *htt
defer span.End()

// Handling UnixFS
dr, err := i.api.UnixFs().Get(ctx, resolvedPath)
dr, err := i.api.GetUnixFs(ctx, resolvedPath)
if err != nil {
webError(w, "ipfs cat "+html.EscapeString(contentPath.String()), err, http.StatusBadRequest)
return
Expand Down
6 changes: 3 additions & 3 deletions gateway/handler_unixfs__redirects.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (i *handler) handleRedirectsFileRules(w http.ResponseWriter, r *http.Reques

func (i *handler) getRedirectRules(r *http.Request, redirectsFilePath ipath.Resolved) ([]redirects.Rule, error) {
// Convert the path into a file node
node, err := i.api.UnixFs().Get(r.Context(), redirectsFilePath)
node, err := i.api.GetUnixFs(r.Context(), redirectsFilePath)
if err != nil {
return nil, fmt.Errorf("could not get _redirects: %w", err)
}
Expand Down Expand Up @@ -170,7 +170,7 @@ func (i *handler) serve4xx(w http.ResponseWriter, r *http.Request, content4xxPat
return err
}

node, err := i.api.UnixFs().Get(r.Context(), resolved4xxPath)
node, err := i.api.GetUnixFs(r.Context(), resolved4xxPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -220,7 +220,7 @@ func (i *handler) serveLegacy404IfPresent(w http.ResponseWriter, r *http.Request
return false
}

dr, err := i.api.UnixFs().Get(r.Context(), resolved404Path)
dr, err := i.api.GetUnixFs(r.Context(), resolved404Path)
if err != nil {
return false
}
Expand Down
4 changes: 2 additions & 2 deletions gateway/handler_unixfs_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (i *handler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *

// Check if directory has index.html, if so, serveFile
idxPath := ipath.Join(contentPath, "index.html")
idx, err := i.api.UnixFs().Get(ctx, idxPath)
idx, err := i.api.GetUnixFs(ctx, idxPath)
switch err.(type) {
case nil:
f, ok := idx.(files.File)
Expand Down Expand Up @@ -107,7 +107,7 @@ func (i *handler) serveDirectory(ctx context.Context, w http.ResponseWriter, r *
// Optimization: use Unixfs.Ls without resolving children, but using the
// cumulative DAG size as the file size. This allows for a fast listing
// while keeping a good enough Size field.
results, err := i.api.UnixFs().Ls(ctx,
results, err := i.api.LsUnixFs(ctx,
resolvedPath,
options.Unixfs.ResolveChildren(false),
options.Unixfs.UseCumulativeSize(true),
Expand Down

0 comments on commit b4a01af

Please sign in to comment.