mirror of
https://github.com/ipfs/kubo.git
synced 2025-08-06 11:31:54 +08:00
refactor: switch gateway code to new API from go-libipfs (#9681)
Co-authored-by: Marcin Rataj <lidel@lidel.org> Co-authored-by: Henrique Dias <hacdias@gmail.com>
This commit is contained in:
@ -2,24 +2,26 @@ package corehttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/ipfs/boxo/blockservice"
|
||||
iface "github.com/ipfs/boxo/coreiface"
|
||||
options "github.com/ipfs/boxo/coreiface/options"
|
||||
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
|
||||
"github.com/ipfs/boxo/coreiface/path"
|
||||
"github.com/ipfs/boxo/exchange/offline"
|
||||
"github.com/ipfs/boxo/files"
|
||||
"github.com/ipfs/boxo/gateway"
|
||||
"github.com/ipfs/boxo/namesys"
|
||||
"github.com/ipfs/go-block-format"
|
||||
offlineroute "github.com/ipfs/boxo/routing/offline"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
version "github.com/ipfs/kubo"
|
||||
config "github.com/ipfs/kubo/config"
|
||||
core "github.com/ipfs/kubo/core"
|
||||
coreapi "github.com/ipfs/kubo/core/coreapi"
|
||||
"github.com/ipfs/kubo/core/node"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
id "github.com/libp2p/go-libp2p/p2p/protocol/identify"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
)
|
||||
@ -42,7 +44,7 @@ func GatewayOption(paths ...string) ServeOption {
|
||||
Headers: headers,
|
||||
}
|
||||
|
||||
gwAPI, err := newGatewayAPI(n)
|
||||
gwAPI, err := newGatewayBackend(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -70,7 +72,7 @@ func HostnameOption() ServeOption {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gwAPI, err := newGatewayAPI(n)
|
||||
gwAPI, err := newGatewayBackend(n)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -93,83 +95,120 @@ func VersionOption() ServeOption {
|
||||
}
|
||||
}
|
||||
|
||||
type gatewayAPI struct {
|
||||
ns namesys.NameSystem
|
||||
api iface.CoreAPI
|
||||
offlineAPI iface.CoreAPI
|
||||
}
|
||||
|
||||
func newGatewayAPI(n *core.IpfsNode) (*gatewayAPI, error) {
|
||||
func newGatewayBackend(n *core.IpfsNode) (gateway.IPFSBackend, error) {
|
||||
cfg, err := n.Repo.Config()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
api, err := coreapi.NewCoreAPI(n, options.Api.FetchBlocks(!cfg.Gateway.NoFetch))
|
||||
bserv := n.Blocks
|
||||
var vsRouting routing.ValueStore = n.Routing
|
||||
nsys := n.Namesys
|
||||
if cfg.Gateway.NoFetch {
|
||||
bserv = blockservice.New(bserv.Blockstore(), offline.Exchange(bserv.Blockstore()))
|
||||
|
||||
cs := cfg.Ipns.ResolveCacheSize
|
||||
if cs == 0 {
|
||||
cs = node.DefaultIpnsCacheSize
|
||||
}
|
||||
if cs < 0 {
|
||||
return nil, fmt.Errorf("cannot specify negative resolve cache size")
|
||||
}
|
||||
|
||||
vsRouting = offlineroute.NewOfflineRouter(n.Repo.Datastore(), n.RecordValidator)
|
||||
nsys, err = namesys.NewNameSystem(vsRouting,
|
||||
namesys.WithDatastore(n.Repo.Datastore()),
|
||||
namesys.WithDNSResolver(n.DNSResolver),
|
||||
namesys.WithCache(cs))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error constructing namesys: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
gw, err := gateway.NewBlocksGateway(bserv, gateway.WithValueStore(vsRouting), gateway.WithNameSystem(nsys))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offlineAPI, err := api.WithOptions(options.Api.Offline(true))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return &offlineGatewayErrWrapper{gwimpl: gw}, nil
|
||||
}
|
||||
|
||||
type offlineGatewayErrWrapper struct {
|
||||
gwimpl gateway.IPFSBackend
|
||||
}
|
||||
|
||||
func offlineErrWrap(err error) error {
|
||||
if errors.Is(err, iface.ErrOffline) {
|
||||
return fmt.Errorf("%s : %w", err.Error(), gateway.ErrServiceUnavailable)
|
||||
}
|
||||
|
||||
return &gatewayAPI{
|
||||
ns: n.Namesys,
|
||||
api: api,
|
||||
offlineAPI: offlineAPI,
|
||||
}, nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) GetUnixFsNode(ctx context.Context, pth path.Resolved) (files.Node, error) {
|
||||
return gw.api.Unixfs().Get(ctx, pth)
|
||||
func (o *offlineGatewayErrWrapper) Get(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, *gateway.GetResponse, error) {
|
||||
md, n, err := o.gwimpl.Get(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, n, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) LsUnixFsDir(ctx context.Context, pth path.Resolved) (<-chan iface.DirEntry, error) {
|
||||
// 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.
|
||||
return gw.api.Unixfs().Ls(ctx, pth,
|
||||
options.Unixfs.ResolveChildren(false),
|
||||
options.Unixfs.UseCumulativeSize(true),
|
||||
)
|
||||
func (o *offlineGatewayErrWrapper) GetRange(ctx context.Context, path gateway.ImmutablePath, ranges ...gateway.GetRange) (gateway.ContentPathMetadata, files.File, error) {
|
||||
md, n, err := o.gwimpl.GetRange(ctx, path, ranges...)
|
||||
err = offlineErrWrap(err)
|
||||
return md, n, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) GetBlock(ctx context.Context, cid cid.Cid) (blocks.Block, error) {
|
||||
r, err := gw.api.Block().Get(ctx, path.IpfsPath(cid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return blocks.NewBlockWithCid(data, cid)
|
||||
func (o *offlineGatewayErrWrapper) GetAll(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) {
|
||||
md, n, err := o.gwimpl.GetAll(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, n, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
|
||||
return gw.api.Routing().Get(ctx, "/ipns/"+c.String())
|
||||
func (o *offlineGatewayErrWrapper) GetBlock(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.File, error) {
|
||||
md, n, err := o.gwimpl.GetBlock(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, n, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) GetDNSLinkRecord(ctx context.Context, hostname string) (path.Path, error) {
|
||||
p, err := gw.ns.Resolve(ctx, "/ipns/"+hostname, nsopts.Depth(1))
|
||||
if err == namesys.ErrResolveRecursion {
|
||||
err = nil
|
||||
}
|
||||
return path.New(p.String()), err
|
||||
func (o *offlineGatewayErrWrapper) Head(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, files.Node, error) {
|
||||
md, n, err := o.gwimpl.Head(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, n, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) IsCached(ctx context.Context, pth path.Path) bool {
|
||||
_, err := gw.offlineAPI.Block().Stat(ctx, pth)
|
||||
return err == nil
|
||||
func (o *offlineGatewayErrWrapper) ResolvePath(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, error) {
|
||||
md, err := o.gwimpl.ResolvePath(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, err
|
||||
}
|
||||
|
||||
func (gw *gatewayAPI) ResolvePath(ctx context.Context, pth path.Path) (path.Resolved, error) {
|
||||
return gw.api.ResolvePath(ctx, pth)
|
||||
func (o *offlineGatewayErrWrapper) GetCAR(ctx context.Context, path gateway.ImmutablePath) (gateway.ContentPathMetadata, io.ReadCloser, <-chan error, error) {
|
||||
md, data, errCh, err := o.gwimpl.GetCAR(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return md, data, errCh, err
|
||||
}
|
||||
|
||||
func (o *offlineGatewayErrWrapper) IsCached(ctx context.Context, path path.Path) bool {
|
||||
return o.gwimpl.IsCached(ctx, path)
|
||||
}
|
||||
|
||||
func (o *offlineGatewayErrWrapper) GetIPNSRecord(ctx context.Context, c cid.Cid) ([]byte, error) {
|
||||
rec, err := o.gwimpl.GetIPNSRecord(ctx, c)
|
||||
err = offlineErrWrap(err)
|
||||
return rec, err
|
||||
}
|
||||
|
||||
func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (gateway.ImmutablePath, error) {
|
||||
imPath, err := o.gwimpl.ResolveMutable(ctx, path)
|
||||
err = offlineErrWrap(err)
|
||||
return imPath, err
|
||||
}
|
||||
|
||||
func (o *offlineGatewayErrWrapper) GetDNSLinkRecord(ctx context.Context, s string) (path.Path, error) {
|
||||
p, err := o.gwimpl.GetDNSLinkRecord(ctx, s)
|
||||
err = offlineErrWrap(err)
|
||||
return p, err
|
||||
}
|
||||
|
||||
var _ gateway.IPFSBackend = (*offlineGatewayErrWrapper)(nil)
|
||||
|
||||
var defaultPaths = []string{"/ipfs/", "/ipns/", "/api/", "/p2p/"}
|
||||
|
||||
var subdomainGatewaySpec = &gateway.Specification{
|
||||
|
Reference in New Issue
Block a user