mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-28 22:08:01 +08:00
152 lines
3.1 KiB
Go
152 lines
3.1 KiB
Go
// Package namecache implements background following (resolution and pinning) of names
|
|
package namecache
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
namesys "github.com/ipfs/go-ipfs/namesys"
|
|
pin "github.com/ipfs/go-ipfs/pin"
|
|
|
|
uio "gx/ipfs/QmUnHNqhSB1JgzVCxL1Kz3yb4bdyB4q1Z9AD5AUBVmt3fZ/go-unixfs/io"
|
|
resolver "gx/ipfs/QmVi2uUygezqaMTqs3Yzt5FcZFHJoYD4B7jQ2BELjj7ZuY/go-path/resolver"
|
|
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
|
|
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
|
|
)
|
|
|
|
const (
|
|
followInterval = 60 * time.Minute
|
|
)
|
|
|
|
var log = logging.Logger("namecache")
|
|
|
|
// NameCache represents a following cache of names
|
|
type NameCache interface {
|
|
Follow(name string, pinit bool)
|
|
Unfollow(name string)
|
|
ListFollows() []string
|
|
}
|
|
|
|
type nameCache struct {
|
|
nsys namesys.NameSystem
|
|
pinning pin.Pinner
|
|
dag ipld.DAGService
|
|
|
|
ctx context.Context
|
|
follows map[string]func()
|
|
mx sync.Mutex
|
|
}
|
|
|
|
func NewNameCache(ctx context.Context, nsys namesys.NameSystem, pinning pin.Pinner, dag ipld.DAGService) NameCache {
|
|
return &nameCache{
|
|
ctx: ctx,
|
|
nsys: nsys,
|
|
pinning: pinning,
|
|
dag: dag,
|
|
follows: make(map[string]func()),
|
|
}
|
|
}
|
|
|
|
// Follow spawns a goroutine that periodically resolves a name
|
|
// and (when pinit is true) pins it in the background
|
|
func (nc *nameCache) Follow(name string, pinit bool) {
|
|
nc.mx.Lock()
|
|
defer nc.mx.Unlock()
|
|
|
|
if _, ok := nc.follows[name]; ok {
|
|
return
|
|
}
|
|
|
|
ctx, cancel := context.WithCancel(nc.ctx)
|
|
go nc.followName(ctx, name, pinit)
|
|
nc.follows[name] = cancel
|
|
}
|
|
|
|
// Unfollow cancels a follow
|
|
func (nc *nameCache) Unfollow(name string) {
|
|
nc.mx.Lock()
|
|
defer nc.mx.Unlock()
|
|
|
|
cancel, ok := nc.follows[name]
|
|
if ok {
|
|
cancel()
|
|
delete(nc.follows, name)
|
|
}
|
|
}
|
|
|
|
// ListFollows returns a list of names currently being followed
|
|
func (nc *nameCache) ListFollows() []string {
|
|
nc.mx.Lock()
|
|
defer nc.mx.Unlock()
|
|
|
|
follows := make([]string, 0)
|
|
for name, _ := range nc.follows {
|
|
follows = append(follows, name)
|
|
}
|
|
|
|
return follows
|
|
}
|
|
|
|
func (nc *nameCache) followName(ctx context.Context, name string, pinit bool) {
|
|
nc.resolveAndPin(ctx, name, pinit)
|
|
|
|
ticker := time.NewTicker(followInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
nc.resolveAndPin(ctx, name, pinit)
|
|
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (nc *nameCache) resolveAndPin(ctx context.Context, name string, pinit bool) {
|
|
log.Debugf("resolving %s", name)
|
|
|
|
if !strings.HasPrefix(name, "/ipns/") {
|
|
name = "/ipns/" + name
|
|
}
|
|
|
|
p, err := nc.nsys.Resolve(ctx, name)
|
|
if err != nil {
|
|
log.Debugf("error resolving %s: %s", name, err.Error())
|
|
return
|
|
}
|
|
|
|
log.Debugf("resolved %s to %s", name, p)
|
|
|
|
if !pinit {
|
|
return
|
|
}
|
|
|
|
log.Debugf("pinning %s", p)
|
|
|
|
r := &resolver.Resolver{
|
|
DAG: nc.dag,
|
|
ResolveOnce: uio.ResolveUnixfsOnce,
|
|
}
|
|
|
|
n, err := r.ResolvePath(ctx, p)
|
|
if err != nil {
|
|
log.Debugf("error resolving path %s to node: %s", p, err.Error())
|
|
return
|
|
}
|
|
|
|
err = nc.pinning.Pin(ctx, n, true)
|
|
if err != nil {
|
|
log.Debugf("error pinning path %s: %s", p, err.Error())
|
|
return
|
|
}
|
|
|
|
err = nc.pinning.Flush()
|
|
if err != nil {
|
|
log.Debugf("error flushing pin: %s", err.Error())
|
|
}
|
|
}
|