Skip to content

Commit 4695fd9

Browse files
authored
refactor: namesys cleanup, gateway /ipns/ ttl (#10115)
1 parent 170686b commit 4695fd9

File tree

20 files changed

+167
-75
lines changed

20 files changed

+167
-75
lines changed

client/rpc/name.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88

99
iface "github.com/ipfs/boxo/coreiface"
1010
caopts "github.com/ipfs/boxo/coreiface/options"
11-
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
1211
"github.com/ipfs/boxo/ipns"
12+
"github.com/ipfs/boxo/namesys"
1313
"github.com/ipfs/boxo/path"
1414
)
1515

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

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

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

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

118118
req := api.core().Request("name/resolve", name).

core/commands/dht_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
func TestKeyTranslation(t *testing.T) {
1313
pid := test.RandPeerIDFatal(t)
14-
pkname := namesys.PkKeyForID(pid)
14+
pkname := namesys.PkRoutingKey(pid)
1515
ipnsname := ipns.NameFromPeer(pid).RoutingKey()
1616

1717
pkk, err := escapeDhtKey("/pk/" + pid.String())

core/commands/dns.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import (
44
"fmt"
55
"io"
66

7-
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
87
namesys "github.com/ipfs/boxo/namesys"
8+
"github.com/ipfs/boxo/path"
99
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
1010
ncmd "github.com/ipfs/kubo/core/commands/name"
1111

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

50-
var routing []nsopts.ResolveOpt
50+
var routing []namesys.ResolveOption
5151
if !recursive {
52-
routing = append(routing, nsopts.Depth(1))
52+
routing = append(routing, namesys.ResolveWithDepth(1))
5353
}
5454

55-
output, err := resolver.Resolve(req.Context, name, routing...)
55+
p, err := path.NewPath(name)
56+
if err != nil {
57+
return err
58+
}
59+
60+
val, err := resolver.Resolve(req.Context, p, routing...)
5661
if err != nil && (recursive || err != namesys.ErrResolveRecursion) {
5762
return err
5863
}
59-
return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: output.String()})
64+
return cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: val.Path.String()})
6065
},
6166
Encoders: cmds.EncoderMap{
6267
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ncmd.ResolvedPath) error {

core/commands/name/ipns.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,12 @@ import (
77
"strings"
88
"time"
99

10-
namesys "github.com/ipfs/boxo/namesys"
11-
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
12-
1310
options "github.com/ipfs/boxo/coreiface/options"
14-
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
11+
"github.com/ipfs/boxo/namesys"
1512
"github.com/ipfs/boxo/path"
1613
cmds "github.com/ipfs/go-ipfs-cmds"
1714
logging "github.com/ipfs/go-log"
15+
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
1816
)
1917

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

110108
if !recursive {
111-
opts = append(opts, options.Name.ResolveOption(nsopts.Depth(1)))
109+
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDepth(1)))
112110
}
113111
if rcok {
114-
opts = append(opts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
112+
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtRecordCount(rc)))
115113
}
116114
if dhttok {
117115
d, err := time.ParseDuration(dhtt)
@@ -121,7 +119,7 @@ Resolve the value of a dnslink:
121119
if d < 0 {
122120
return errors.New("DHT timeout value must be >= 0")
123121
}
124-
opts = append(opts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
122+
opts = append(opts, options.Name.ResolveOption(namesys.ResolveWithDhtTimeout(d)))
125123
}
126124

127125
if !strings.HasPrefix(name, "/ipns/") {

core/commands/name/publish.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
iface "github.com/ipfs/boxo/coreiface"
1313
options "github.com/ipfs/boxo/coreiface/options"
14+
ipns "github.com/ipfs/boxo/ipns"
1415
cmds "github.com/ipfs/go-ipfs-cmds"
1516
ke "github.com/ipfs/kubo/core/commands/keyencode"
1617
)
@@ -59,7 +60,7 @@ Publish an <ipfs-path> with another name, added by an 'ipfs key' command:
5960
> ipfs name publish --key=mykey /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
6061
Published to QmSrPmbaUKA3ZodhzPWZnpFgcPMFWF4QsxXbkWfEptTBJd: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
6162
62-
Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
63+
Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
6364
'ipfs key list -l'):
6465
6566
> ipfs name publish --key=QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
@@ -72,16 +73,13 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
7273
cmds.StringArg(ipfsPathOptionName, true, false, "ipfs path of the object to be published.").EnableStdin(),
7374
},
7475
Options: []cmds.Option{
75-
cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true),
76-
cmds.StringOption(lifeTimeOptionName, "t",
77-
`Time duration that the record will be valid for. <<default>>
78-
This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are
79-
"ns", "us" (or "µs"), "ms", "s", "m", "h".`).WithDefault("24h"),
80-
cmds.BoolOption(allowOfflineOptionName, "When offline, save the IPNS record to the the local datastore without broadcasting to the network instead of simply failing."),
81-
cmds.StringOption(ttlOptionName, "Time duration this record should be cached for. Uses the same syntax as the lifetime option. (caution: experimental)"),
8276
cmds.StringOption(keyOptionName, "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'.").WithDefault("self"),
83-
cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."),
77+
cmds.BoolOption(resolveOptionName, "Check if the given path can be resolved before publishing.").WithDefault(true),
78+
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()),
79+
cmds.StringOption(ttlOptionName, "Time duration hint, akin to --lifetime, indicating how long to cache this record before checking for updates.").WithDefault(ipns.DefaultRecordTTL.String()),
80+
cmds.BoolOption(quieterOptionName, "Q", "Write only final IPNS Name encoded as CIDv1 (for use in /ipns content paths)."),
8481
cmds.BoolOption(v1compatOptionName, "Produce a backward-compatible IPNS Record by including fields for both V1 and V2 signatures.").WithDefault(true),
82+
cmds.BoolOption(allowOfflineOptionName, "When --offline, save the IPNS record to the the local datastore without broadcasting to the network (instead of failing)."),
8583
ke.OptionIPNSBase,
8684
},
8785
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {

core/commands/resolve.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ import (
88
"time"
99

1010
ns "github.com/ipfs/boxo/namesys"
11-
"github.com/ipfs/boxo/path"
1211
cidenc "github.com/ipfs/go-cidutil/cidenc"
1312
cmdenv "github.com/ipfs/kubo/core/commands/cmdenv"
1413
"github.com/ipfs/kubo/core/commands/cmdutils"
1514
ncmd "github.com/ipfs/kubo/core/commands/name"
1615

1716
options "github.com/ipfs/boxo/coreiface/options"
18-
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
17+
"github.com/ipfs/boxo/path"
1918
cmds "github.com/ipfs/go-ipfs-cmds"
2019
)
2120

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

9392
if rcok {
94-
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtRecordCount(rc)))
93+
ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtRecordCount(rc)))
9594
}
9695
if dhttok {
9796
d, err := time.ParseDuration(dhtt)
@@ -101,7 +100,7 @@ Resolve the value of an IPFS DAG path:
101100
if d < 0 {
102101
return errors.New("DHT timeout value must be >= 0")
103102
}
104-
ropts = append(ropts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
103+
ropts = append(ropts, options.Name.ResolveOption(ns.ResolveWithDhtTimeout(d)))
105104
}
106105
p, err := api.Name().Resolve(req.Context, name, ropts...)
107106
// ErrResolveRecursion is fine

core/coreapi/name.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515

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

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

60-
publishOptions := []nsopts.PublishOption{
61-
nsopts.PublishWithEOL(eol),
62-
nsopts.PublishCompatibleWithV1(options.CompatibleWithV1),
59+
publishOptions := []namesys.PublishOption{
60+
namesys.PublishWithEOL(eol),
61+
namesys.PublishWithIPNSOption(ipns.WithV1Compatibility(options.CompatibleWithV1)),
6362
}
6463

6564
if options.TTL != nil {
66-
publishOptions = append(publishOptions, nsopts.PublishWithTTL(*options.TTL))
65+
publishOptions = append(publishOptions, namesys.PublishWithTTL(*options.TTL))
6766
}
6867

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

111+
p, err := path.NewPath(name)
112+
if err != nil {
113+
return nil, err
114+
}
115+
112116
out := make(chan coreiface.IpnsResult)
113117
go func() {
114118
defer close(out)
115-
for res := range resolver.ResolveAsync(ctx, name, options.ResolveOpts...) {
119+
for res := range resolver.ResolveAsync(ctx, p, options.ResolveOpts...) {
116120
select {
117121
case out <- coreiface.IpnsResult{Path: res.Path, Err: res.Err}:
118122
case <-ctx.Done():

core/coreapi/path.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package coreapi
22

33
import (
44
"context"
5+
"errors"
56
"fmt"
67

7-
"github.com/ipfs/boxo/namesys/resolve"
8+
"github.com/ipfs/boxo/namesys"
89
"github.com/ipfs/kubo/tracing"
910

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

43-
p, err := resolve.ResolveIPNS(ctx, api.namesys, p)
44-
if err == resolve.ErrNoNamesys {
44+
res, err := namesys.Resolve(ctx, api.namesys, p)
45+
if errors.Is(err, namesys.ErrNoNamesys) {
4546
return path.ImmutablePath{}, nil, coreiface.ErrOffline
4647
} else if err != nil {
4748
return path.ImmutablePath{}, nil, err
4849
}
50+
p = res.Path
4951

5052
var resolver ipfspathresolver.Resolver
5153
switch p.Namespace() {

core/corehttp/gateway.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"net"
99
"net/http"
10+
"time"
1011

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

198-
func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (path.ImmutablePath, error) {
199-
imPath, err := o.gwimpl.ResolveMutable(ctx, path)
199+
func (o *offlineGatewayErrWrapper) ResolveMutable(ctx context.Context, path path.Path) (path.ImmutablePath, time.Duration, time.Time, error) {
200+
imPath, ttl, lastMod, err := o.gwimpl.ResolveMutable(ctx, path)
200201
err = offlineErrWrap(err)
201-
return imPath, err
202+
return imPath, ttl, lastMod, err
202203
}
203204

204205
func (o *offlineGatewayErrWrapper) GetDNSLinkRecord(ctx context.Context, s string) (path.Path, error) {

core/corehttp/gateway_test.go

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import (
1717
"github.com/stretchr/testify/assert"
1818

1919
iface "github.com/ipfs/boxo/coreiface"
20-
nsopts "github.com/ipfs/boxo/coreiface/options/namesys"
2120
"github.com/ipfs/boxo/path"
2221
"github.com/ipfs/go-datastore"
2322
syncds "github.com/ipfs/go-datastore/sync"
@@ -27,41 +26,47 @@ import (
2726

2827
type mockNamesys map[string]path.Path
2928

30-
func (m mockNamesys) Resolve(ctx context.Context, name string, opts ...nsopts.ResolveOpt) (value path.Path, err error) {
31-
cfg := nsopts.DefaultResolveOpts()
29+
func (m mockNamesys) Resolve(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) (namesys.Result, error) {
30+
cfg := namesys.DefaultResolveOptions()
3231
for _, o := range opts {
3332
o(&cfg)
3433
}
3534
depth := cfg.Depth
36-
if depth == nsopts.UnlimitedDepth {
35+
if depth == namesys.UnlimitedDepth {
3736
// max uint
3837
depth = ^uint(0)
3938
}
39+
var (
40+
value path.Path
41+
)
42+
name := path.SegmentsToString(p.Segments()[:2]...)
4043
for strings.HasPrefix(name, "/ipns/") {
4144
if depth == 0 {
42-
return value, namesys.ErrResolveRecursion
45+
return namesys.Result{Path: value}, namesys.ErrResolveRecursion
4346
}
4447
depth--
4548

46-
var ok bool
47-
value, ok = m[name]
49+
v, ok := m[name]
4850
if !ok {
49-
return nil, namesys.ErrResolveFailed
51+
return namesys.Result{}, namesys.ErrResolveFailed
5052
}
53+
value = v
5154
name = value.String()
5255
}
53-
return value, nil
56+
57+
value, err := path.Join(value, p.Segments()[2:]...)
58+
return namesys.Result{Path: value}, err
5459
}
5560

56-
func (m mockNamesys) ResolveAsync(ctx context.Context, name string, opts ...nsopts.ResolveOpt) <-chan namesys.Result {
57-
out := make(chan namesys.Result, 1)
58-
v, err := m.Resolve(ctx, name, opts...)
59-
out <- namesys.Result{Path: v, Err: err}
61+
func (m mockNamesys) ResolveAsync(ctx context.Context, p path.Path, opts ...namesys.ResolveOption) <-chan namesys.AsyncResult {
62+
out := make(chan namesys.AsyncResult, 1)
63+
res, err := m.Resolve(ctx, p, opts...)
64+
out <- namesys.AsyncResult{Path: res.Path, TTL: res.TTL, LastMod: res.LastMod, Err: err}
6065
close(out)
6166
return out
6267
}
6368

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

0 commit comments

Comments
 (0)