Skip to content

Commit

Permalink
refactor: namesys cleanup, gateway /ipns/ ttl (#10115)
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias authored Oct 18, 2023
1 parent 170686b commit 4695fd9
Show file tree
Hide file tree
Showing 20 changed files with 167 additions and 75 deletions.
14 changes: 7 additions & 7 deletions client/rpc/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import (

iface "github.com/ipfs/boxo/coreiface"
caopts "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/ipns"
"github.com/ipfs/boxo/namesys"
"github.com/ipfs/boxo/path"
)

Expand Down Expand Up @@ -49,9 +49,9 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name
return nil, err
}

ropts := nsopts.ProcessOpts(options.ResolveOpts)
if ropts.Depth != nsopts.DefaultDepthLimit && ropts.Depth != 1 {
return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", nsopts.DefaultDepthLimit)
ropts := namesys.ProcessResolveOptions(options.ResolveOpts)
if ropts.Depth != namesys.DefaultDepthLimit && ropts.Depth != 1 {
return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", namesys.DefaultDepthLimit)
}

req := api.core().Request("name/resolve", name).
Expand Down Expand Up @@ -110,9 +110,9 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
return nil, err
}

ropts := nsopts.ProcessOpts(options.ResolveOpts)
if ropts.Depth != nsopts.DefaultDepthLimit && ropts.Depth != 1 {
return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", nsopts.DefaultDepthLimit)
ropts := namesys.ProcessResolveOptions(options.ResolveOpts)
if ropts.Depth != namesys.DefaultDepthLimit && ropts.Depth != 1 {
return nil, fmt.Errorf("Name.Resolve: depth other than 1 or %d not supported", namesys.DefaultDepthLimit)
}

req := api.core().Request("name/resolve", name).
Expand Down
2 changes: 1 addition & 1 deletion core/commands/dht_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func TestKeyTranslation(t *testing.T) {
pid := test.RandPeerIDFatal(t)
pkname := namesys.PkKeyForID(pid)
pkname := namesys.PkRoutingKey(pid)
ipnsname := ipns.NameFromPeer(pid).RoutingKey()

pkk, err := escapeDhtKey("/pk/" + pid.String())
Expand Down
15 changes: 10 additions & 5 deletions core/commands/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"fmt"
"io"

nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
namesys "github.com/ipfs/boxo/namesys"
"github.com/ipfs/boxo/path"
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
ncmd "github.com/ipfs/kubo/core/commands/name"

Expand Down Expand Up @@ -47,16 +47,21 @@ It will work across multiple DNSLinks and IPNS keys.
name := req.Arguments[0]
resolver := namesys.NewDNSResolver(node.DNSResolver.LookupTXT)

var routing []nsopts.ResolveOpt
var routing []namesys.ResolveOption
if !recursive {
routing = append(routing, nsopts.Depth(1))
routing = append(routing, namesys.ResolveWithDepth(1))
}

output, err := resolver.Resolve(req.Context, name, routing...)
p, err := path.NewPath(name)
if err != nil {
return err
}

val, err := resolver.Resolve(req.Context, p, routing...)
if err != nil && (recursive || err != namesys.ErrResolveRecursion) {
return err
}
return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: output.String()})
return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: val.Path.String()})
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error {
Expand Down
16 changes: 7 additions & 9 deletions core/commands/name/ipns.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ import (
"strings"
"time"

namesys "github.com/ipfs/boxo/namesys"
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"

options "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/namesys"
"github.com/ipfs/boxo/path"
cmds "github.com/ipfs/go-ipfs-cmds"
logging "github.com/ipfs/go-log"
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
)

var log = logging.Logger("core/commands/ipns")
Expand Down Expand Up @@ -75,8 +73,8 @@ Resolve the value of a dnslink:
Options: []cmds.Option{
cmds.BoolOption(recursiveOptionName, "r", "Resolve until the result is not an IPNS name.").WithDefault(true),
cmds.BoolOption(nocacheOptionName, "n", "Do not use cached entries."),
cmds.UintOption(dhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution."),
cmds.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
cmds.UintOption(dhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution.").WithDefault(uint(namesys.DefaultResolverDhtRecordCount)),
cmds.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout.").WithDefault(namesys.DefaultResolverDhtTimeout.String()),
cmds.BoolOption(streamOptionName, "s", "Stream entries as they are found."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
Expand Down Expand Up @@ -108,10 +106,10 @@ Resolve the value of a dnslink:
}

if !recursive {
opts = append(opts, options.Name.ResolveOption(nsopts.Depth(1)))
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDepth(1)))
}
if rcok {
opts = append(opts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtRecordCount(rc)))
}
if dhttok {
d, err := time.ParseDuration(dhtt)
Expand All @@ -121,7 +119,7 @@ Resolve the value of a dnslink:
if d < 0 {
return errors.New("DHT timeout value must be >= 0")
}
opts = append(opts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtTimeout(d)))
}

if !strings.HasPrefix(name, "/ipns/") {
Expand Down
16 changes: 7 additions & 9 deletions core/commands/name/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

iface "github.com/ipfs/boxo/coreiface"
options "github.com/ipfs/boxo/coreiface/options"
ipns "github.com/ipfs/boxo/ipns"
cmds "github.com/ipfs/go-ipfs-cmds"
ke "github.com/ipfs/kubo/core/commands/keyencode"
)
Expand Down Expand Up @@ -59,7 +60,7 @@ Publish an <ipfs-path> with another name, added by an 'ipfs key' command:
> ipfs name publish --key=mykey /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
Published to QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
'ipfs key list -l'):
> ipfs name publish --key=QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
Expand All @@ -72,16 +73,13 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
cmds.StringArg(ipfsPathOptionName, true, false, "ipfs path of the object to be published.").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true),
cmds.StringOption(lifeTimeOptionName, "t",
`Time duration that the record will be valid for. <<default>>
This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are
"ns", "us" (or "µs"), "ms", "s", "m", "h".`).WithDefault("24h"),
cmds.BoolOption(allowOfflineOptionName, "When offline, save the IPNS record to the the local datastore without broadcasting to the network instead of simply failing."),
cmds.StringOption(ttlOptionName, "Time duration this record should be cached for. Uses the same syntax as the lifetime option. (caution: experimental)"),
cmds.StringOption(keyOptionName, "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'.").WithDefault("self"),
cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true),
cmds.StringOption(lifeTimeOptionName, "t", `Time duration the signed record will be valid for. Accepts durations such as "300s", "1.5h" or "7d2h45m"`).WithDefault(ipns.DefaultRecordLifetime.String()),
cmds.StringOption(ttlOptionName, "Time duration hint, akin to --lifetime, indicating how long to cache this record before checking for updates.").WithDefault(ipns.DefaultRecordTTL.String()),
cmds.BoolOption(quieterOptionName, "Q", "Write only final IPNS Name encoded as CIDv1 (for use in /ipns content paths)."),
cmds.BoolOption(v1compatOptionName, "Produce a backward-compatible IPNS Record by including fields for both V1 and V2 signatures.").WithDefault(true),
cmds.BoolOption(allowOfflineOptionName, "When --offline, save the IPNS record to the the local datastore without broadcasting to the network (instead of failing)."),
ke.OptionIPNSBase,
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
Expand Down
9 changes: 4 additions & 5 deletions core/commands/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import (
"time"

ns "github.com/ipfs/boxo/namesys"
"github.com/ipfs/boxo/path"
cidenc "github.com/ipfs/go-cidutil/cidenc"
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
"github.com/ipfs/kubo/core/commands/cmdutils"
ncmd "github.com/ipfs/kubo/core/commands/name"

options "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/path"
cmds "github.com/ipfs/go-ipfs-cmds"
)

Expand Down Expand Up @@ -87,11 +86,11 @@ Resolve the value of an IPFS DAG path:
rc, rcok := req.Options[resolveDhtRecordCountOptionName].(uint)
dhtt, dhttok := req.Options[resolveDhtTimeoutOptionName].(string)
ropts := []options.NameResolveOption{
options.Name.ResolveOption(nsopts.Depth(1)),
options.Name.ResolveOption(ns.ResolveWithDepth(1)),
}

if rcok {
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtRecordCount(rc)))
}
if dhttok {
d, err := time.ParseDuration(dhtt)
Expand All @@ -101,7 +100,7 @@ Resolve the value of an IPFS DAG path:
if d < 0 {
return errors.New("DHT timeout value must be >= 0")
}
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtTimeout(d)))
}
p, err := api.Name().Resolve(req.Context, name, ropts...)
// ErrResolveRecursion is fine
Expand Down
16 changes: 10 additions & 6 deletions core/coreapi/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (

coreiface "github.com/ipfs/boxo/coreiface"
caopts "github.com/ipfs/boxo/coreiface/options"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/path"
ci "github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
Expand Down Expand Up @@ -57,13 +56,13 @@ func (api *NameAPI) Publish(ctx context.Context, p path.Path, opts ...caopts.Nam

eol := time.Now().Add(options.ValidTime)

publishOptions := []nsopts.PublishOption{
nsopts.PublishWithEOL(eol),
nsopts.PublishCompatibleWithV1(options.CompatibleWithV1),
publishOptions := []namesys.PublishOption{
namesys.PublishWithEOL(eol),
namesys.PublishWithIPNSOption(ipns.WithV1Compatibility(options.CompatibleWithV1)),
}

if options.TTL != nil {
publishOptions = append(publishOptions, nsopts.PublishWithTTL(*options.TTL))
publishOptions = append(publishOptions, namesys.PublishWithTTL(*options.TTL))
}

err = api.namesys.Publish(ctx, k, p, publishOptions...)
Expand Down Expand Up @@ -109,10 +108,15 @@ func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.Name
name = "/ipns/" + name
}

p, err := path.NewPath(name)
if err != nil {
return nil, err
}

out := make(chan coreiface.IpnsResult)
go func() {
defer close(out)
for res := range resolver.ResolveAsync(ctx, name, options.ResolveOpts...) {
for res := range resolver.ResolveAsync(ctx, p, options.ResolveOpts...) {
select {
case out <- coreiface.IpnsResult{Path: res.Path, Err: res.Err}:
case <-ctx.Done():
Expand Down
8 changes: 5 additions & 3 deletions core/coreapi/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package coreapi

import (
"context"
"errors"
"fmt"

"github.com/ipfs/boxo/namesys/resolve"
"github.com/ipfs/boxo/namesys"
"github.com/ipfs/kubo/tracing"

"go.opentelemetry.io/otel/attribute"
Expand Down Expand Up @@ -40,12 +41,13 @@ func (api *CoreAPI) ResolvePath(ctx context.Context, p path.Path) (path.Immutabl
ctx, span := tracing.Span(ctx, "CoreAPI", "ResolvePath", trace.WithAttributes(attribute.String("path", p.String())))
defer span.End()

p, err := resolve.ResolveIPNS(ctx, api.namesys, p)
if err == resolve.ErrNoNamesys {
res, err := namesys.Resolve(ctx, api.namesys, p)
if errors.Is(err, namesys.ErrNoNamesys) {
return path.ImmutablePath{}, nil, coreiface.ErrOffline
} else if err != nil {
return path.ImmutablePath{}, nil, err
}
p = res.Path

var resolver ipfspathresolver.Resolver
switch p.Namespace() {
Expand Down
7 changes: 4 additions & 3 deletions core/corehttp/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net"
"net/http"
"time"

"github.com/ipfs/boxo/blockservice"
iface "github.com/ipfs/boxo/coreiface"
Expand Down Expand Up @@ -195,10 +196,10 @@ func (o *offlineGatewayErrWrapper) GetIPNSRecord(ctx context.Context, c cid.Cid)
return rec, err
}

func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (path.ImmutablePath, error) {
imPath, err := o.gwimpl.ResolveMutable(ctx, path)
func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (path.ImmutablePath, time.Duration, time.Time, error) {
imPath, ttl, lastMod, err := o.gwimpl.ResolveMutable(ctx, path)
err = offlineErrWrap(err)
return imPath, err
return imPath, ttl, lastMod, err
}

func (o *offlineGatewayErrWrapper) GetDNSLinkRecord(ctx context.Context, s string) (path.Path, error) {
Expand Down
33 changes: 19 additions & 14 deletions core/corehttp/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/stretchr/testify/assert"

iface "github.com/ipfs/boxo/coreiface"
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
"github.com/ipfs/boxo/path"
"github.com/ipfs/go-datastore"
syncds "github.com/ipfs/go-datastore/sync"
Expand All @@ -27,41 +26,47 @@ import (

type mockNamesys map[string]path.Path

func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) {
cfg := nsopts.DefaultResolveOpts()
func (m mockNamesys) Resolve(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) (namesys.Result, error) {
cfg := namesys.DefaultResolveOptions()
for _, o := range opts {
o(&cfg)
}
depth := cfg.Depth
if depth == nsopts.UnlimitedDepth {
if depth == namesys.UnlimitedDepth {
// max uint
depth = ^uint(0)
}
var (
value path.Path
)
name := path.SegmentsToString(p.Segments()[:2]...)
for strings.HasPrefix(name, "/ipns/") {
if depth == 0 {
return value, namesys.ErrResolveRecursion
return namesys.Result{Path: value}, namesys.ErrResolveRecursion
}
depth--

var ok bool
value, ok = m[name]
v, ok := m[name]
if !ok {
return nil, namesys.ErrResolveFailed
return namesys.Result{}, namesys.ErrResolveFailed
}
value = v
name = value.String()
}
return value, nil

value, err := path.Join(value, p.Segments()[2:]...)
return namesys.Result{Path: value}, err
}

func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsopts.ResolveOpt) <-chan namesys.Result {
out := make(chan namesys.Result, 1)
v, err := m.Resolve(ctx, name, opts...)
out <- namesys.Result{Path: v, Err: err}
func (m mockNamesys) ResolveAsync(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) <-chan namesys.AsyncResult {
out := make(chan namesys.AsyncResult, 1)
res, err := m.Resolve(ctx, p, opts...)
out <- namesys.AsyncResult{Path: res.Path, TTL: res.TTL, LastMod: res.LastMod, Err: err}
close(out)
return out
}

func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...nsopts.PublishOption) error {
func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Path, opts ...namesys.PublishOption) error {
return errors.New("not implemented for mockNamesys")
}

Expand Down
Loading

0 comments on commit 4695fd9

Please sign in to comment.