cleanup namesys a bit
Remove ~50 lines of code, some casting, and a superfluous map (when go starts looking like python, something's wrong). License: MIT Signed-off-by: Steven Allen <steven@stebalien.com>
Steven Allen committed
May 9, 2018 at 13:55 UTC
1089eda84b9e1c81bed468587cc26cad99351d5e
14 files changed
+175
-204
core/commands/ipns.go
+1
-1
@@ -90,7 +90,7 @@ Resolve the value of a dnslink:
90
91
if local {
92
offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
93
- resolver = namesys.NewRoutingResolver(offroute, 0)
93
+ resolver = namesys.NewIpnsResolver(offroute)
94
}
95
96
if nocache {
core/coreapi/name.go
+1
-1
@@ -108,7 +108,7 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
108
109
if options.Local {
110
offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
111
- resolver = namesys.NewRoutingResolver(offroute, 0)
111
+ resolver = namesys.NewIpnsResolver(offroute)
112
}
113
114
if !options.Cache {
fuse/ipns/common.go
+1
-1
@@ -28,7 +28,7 @@ func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error {
28
return err
29
}
30
31
- pub := nsys.NewRoutingPublisher(n.Routing, n.Repo.Datastore())
31
+ pub := nsys.NewIpnsPublisher(n.Routing, n.Repo.Datastore())
32
33
return pub.Publish(ctx, key, path.FromCid(emptyDir.Cid()))
34
}
namesys/base.go
+3
-2
@@ -2,6 +2,7 @@ package namesys
2
3
import (
4
"strings"
5
+ "time"
6
7
context "context"
8
@@ -11,14 +12,14 @@ import (
12
13
type resolver interface {
14
// resolveOnce looks up a name once (without recursion).
14
- resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (value path.Path, err error)
15
+ resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (value path.Path, ttl time.Duration, err error)
16
}
17
18
// resolve is a helper for implementing Resolver.ResolveN using resolveOnce.
19
func resolve(ctx context.Context, r resolver, name string, options *opts.ResolveOpts, prefixes ...string) (path.Path, error) {
20
depth := options.Depth
21
for {
21
- p, err := r.resolveOnce(ctx, name, options)
22
+ p, _, err := r.resolveOnce(ctx, name, options)
23
if err != nil {
24
return "", err
25
}
namesys/cache.go
new
+47
@@ -0,0 +1,47 @@
1
+package namesys
2
+
3
+import (
4
+ "time"
5
+
6
+ path "github.com/ipfs/go-ipfs/path"
7
+)
8
+
9
+func (ns *mpns) cacheGet(name string) (path.Path, bool) {
10
+ if ns.cache == nil {
11
+ return "", false
12
+ }
13
+
14
+ ientry, ok := ns.cache.Get(name)
15
+ if !ok {
16
+ return "", false
17
+ }
18
+
19
+ entry, ok := ientry.(cacheEntry)
20
+ if !ok {
21
+ // should never happen, purely for sanity
22
+ log.Panicf("unexpected type %T in cache for %q.", ientry, name)
23
+ }
24
+
25
+ if time.Now().Before(entry.eol) {
26
+ return entry.val, true
27
+ }
28
+
29
+ ns.cache.Remove(name)
30
+
31
+ return "", false
32
+}
33
+
34
+func (ns *mpns) cacheSet(name string, val path.Path, ttl time.Duration) {
35
+ if ns.cache == nil || ttl <= 0 {
36
+ return
37
+ }
38
+ ns.cache.Add(name, cacheEntry{
39
+ val: val,
40
+ eol: time.Now().Add(ttl),
41
+ })
42
+}
43
+
44
+type cacheEntry struct {
45
+ val path.Path
46
+ eol time.Time
47
+}
namesys/dns.go
+9
-8
@@ -5,6 +5,7 @@ import (
5
"errors"
6
"net"
7
"strings"
8
+ "time"
9
10
opts "github.com/ipfs/go-ipfs/namesys/opts"
11
path "github.com/ipfs/go-ipfs/path"
@@ -38,12 +39,12 @@ type lookupRes struct {
39
// resolveOnce implements resolver.
40
// TXT records for a given domain name should contain a b58
41
// encoded multihash.
41
-func (r *DNSResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) {
42
+func (r *DNSResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, time.Duration, error) {
43
segments := strings.SplitN(name, "/", 2)
44
domain := segments[0]
45
46
if !isd.IsDomain(domain) {
46
- return "", errors.New("not a valid domain name")
47
+ return "", 0, errors.New("not a valid domain name")
48
}
49
log.Debugf("DNSResolver resolving %s", domain)
50
@@ -57,7 +58,7 @@ func (r *DNSResolver) resolveOnce(ctx context.Context, name string, options *opt
58
select {
59
case subRes = <-subChan:
60
case <-ctx.Done():
60
- return "", ctx.Err()
61
+ return "", 0, ctx.Err()
62
}
63
64
var p path.Path
@@ -68,19 +69,19 @@ func (r *DNSResolver) resolveOnce(ctx context.Context, name string, options *opt
69
select {
70
case rootRes = <-rootChan:
71
case <-ctx.Done():
71
- return "", ctx.Err()
72
+ return "", 0, ctx.Err()
73
}
74
if rootRes.error == nil {
75
p = rootRes.path
76
} else {
76
- return "", ErrResolveFailed
77
+ return "", 0, ErrResolveFailed
78
}
79
}
80
+ var err error
81
if len(segments) > 1 {
80
- return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[1])
81
- } else {
82
- return p, nil
82
+ p, err = path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[1])
83
}
84
+ return p, 0, err
85
}
86
87
func workDomain(r *DNSResolver, name string, res chan lookupRes) {
namesys/ipns_validate_test.go
+6
-6
@@ -81,7 +81,7 @@ func TestResolverValidation(t *testing.T) {
81
peerstore := pstore.NewPeerstore()
82
83
vstore := newMockValueStore(rid, dstore, peerstore)
84
- resolver := NewRoutingResolver(vstore, 0)
84
+ resolver := NewIpnsResolver(vstore)
85
86
// Create entry with expiry in one hour
87
priv, id, _, ipnsDHTPath := genKeys(t)
@@ -105,7 +105,7 @@ func TestResolverValidation(t *testing.T) {
105
}
106
107
// Resolve entry
108
- resp, err := resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts())
108
+ resp, _, err := resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts())
109
if err != nil {
110
t.Fatal(err)
111
}
@@ -126,7 +126,7 @@ func TestResolverValidation(t *testing.T) {
126
}
127
128
// Record should fail validation because entry is expired
129
- _, err = resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts())
129
+ _, _, err = resolver.resolveOnce(ctx, id.Pretty(), opts.DefaultResolveOpts())
130
if err == nil {
131
t.Fatal("ValidateIpnsRecord should have returned error")
132
}
@@ -148,7 +148,7 @@ func TestResolverValidation(t *testing.T) {
148
149
// Record should fail validation because public key defined by
150
// ipns path doesn't match record signature
151
- _, err = resolver.resolveOnce(ctx, id2.Pretty(), opts.DefaultResolveOpts())
151
+ _, _, err = resolver.resolveOnce(ctx, id2.Pretty(), opts.DefaultResolveOpts())
152
if err == nil {
153
t.Fatal("ValidateIpnsRecord should have failed signature verification")
154
}
@@ -166,7 +166,7 @@ func TestResolverValidation(t *testing.T) {
166
167
// Record should fail validation because public key is not available
168
// in peer store or on network
169
- _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts())
169
+ _, _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts())
170
if err == nil {
171
t.Fatal("ValidateIpnsRecord should have failed because public key was not found")
172
}
@@ -181,7 +181,7 @@ func TestResolverValidation(t *testing.T) {
181
// public key is available in the peer store by looking it up in
182
// the DHT, which causes the DHT to fetch it and cache it in the
183
// peer store
184
- _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts())
184
+ _, _, err = resolver.resolveOnce(ctx, id3.Pretty(), opts.DefaultResolveOpts())
185
if err != nil {
186
t.Fatal(err)
187
}
namesys/namesys.go
+49
-70
@@ -9,6 +9,7 @@ import (
9
path "github.com/ipfs/go-ipfs/path"
10
11
routing "gx/ipfs/QmUHRKTeaoASDvDj7cTAXsmjAY7KQ13ErtzkQHZQq6uFUz/go-libp2p-routing"
12
+ lru "gx/ipfs/QmVYxfoJQiZijTgPNHCHgHELvQpbsJNTg6Crmc3dQkj3yy/golang-lru"
13
isd "gx/ipfs/QmZmmuAXgX73UQmX1jRKjTGmjzq24Jinqkq8vzkBtno4uX/go-is-domain"
14
mh "gx/ipfs/QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua/go-multihash"
15
peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer"
@@ -26,21 +27,25 @@ import (
27
// It can only publish to: (a) IPFS routing naming.
28
//
29
type mpns struct {
29
- resolvers map[string]resolver
30
- publishers map[string]Publisher
30
+ dnsResolver, proquintResolver, ipnsResolver resolver
31
+ ipnsPublisher Publisher
32
+
33
+ cache *lru.Cache
34
}
35
36
// NewNameSystem will construct the IPFS naming system based on Routing
37
func NewNameSystem(r routing.ValueStore, ds ds.Datastore, cachesize int) NameSystem {
38
+ var cache *lru.Cache
39
+ if cachesize > 0 {
40
+ cache, _ = lru.New(cachesize)
41
+ }
42
+
43
return &mpns{
36
- resolvers: map[string]resolver{
37
- "dns": NewDNSResolver(),
38
- "proquint": new(ProquintResolver),
39
- "ipns": NewRoutingResolver(r, cachesize),
40
- },
41
- publishers: map[string]Publisher{
42
- "ipns": NewRoutingPublisher(r, ds),
43
- },
44
+ dnsResolver: NewDNSResolver(),
45
+ proquintResolver: new(ProquintResolver),
46
+ ipnsResolver: NewIpnsResolver(r),
47
+ ipnsPublisher: NewIpnsPublisher(r, ds),
48
+ cache: cache,
49
}
50
}
51
@@ -60,42 +65,46 @@ func (ns *mpns) Resolve(ctx context.Context, name string, options ...opts.Resolv
65
}
66
67
// resolveOnce implements resolver.
63
-func (ns *mpns) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) {
68
+func (ns *mpns) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, time.Duration, error) {
69
if !strings.HasPrefix(name, "/ipns/") {
70
name = "/ipns/" + name
71
}
72
segments := strings.SplitN(name, "/", 4)
73
if len(segments) < 3 || segments[0] != "" {
74
log.Debugf("invalid name syntax for %s", name)
70
- return "", ErrResolveFailed
75
+ return "", 0, ErrResolveFailed
76
}
77
73
- // Resolver selection:
74
- // 1. if it is a multihash resolve through "ipns".
75
- // 2. if it is a domain name, resolve through "dns"
76
- // 3. otherwise resolve through the "proquint" resolver
78
key := segments[2]
78
- resName := "proquint"
79
- if _, err := mh.FromB58String(key); err == nil {
80
- resName = "ipns"
81
- } else if isd.IsDomain(key) {
82
- resName = "dns"
83
- }
79
85
- res, ok := ns.resolvers[resName]
80
+ p, ok := ns.cacheGet(key)
81
+ var err error
82
if !ok {
87
- log.Debugf("no resolver found for %s", name)
88
- return "", ErrResolveFailed
89
- }
90
- p, err := res.resolveOnce(ctx, key, options)
91
- if err != nil {
92
- return "", ErrResolveFailed
83
+ // Resolver selection:
84
+ // 1. if it is a multihash resolve through "ipns".
85
+ // 2. if it is a domain name, resolve through "dns"
86
+ // 3. otherwise resolve through the "proquint" resolver
87
+ var res resolver
88
+ if _, err := mh.FromB58String(key); err == nil {
89
+ res = ns.ipnsResolver
90
+ } else if isd.IsDomain(key) {
91
+ res = ns.dnsResolver
92
+ } else {
93
+ res = ns.proquintResolver
94
+ }
95
+
96
+ var ttl time.Duration
97
+ p, ttl, err = res.resolveOnce(ctx, key, options)
98
+ if err != nil {
99
+ return "", 0, ErrResolveFailed
100
+ }
101
+ ns.cacheSet(key, p, ttl)
102
}
103
104
if len(segments) > 3 {
96
- return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
105
+ p, err = path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
106
}
98
- return p, nil
107
+ return p, 0, err
108
}
109
110
// Publish implements Publisher
@@ -104,47 +113,17 @@ func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) e
113
}
114
115
func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error {
107
- pub, ok := ns.publishers["ipns"]
108
- if !ok {
109
- return ErrPublishFailed
110
- }
111
- if err := pub.PublishWithEOL(ctx, name, value, eol); err != nil {
112
- return err
113
- }
114
- ns.addToIpnsCache(name, value, eol)
115
- return nil
116
-
117
-}
118
-
119
-func (ns *mpns) addToIpnsCache(key ci.PrivKey, value path.Path, eol time.Time) {
120
- rr, ok := ns.resolvers["ipns"].(*routingResolver)
121
- if !ok {
122
- // should never happen, purely for sanity
123
- log.Panicf("unexpected type %T as DHT resolver.", ns.resolvers["ipns"])
124
- }
125
- if rr.cache == nil {
126
- // resolver has no caching
127
- return
128
- }
129
-
130
- var err error
131
- value, err = path.ParsePath(value.String())
116
+ id, err := peer.IDFromPrivateKey(name)
117
if err != nil {
133
- log.Error("could not parse path")
134
- return
118
+ return err
119
}
136
-
137
- name, err := peer.IDFromPrivateKey(key)
138
- if err != nil {
139
- log.Error("while adding to cache, could not get peerid from private key")
140
- return
120
+ if err := ns.ipnsPublisher.PublishWithEOL(ctx, name, value, eol); err != nil {
121
+ return err
122
}
142
-
143
- if time.Now().Add(DefaultResolverCacheTTL).Before(eol) {
144
- eol = time.Now().Add(DefaultResolverCacheTTL)
123
+ ttl := DefaultResolverCacheTTL
124
+ if ttEol := eol.Sub(time.Now()); ttEol < ttl {
125
+ ttl = ttEol
126
}
146
- rr.cache.Add(name.Pretty(), cacheEntry{
147
- val: value,
148
- eol: eol,
149
- })
127
+ ns.cacheSet(peer.IDB58Encode(id), value, ttl)
128
+ return nil
129
}
namesys/namesys_test.go
+8
-8
@@ -1,10 +1,10 @@
1
package namesys
2
3
import (
4
+ "context"
5
"fmt"
6
"testing"
6
-
7
- context "context"
7
+ "time"
8
9
opts "github.com/ipfs/go-ipfs/namesys/opts"
10
path "github.com/ipfs/go-ipfs/path"
@@ -21,6 +21,7 @@ type mockResolver struct {
21
}
22
23
func testResolution(t *testing.T, resolver Resolver, name string, depth uint, expected string, expError error) {
24
+ t.Helper()
25
p, err := resolver.Resolve(context.Background(), name, opts.Depth(depth))
26
if err != expError {
27
t.Fatal(fmt.Errorf(
@@ -34,8 +35,9 @@ func testResolution(t *testing.T, resolver Resolver, name string, depth uint, ex
35
}
36
}
37
37
-func (r *mockResolver) resolveOnce(ctx context.Context, name string, opts *opts.ResolveOpts) (path.Path, error) {
38
- return path.ParsePath(r.entries[name])
38
+func (r *mockResolver) resolveOnce(ctx context.Context, name string, opts *opts.ResolveOpts) (path.Path, time.Duration, error) {
39
+ p, err := path.ParsePath(r.entries[name])
40
+ return p, 0, err
41
}
42
43
func mockResolverOne() *mockResolver {
@@ -58,10 +60,8 @@ func mockResolverTwo() *mockResolver {
60
61
func TestNamesysResolution(t *testing.T) {
62
r := &mpns{
61
- resolvers: map[string]resolver{
62
- "ipns": mockResolverOne(),
63
- "dns": mockResolverTwo(),
64
- },
63
+ ipnsResolver: mockResolverOne(),
64
+ dnsResolver: mockResolverTwo(),
65
}
66
67
testResolution(t, r, "Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", opts.DefaultDepthLimit, "/ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj", nil)
namesys/proquint.go
+5
-3
@@ -2,6 +2,7 @@ package namesys
2
3
import (
4
"errors"
5
+ "time"
6
7
context "context"
8
@@ -18,10 +19,11 @@ func (r *ProquintResolver) Resolve(ctx context.Context, name string, options ...
19
}
20
21
// resolveOnce implements resolver. Decodes the proquint string.
21
-func (r *ProquintResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) {
22
+func (r *ProquintResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, time.Duration, error) {
23
ok, err := proquint.IsProquint(name)
24
if err != nil || !ok {
24
- return "", errors.New("not a valid proquint string")
25
+ return "", 0, errors.New("not a valid proquint string")
26
}
26
- return path.FromString(string(proquint.Decode(name))), nil
27
+ // Return a 0 TTL as caching this result is pointless.
28
+ return path.FromString(string(proquint.Decode(name))), 0, nil
29
}
namesys/publisher.go
+10
-10
@@ -28,9 +28,9 @@ const ipnsPrefix = "/ipns/"
28
const PublishPutValTimeout = time.Minute
29
const DefaultRecordTTL = 24 * time.Hour
30
31
-// ipnsPublisher is capable of publishing and resolving names to the IPFS
31
+// IpnsPublisher is capable of publishing and resolving names to the IPFS
32
// routing system.
33
-type ipnsPublisher struct {
33
+type IpnsPublisher struct {
34
routing routing.ValueStore
35
ds ds.Datastore
36
@@ -38,17 +38,17 @@ type ipnsPublisher struct {
38
mu sync.Mutex
39
}
40
41
-// NewRoutingPublisher constructs a publisher for the IPFS Routing name system.
42
-func NewRoutingPublisher(route routing.ValueStore, ds ds.Datastore) *ipnsPublisher {
41
+// NewIpnsPublisher constructs a publisher for the IPFS Routing name system.
42
+func NewIpnsPublisher(route routing.ValueStore, ds ds.Datastore) *IpnsPublisher {
43
if ds == nil {
44
panic("nil datastore")
45
}
46
- return &ipnsPublisher{routing: route, ds: ds}
46
+ return &IpnsPublisher{routing: route, ds: ds}
47
}
48
49
// Publish implements Publisher. Accepts a keypair and a value,
50
// and publishes it out to the routing system
51
-func (p *ipnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value path.Path) error {
51
+func (p *IpnsPublisher) Publish(ctx context.Context, k ci.PrivKey, value path.Path) error {
52
log.Debugf("Publish %s", value)
53
return p.PublishWithEOL(ctx, k, value, time.Now().Add(DefaultRecordTTL))
54
}
@@ -62,7 +62,7 @@ func IpnsDsKey(id peer.ID) ds.Key {
62
//
63
// This method will not search the routing system for records published by other
64
// nodes.
65
-func (p *ipnsPublisher) ListPublished(ctx context.Context) (map[peer.ID]*pb.IpnsEntry, error) {
65
+func (p *IpnsPublisher) ListPublished(ctx context.Context) (map[peer.ID]*pb.IpnsEntry, error) {
66
query, err := p.ds.Query(dsquery.Query{
67
Prefix: ipnsPrefix,
68
})
@@ -114,7 +114,7 @@ func (p *ipnsPublisher) ListPublished(ctx context.Context) (map[peer.ID]*pb.Ipns
114
//
115
// If `checkRouting` is true and we have no existing record, this method will
116
// check the routing system for any existing records.
117
-func (p *ipnsPublisher) GetPublished(ctx context.Context, id peer.ID, checkRouting bool) (*pb.IpnsEntry, error) {
117
+func (p *IpnsPublisher) GetPublished(ctx context.Context, id peer.ID, checkRouting bool) (*pb.IpnsEntry, error) {
118
ctx, cancel := context.WithTimeout(ctx, time.Second*30)
119
defer cancel()
120
@@ -148,7 +148,7 @@ func (p *ipnsPublisher) GetPublished(ctx context.Context, id peer.ID, checkRouti
148
return e, nil
149
}
150
151
-func (p *ipnsPublisher) updateRecord(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) (*pb.IpnsEntry, error) {
151
+func (p *IpnsPublisher) updateRecord(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) (*pb.IpnsEntry, error) {
152
id, err := peer.IDFromPrivateKey(k)
153
if err != nil {
154
return nil, err
@@ -197,7 +197,7 @@ func (p *ipnsPublisher) updateRecord(ctx context.Context, k ci.PrivKey, value pa
197
198
// PublishWithEOL is a temporary stand in for the ipns records implementation
199
// see here for more details: https://github.com/ipfs/specs/tree/master/records
200
-func (p *ipnsPublisher) PublishWithEOL(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) error {
200
+func (p *IpnsPublisher) PublishWithEOL(ctx context.Context, k ci.PrivKey, value path.Path, eol time.Time) error {
201
record, err := p.updateRecord(ctx, k, value, eol)
202
if err != nil {
203
return err
namesys/republisher/repub_test.go
+1
-1
@@ -58,7 +58,7 @@ func TestRepublish(t *testing.T) {
58
// have one node publish a record that is valid for 1 second
59
publisher := nodes[3]
60
p := path.FromString("/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn") // does not need to be valid
61
- rp := namesys.NewRoutingPublisher(publisher.Routing, publisher.Repo.Datastore())
61
+ rp := namesys.NewIpnsPublisher(publisher.Routing, publisher.Repo.Datastore())
62
err := rp.PublishWithEOL(ctx, publisher.PrivateKey, p, time.Now().Add(time.Second))
63
if err != nil {
64
t.Fatal(err)
namesys/resolve_test.go
+6
-6
@@ -21,8 +21,8 @@ func TestRoutingResolve(t *testing.T) {
21
id := testutil.RandIdentityOrFatal(t)
22
d := serv.ClientWithDatastore(context.Background(), id, dstore)
23
24
- resolver := NewRoutingResolver(d, 0)
25
- publisher := NewRoutingPublisher(d, dstore)
24
+ resolver := NewIpnsResolver(d)
25
+ publisher := NewIpnsPublisher(d, dstore)
26
27
privk, pubk, err := testutil.RandTestKeyPair(512)
28
if err != nil {
@@ -54,8 +54,8 @@ func TestPrexistingExpiredRecord(t *testing.T) {
54
dstore := dssync.MutexWrap(ds.NewMapDatastore())
55
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)
56
57
- resolver := NewRoutingResolver(d, 0)
58
- publisher := NewRoutingPublisher(d, dstore)
57
+ resolver := NewIpnsResolver(d)
58
+ publisher := NewIpnsPublisher(d, dstore)
59
60
privk, pubk, err := testutil.RandTestKeyPair(512)
61
if err != nil {
@@ -96,8 +96,8 @@ func TestPrexistingRecord(t *testing.T) {
96
dstore := dssync.MutexWrap(ds.NewMapDatastore())
97
d := mockrouting.NewServer().ClientWithDatastore(context.Background(), testutil.RandIdentityOrFatal(t), dstore)
98
99
- resolver := NewRoutingResolver(d, 0)
100
- publisher := NewRoutingPublisher(d, dstore)
99
+ resolver := NewIpnsResolver(d)
100
+ publisher := NewIpnsPublisher(d, dstore)
101
102
privk, pubk, err := testutil.RandTestKeyPair(512)
103
if err != nil {
namesys/routing.go
+28
-87
@@ -12,7 +12,6 @@ import (
12
u "gx/ipfs/QmNiJuT8Ja3hMVpBHXv3Q6dwmperaQ6JjLtpMQgMCD7xvx/go-ipfs-util"
13
logging "gx/ipfs/QmTG23dvpBCBjqQwyDxV8CQT6jmS4PSftNr1VqHhE3MLy7/go-log"
14
routing "gx/ipfs/QmUHRKTeaoASDvDj7cTAXsmjAY7KQ13ErtzkQHZQq6uFUz/go-libp2p-routing"
15
- lru "gx/ipfs/QmVYxfoJQiZijTgPNHCHgHELvQpbsJNTg6Crmc3dQkj3yy/golang-lru"
15
proto "gx/ipfs/QmZ4Qi3GaRbjcx28Sme5eMH7RQjGkt8wHxt2a65oLaeFEV/gogo-protobuf/proto"
16
mh "gx/ipfs/QmZyZDi491cCNTLfAhwcaDii2Kg4pwKRkhqQzURGDvY6ua/go-multihash"
17
peer "gx/ipfs/QmcJukH2sAFjY3HdBKq35WDzWoL3UUu2gt9wdfqZTUyM74/go-libp2p-peer"
@@ -22,102 +21,31 @@ import (
21
22
var log = logging.Logger("namesys")
23
25
-// routingResolver implements NSResolver for the main IPFS SFS-like naming
26
-type routingResolver struct {
24
+// IpnsResolver implements NSResolver for the main IPFS SFS-like naming
25
+type IpnsResolver struct {
26
routing routing.ValueStore
28
-
29
- cache *lru.Cache
30
-}
31
-
32
-func (r *routingResolver) cacheGet(name string) (path.Path, bool) {
33
- if r.cache == nil {
34
- return "", false
35
- }
36
-
37
- ientry, ok := r.cache.Get(name)
38
- if !ok {
39
- return "", false
40
- }
41
-
42
- entry, ok := ientry.(cacheEntry)
43
- if !ok {
44
- // should never happen, purely for sanity
45
- log.Panicf("unexpected type %T in cache for %q.", ientry, name)
46
- }
47
-
48
- if time.Now().Before(entry.eol) {
49
- return entry.val, true
50
- }
51
-
52
- r.cache.Remove(name)
53
-
54
- return "", false
55
-}
56
-
57
-func (r *routingResolver) cacheSet(name string, val path.Path, rec *pb.IpnsEntry) {
58
- if r.cache == nil {
59
- return
60
- }
61
-
62
- // if completely unspecified, just use one minute
63
- ttl := DefaultResolverCacheTTL
64
- if rec.Ttl != nil {
65
- recttl := time.Duration(rec.GetTtl())
66
- if recttl >= 0 {
67
- ttl = recttl
68
- }
69
- }
70
-
71
- cacheTil := time.Now().Add(ttl)
72
- eol, ok := checkEOL(rec)
73
- if ok && eol.Before(cacheTil) {
74
- cacheTil = eol
75
- }
76
-
77
- r.cache.Add(name, cacheEntry{
78
- val: val,
79
- eol: cacheTil,
80
- })
81
-}
82
-
83
-type cacheEntry struct {
84
- val path.Path
85
- eol time.Time
27
}
28
88
-// NewRoutingResolver constructs a name resolver using the IPFS Routing system
29
+// NewIpnsResolver constructs a name resolver using the IPFS Routing system
30
// to implement SFS-like naming on top.
90
-// cachesize is the limit of the number of entries in the lru cache. Setting it
91
-// to '0' will disable caching.
92
-func NewRoutingResolver(route routing.ValueStore, cachesize int) *routingResolver {
31
+func NewIpnsResolver(route routing.ValueStore) *IpnsResolver {
32
if route == nil {
33
panic("attempt to create resolver with nil routing system")
34
}
96
-
97
- var cache *lru.Cache
98
- if cachesize > 0 {
99
- cache, _ = lru.New(cachesize)
100
- }
101
-
102
- return &routingResolver{
35
+ return &IpnsResolver{
36
routing: route,
104
- cache: cache,
37
}
38
}
39
40
// Resolve implements Resolver.
109
-func (r *routingResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
41
+func (r *IpnsResolver) Resolve(ctx context.Context, name string, options ...opts.ResolveOpt) (path.Path, error) {
42
return resolve(ctx, r, name, opts.ProcessOpts(options), "/ipns/")
43
}
44
45
// resolveOnce implements resolver. Uses the IPFS routing system to
46
// resolve SFS-like names.
115
-func (r *routingResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, error) {
47
+func (r *IpnsResolver) resolveOnce(ctx context.Context, name string, options *opts.ResolveOpts) (path.Path, time.Duration, error) {
48
log.Debugf("RoutingResolver resolving %s", name)
117
- cached, ok := r.cacheGet(name)
118
- if ok {
119
- return cached, nil
120
- }
49
50
if options.DhtTimeout != 0 {
51
// Resolution must complete within the timeout
@@ -131,13 +59,13 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, options
59
if err != nil {
60
// name should be a multihash. if it isn't, error out here.
61
log.Debugf("RoutingResolver: bad input hash: [%s]\n", name)
134
- return "", err
62
+ return "", 0, err
63
}
64
65
pid, err := peer.IDFromBytes(hash)
66
if err != nil {
67
log.Debugf("RoutingResolver: could not convert public key hash %s to peer ID: %s\n", name, err)
140
- return "", err
68
+ return "", 0, err
69
}
70
71
// Name should be the hash of a public key retrievable from ipfs.
@@ -148,7 +76,7 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, options
76
_, err = routing.GetPublicKey(r.routing, ctx, pid)
77
if err != nil {
78
log.Debugf("RoutingResolver: could not retrieve public key %s: %s\n", name, err)
151
- return "", err
79
+ return "", 0, err
80
}
81
82
// Use the routing system to get the name.
@@ -158,14 +86,14 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, options
86
val, err := r.routing.GetValue(ctx, ipnsKey, dht.Quorum(int(options.DhtRecordCount)))
87
if err != nil {
88
log.Debugf("RoutingResolver: dht get for name %s failed: %s", name, err)
161
- return "", err
89
+ return "", 0, err
90
}
91
92
entry := new(pb.IpnsEntry)
93
err = proto.Unmarshal(val, entry)
94
if err != nil {
95
log.Debugf("RoutingResolver: could not unmarshal value for name %s: %s", name, err)
168
- return "", err
96
+ return "", 0, err
97
}
98
99
var p path.Path
@@ -178,12 +106,25 @@ func (r *routingResolver) resolveOnce(ctx context.Context, name string, options
106
// Not a multihash, probably a new record
107
p, err = path.ParsePath(string(entry.GetValue()))
108
if err != nil {
181
- return "", err
109
+ return "", 0, err
110
+ }
111
+ }
112
+
113
+ ttl := DefaultResolverCacheTTL
114
+ if entry.Ttl != nil {
115
+ ttl = time.Duration(*entry.Ttl)
116
+ }
117
+ if eol, ok := checkEOL(entry); ok {
118
+ ttEol := eol.Sub(time.Now())
119
+ if ttEol < 0 {
120
+ // It *was* valid when we first resolved it.
121
+ ttl = 0
122
+ } else if ttEol < ttl {
123
+ ttl = ttEol
124
}
125
}
126
185
- r.cacheSet(name, p, entry)
186
- return p, nil
127
+ return p, ttl, nil
128
}
129
130
func checkEOL(e *pb.IpnsEntry) (time.Time, bool) {