Skip to content
This repository was archived by the owner on Jun 20, 2023. It is now read-only.

Commit 6436cc9

Browse files
committed
feat: use PublishOptions for publishing IPNS records
1 parent 1bf7d3d commit 6436cc9

File tree

8 files changed

+117
-150
lines changed

8 files changed

+117
-150
lines changed

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ require (
55
github.com/hashicorp/golang-lru v0.5.4
66
github.com/ipfs/go-cid v0.0.7
77
github.com/ipfs/go-datastore v0.5.0
8-
github.com/ipfs/go-ipfs-ds-help v0.1.1
8+
github.com/ipfs/go-ipfs-ds-help v1.1.0
99
github.com/ipfs/go-ipfs-keystore v0.0.2
1010
github.com/ipfs/go-ipfs-routing v0.2.1
1111
github.com/ipfs/go-ipns v0.1.2
1212
github.com/ipfs/go-log v1.0.5
13-
github.com/ipfs/go-path v0.0.9
14-
github.com/ipfs/interface-go-ipfs-core v0.4.0
13+
github.com/ipfs/go-path v0.1.1
14+
github.com/ipfs/interface-go-ipfs-core v0.7.1-0.20221207140113-4f1c5845bf21
1515
github.com/jbenet/goprocess v0.1.4
1616
github.com/libp2p/go-libp2p v0.16.0
1717
github.com/libp2p/go-libp2p-core v0.11.0

go.sum

Lines changed: 70 additions & 65 deletions
Large diffs are not rendered by default.

interface.go

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,30 @@ That works well for many use cases, but doesn't allow you to answer
77
questions like "what is Alice's current homepage?". The mutable name
88
system allows Alice to publish information like:
99
10-
The current homepage for alice.example.com is
11-
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
10+
The current homepage for alice.example.com is
11+
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
1212
1313
or:
1414
15-
The current homepage for node
16-
QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
17-
is
18-
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
15+
The current homepage for node
16+
QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy
17+
is
18+
/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj
1919
2020
The mutable name system also allows users to resolve those references
2121
to find the immutable IPFS object currently referenced by a given
2222
mutable name.
2323
2424
For command-line bindings to this functionality, see:
2525
26-
ipfs name
27-
ipfs dns
28-
ipfs resolve
26+
ipfs name
27+
ipfs dns
28+
ipfs resolve
2929
*/
3030
package namesys
3131

3232
import (
3333
"errors"
34-
"time"
3534

3635
context "context"
3736

@@ -95,12 +94,7 @@ type Resolver interface {
9594

9695
// Publisher is an object capable of publishing particular names.
9796
type Publisher interface {
98-
9997
// Publish establishes a name-value mapping.
10098
// TODO make this not PrivKey specific.
101-
Publish(ctx context.Context, name ci.PrivKey, value path.Path) error
102-
103-
// TODO: to be replaced by a more generic 'PublishWithValidity' type
104-
// call once the records spec is implemented
105-
PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error
99+
Publish(ctx context.Context, name ci.PrivKey, value path.Path, options ...opts.PublishOption) error
106100
}

namesys.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import (
4141
// (b) dns domains: resolves using links in DNS TXT records
4242
//
4343
// It can only publish to: (a) IPFS routing naming.
44-
//
4544
type mpns struct {
4645
ds ds.Datastore
4746

@@ -286,34 +285,36 @@ func emitOnceResult(ctx context.Context, outCh chan<- onceResult, r onceResult)
286285
}
287286

288287
// Publish implements Publisher
289-
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
288+
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path, options ...opts.PublishOption) error {
290289
ctx, span := StartSpan(ctx, "MPNS.Publish")
291290
defer span.End()
292-
return ns.PublishWithEOL(ctx, name, value, time.Now().Add(DefaultRecordEOL))
293-
}
294291

295-
func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error {
296-
ctx, span := StartSpan(ctx, "MPNS.PublishWithEOL", trace.WithAttributes(attribute.String("Value", value.String())))
297-
defer span.End()
292+
// This is a bit hacky. We do this because the EOL is based on the current
293+
// time, but also needed in the end of the function. Therefore, we parse
294+
// the options immediately and add an option PublishWithEOL with the EOL
295+
// calculated in this moment.
296+
publishOpts := opts.ProcessPublishOptions(options)
297+
options = append(options, opts.PublishWithEOL(publishOpts.EOL))
298+
298299
id, err := peer.IDFromPrivateKey(name)
299300
if err != nil {
300301
span.RecordError(err)
301302
return err
302303
}
303304
span.SetAttributes(attribute.String("ID", id.String()))
304-
if err := ns.ipnsPublisher.PublishWithEOL(ctx, name, value, eol); err != nil {
305+
if err := ns.ipnsPublisher.Publish(ctx, name, value, options...); err != nil {
305306
// Invalidate the cache. Publishing may _partially_ succeed but
306307
// still return an error.
307308
ns.cacheInvalidate(string(id))
308309
span.RecordError(err)
309310
return err
310311
}
311312
ttl := DefaultResolverCacheTTL
312-
if setTTL, ok := checkCtxTTL(ctx); ok {
313-
ttl = setTTL
313+
if publishOpts.TTL >= 0 {
314+
ttl = publishOpts.TTL
314315
}
315-
if ttEol := time.Until(eol); ttEol < ttl {
316-
ttl = ttEol
316+
if ttEOL := time.Until(publishOpts.EOL); ttEOL < ttl {
317+
ttl = ttEOL
317318
}
318319
ns.cacheSet(string(id), value, ttl)
319320
return nil

namesys_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,7 @@ func TestPublishWithTTL(t *testing.T) {
166166
ttl := 1 * time.Second
167167
eol := time.Now().Add(2 * time.Second)
168168

169-
ctx := ContextWithTTL(context.Background(), ttl)
170-
err = nsys.Publish(ctx, priv, p)
169+
err = nsys.Publish(context.Background(), priv, p, opts.PublishWithEOL(eol), opts.PublishWithTTL(ttl))
171170
if err != nil {
172171
t.Fatal(err)
173172
}

publisher.go

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
ipns "github.com/ipfs/go-ipns"
1313
pb "github.com/ipfs/go-ipns/pb"
1414
path "github.com/ipfs/go-path"
15+
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
1516
"github.com/libp2p/go-libp2p-core/crypto"
1617
peer "github.com/libp2p/go-libp2p-core/peer"
1718
routing "github.com/libp2p/go-libp2p-core/routing"
@@ -22,11 +23,6 @@ import (
2223

2324
const ipnsPrefix = "/ipns/"
2425

25-
// DefaultRecordEOL specifies the time that the network will cache IPNS
26-
// records after being publihsed. Records should be re-published before this
27-
// interval expires.
28-
const DefaultRecordEOL = 24 * time.Hour
29-
3026
// IpnsPublisher is capable of publishing and resolving names to the IPFS
3127
// routing system.
3228
type IpnsPublisher struct {
@@ -47,9 +43,18 @@ func NewIpnsPublisher(route routing.ValueStore, ds ds.Datastore) *IpnsPublisher
4743

4844
// Publish implements Publisher. Accepts a keypair and a value,
4945
// and publishes it out to the routing system
50-
func (p *IpnsPublisher) Publish(ctx context.Context, k crypto.PrivKey, value path.Path) error {
46+
func (p *IpnsPublisher) Publish(ctx context.Context, k crypto.PrivKey, value path.Path, options ...opts.PublishOption) error {
5147
log.Debugf("Publish %s", value)
52-
return p.PublishWithEOL(ctx, k, value, time.Now().Add(DefaultRecordEOL))
48+
49+
ctx, span := StartSpan(ctx, "IpnsPublisher.Publish", trace.WithAttributes(attribute.String("Value", value.String())))
50+
defer span.End()
51+
52+
record, err := p.updateRecord(ctx, k, value, options...)
53+
if err != nil {
54+
return err
55+
}
56+
57+
return PutRecordToRouting(ctx, p.routing, k.GetPublic(), record)
5358
}
5459

5560
// IpnsDsKey returns a datastore key given an IPNS identifier (peer
@@ -142,7 +147,7 @@ func (p *IpnsPublisher) GetPublished(ctx context.Context, id peer.ID, checkRouti
142147
return e, nil
143148
}
144149

145-
func (p *IpnsPublisher) updateRecord(ctx context.Context, k crypto.PrivKey, value path.Path, eol time.Time) (*pb.IpnsEntry, error) {
150+
func (p *IpnsPublisher) updateRecord(ctx context.Context, k crypto.PrivKey, value path.Path, options ...opts.PublishOption) (*pb.IpnsEntry, error) {
146151
id, err := peer.IDFromPrivateKey(k)
147152
if err != nil {
148153
return nil, err
@@ -164,12 +169,10 @@ func (p *IpnsPublisher) updateRecord(ctx context.Context, k crypto.PrivKey, valu
164169
seqno++
165170
}
166171

167-
// Set the TTL
168-
// TODO: Make this less hacky.
169-
ttl, _ := checkCtxTTL(ctx)
172+
opts := opts.ProcessPublishOptions(options)
170173

171174
// Create record
172-
entry, err := ipns.Create(k, []byte(value), seqno, eol, ttl)
175+
entry, err := ipns.Create(k, []byte(value), seqno, opts.EOL, opts.TTL)
173176
if err != nil {
174177
return nil, err
175178
}
@@ -190,33 +193,6 @@ func (p *IpnsPublisher) updateRecord(ctx context.Context, k crypto.PrivKey, valu
190193
return entry, nil
191194
}
192195

193-
// PublishWithEOL is a temporary stand in for the ipns records implementation
194-
// see here for more details: https://github.com/ipfs/specs/tree/master/records
195-
func (p *IpnsPublisher) PublishWithEOL(ctx context.Context, k crypto.PrivKey, value path.Path, eol time.Time) error {
196-
ctx, span := StartSpan(ctx, "IpnsPublisher.PublishWithEOL", trace.WithAttributes(attribute.String("Value", value.String())))
197-
defer span.End()
198-
199-
record, err := p.updateRecord(ctx, k, value, eol)
200-
if err != nil {
201-
return err
202-
}
203-
204-
return PutRecordToRouting(ctx, p.routing, k.GetPublic(), record)
205-
}
206-
207-
// setting the TTL on published records is an experimental feature.
208-
// as such, i'm using the context to wire it through to avoid changing too
209-
// much code along the way.
210-
func checkCtxTTL(ctx context.Context) (time.Duration, bool) {
211-
v := ctx.Value(ttlContextKey)
212-
if v == nil {
213-
return 0, false
214-
}
215-
216-
d, ok := v.(time.Duration)
217-
return d, ok
218-
}
219-
220196
// PutRecordToRouting publishes the given entry using the provided ValueStore,
221197
// keyed on the ID associated with the provided public key. The public key is
222198
// also made available to the routing system so that entries can be verified.
@@ -307,13 +283,3 @@ func PublishEntry(ctx context.Context, r routing.ValueStore, ipnskey string, rec
307283
func PkKeyForID(id peer.ID) string {
308284
return "/pk/" + string(id)
309285
}
310-
311-
// contextKey is a private comparable type used to hold value keys in contexts
312-
type contextKey string
313-
314-
var ttlContextKey contextKey = "ipns-publish-ttl"
315-
316-
// ContextWithTTL returns a copy of the parent context with an added value representing the TTL
317-
func ContextWithTTL(ctx context.Context, ttl time.Duration) context.Context {
318-
return context.WithValue(context.Background(), ttlContextKey, ttl)
319-
}

republisher/repub.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
ipns "github.com/ipfs/go-ipns"
1818
pb "github.com/ipfs/go-ipns/pb"
1919
logging "github.com/ipfs/go-log"
20+
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
2021
goprocess "github.com/jbenet/goprocess"
2122
gpctx "github.com/jbenet/goprocess/context"
2223
ic "github.com/libp2p/go-libp2p-core/crypto"
@@ -161,7 +162,7 @@ func (rp *Republisher) republishEntry(ctx context.Context, priv ic.PrivKey) erro
161162
if prevEol.After(eol) {
162163
eol = prevEol
163164
}
164-
err = rp.ns.PublishWithEOL(ctx, priv, p, eol)
165+
err = rp.ns.Publish(ctx, priv, p, opts.PublishWithEOL(eol))
165166
span.RecordError(err)
166167
return err
167168
}

republisher/repub_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/ipfs/go-ipns"
2222
ipns_pb "github.com/ipfs/go-ipns/pb"
2323
path "github.com/ipfs/go-path"
24+
opts "github.com/ipfs/interface-go-ipfs-core/options/namesys"
2425

2526
keystore "github.com/ipfs/go-ipfs-keystore"
2627
namesys "github.com/ipfs/go-namesys"
@@ -103,7 +104,7 @@ func TestRepublish(t *testing.T) {
103104
timeout := time.Second
104105
for {
105106
expiration = time.Now().Add(time.Second)
106-
err := rp.PublishWithEOL(ctx, publisher.privKey, p, expiration)
107+
err := rp.Publish(ctx, publisher.privKey, p, opts.PublishWithEOL(expiration))
107108
if err != nil {
108109
t.Fatal(err)
109110
}
@@ -179,7 +180,7 @@ func TestLongEOLRepublish(t *testing.T) {
179180
name := "/ipns/" + publisher.id
180181

181182
expiration := time.Now().Add(time.Hour)
182-
err := rp.PublishWithEOL(ctx, publisher.privKey, p, expiration)
183+
err := rp.Publish(ctx, publisher.privKey, p, opts.PublishWithEOL(expiration))
183184
if err != nil {
184185
t.Fatal(err)
185186
}

0 commit comments

Comments
 (0)