-
Notifications
You must be signed in to change notification settings - Fork 0
/
namesys.go
140 lines (122 loc) · 3.8 KB
/
namesys.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package namesys
import (
"context"
"strings"
"time"
path "github.com/ipfs/go-ipfs/path"
routing "gx/ipfs/QmNdaQ8itUU9jEZUwTsG4gHMaPmRfi6FEe89QjQAFbep3M/go-libp2p-routing"
ci "gx/ipfs/QmP1DfoUjiWH2ZBo1PBH6FupdBucbDepx3HpWmEY6JMUpY/go-libp2p-crypto"
ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore"
peer "gx/ipfs/QmdS9KpbDyPrieswibZhkod1oXqRwZJrUPzxCofAMWpFGq/go-libp2p-peer"
)
// mpns (a multi-protocol NameSystem) implements generic IPFS naming.
//
// Uses several Resolvers:
// (a) IPFS routing naming: SFS-like PKI names.
// (b) dns domains: resolves using links in DNS TXT records
// (c) proquints: interprets string as the raw byte data.
//
// It can only publish to: (a) IPFS routing naming.
//
type mpns struct {
resolvers map[string]resolver
publishers map[string]Publisher
}
// NewNameSystem will construct the IPFS naming system based on Routing
func NewNameSystem(r routing.ValueStore, ds ds.Datastore, cachesize int) NameSystem {
return &mpns{
resolvers: map[string]resolver{
"dns": newDNSResolver(),
"proquint": new(ProquintResolver),
"dht": NewRoutingResolver(r, cachesize),
},
publishers: map[string]Publisher{
"/ipns/": NewRoutingPublisher(r, ds),
},
}
}
const DefaultResolverCacheTTL = time.Minute
// Resolve implements Resolver.
func (ns *mpns) Resolve(ctx context.Context, name string) (path.Path, error) {
return ns.ResolveN(ctx, name, DefaultDepthLimit)
}
// ResolveN implements Resolver.
func (ns *mpns) ResolveN(ctx context.Context, name string, depth int) (path.Path, error) {
if strings.HasPrefix(name, "/ipfs/") {
return path.ParsePath(name)
}
if !strings.HasPrefix(name, "/") {
return path.ParsePath("/ipfs/" + name)
}
return resolve(ctx, ns, name, depth, "/ipns/")
}
// resolveOnce implements resolver.
func (ns *mpns) resolveOnce(ctx context.Context, name string) (path.Path, error) {
if !strings.HasPrefix(name, "/ipns/") {
name = "/ipns/" + name
}
segments := strings.SplitN(name, "/", 4)
if len(segments) < 3 || segments[0] != "" {
log.Warningf("Invalid name syntax for %s", name)
return "", ErrResolveFailed
}
for protocol, resolver := range ns.resolvers {
log.Debugf("Attempting to resolve %s with %s", segments[2], protocol)
p, err := resolver.resolveOnce(ctx, segments[2])
if err == nil {
if len(segments) > 3 {
return path.FromSegments("", strings.TrimRight(p.String(), "/"), segments[3])
} else {
return p, err
}
}
}
log.Warningf("No resolver found for %s", name)
return "", ErrResolveFailed
}
// Publish implements Publisher
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
err := ns.publishers["/ipns/"].Publish(ctx, name, value)
if err != nil {
return err
}
ns.addToDHTCache(name, value, time.Now().Add(DefaultRecordTTL))
return nil
}
func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error {
err := ns.publishers["/ipns/"].PublishWithEOL(ctx, name, value, eol)
if err != nil {
return err
}
ns.addToDHTCache(name, value, eol)
return nil
}
func (ns *mpns) addToDHTCache(key ci.PrivKey, value path.Path, eol time.Time) {
rr, ok := ns.resolvers["dht"].(*routingResolver)
if !ok {
// should never happen, purely for sanity
log.Panicf("unexpected type %T as DHT resolver.", ns.resolvers["dht"])
}
if rr.cache == nil {
// resolver has no caching
return
}
var err error
value, err = path.ParsePath(value.String())
if err != nil {
log.Error("could not parse path")
return
}
name, err := peer.IDFromPrivateKey(key)
if err != nil {
log.Error("while adding to cache, could not get peerid from private key")
return
}
if time.Now().Add(DefaultResolverCacheTTL).Before(eol) {
eol = time.Now().Add(DefaultResolverCacheTTL)
}
rr.cache.Add(name.Pretty(), cacheEntry{
val: value,
eol: eol,
})
}