diff --git a/core/core.go b/core/core.go index 2d1a1b98e96..79cc39782e9 100644 --- a/core/core.go +++ b/core/core.go @@ -297,6 +297,10 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin if follow { n.Namecache = namecache.NewNameCache(ctx, n.Namesys, n.Pinning, n.DAG, n.Blockstore) + n.Namecache, err = namecache.NewPersistentCache(n.Namecache, n.Repo.Datastore()) + if err != nil { + return err + } } // setup local discovery diff --git a/namecache/namecache.go b/namecache/namecache.go index e130f20b6e6..cfa314779a2 100644 --- a/namecache/namecache.go +++ b/namecache/namecache.go @@ -105,7 +105,7 @@ func (nc *nameCache) ListFollows() []string { defer nc.mx.Unlock() follows := make([]string, 0, len(nc.follows)) - for name, _ := range nc.follows { + for name := range nc.follows { follows = append(follows, name) } diff --git a/namecache/persistent.go b/namecache/persistent.go new file mode 100644 index 00000000000..67d30b6f319 --- /dev/null +++ b/namecache/persistent.go @@ -0,0 +1,72 @@ +package namecache + +import ( + "encoding/json" + "time" + + ds "gx/ipfs/Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM/go-datastore" + nsds "gx/ipfs/Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM/go-datastore/namespace" + dsq "gx/ipfs/Qmf4xQhNomPNhrtZc67qSnfJSjxjXs9LWvknJtSXwimPrM/go-datastore/query" +) + +var dsPrefix = ds.NewKey("/namecache") + +// persistent is a cache layer which persists followed names between node +// restarts +type persistent struct { + NameCache + + ds ds.Datastore +} + +type follow struct { + Pin bool + Deadline time.Time +} + +func NewPersistentCache(base NameCache, d ds.Datastore) (NameCache, error) { + d = nsds.Wrap(d, dsPrefix) + + q ,err := d.Query(dsq.Query{}) + if err != nil { + return nil, err + } + defer q.Close() + for e := range q.Next() { + var f follow + if err := json.Unmarshal(e.Value, &f); err != nil { + return nil, err + } + if err := base.Follow(e.Key, f.Pin, time.Now().Sub(f.Deadline)); err != nil { + return nil, err + } + } + + + return &persistent{ + NameCache: base, + ds: d, + }, nil +} + +func (p *persistent) Follow(name string, dopin bool, followInterval time.Duration) error { + b, err := json.Marshal(&follow{ + Pin: dopin, + Deadline: time.Now().Add(followInterval), + }) + if err != nil { + return err + } + + if err := p.NameCache.Follow(name, dopin, followInterval); err != nil { + return err + } + return p.ds.Put(ds.NewKey(name), b) +} + +func (p *persistent) Unfollow(name string) error { + if err := p.NameCache.Unfollow(name); err != nil { + return err + } + return p.ds.Delete(ds.NewKey(name)) +} \ No newline at end of file