Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Implement ipfs name follow #4462

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const (
enablePubSubKwd = "enable-pubsub-experiment"
enableIPNSPubSubKwd = "enable-namesys-pubsub"
enableMultiplexKwd = "enable-mplex-experiment"
enableFollowKwd = "enable-follow-experiment"
// apiAddrKwd = "address-api"
// swarmAddrKwd = "address-swarm"
)
Expand Down Expand Up @@ -167,6 +168,7 @@ Headers.
cmdkit.BoolOption(enablePubSubKwd, "Instantiate the ipfs daemon with the experimental pubsub feature enabled."),
cmdkit.BoolOption(enableIPNSPubSubKwd, "Enable IPNS record distribution through pubsub; enables pubsub."),
cmdkit.BoolOption(enableMultiplexKwd, "Add the experimental 'go-multiplex' stream muxer to libp2p on construction.").WithDefault(true),
cmdkit.BoolOption(enableFollowKwd, "Enable IPNS name following."),

// TODO: add way to override addresses. tricky part: updating the config if also --init.
// cmdkit.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
Expand Down Expand Up @@ -287,6 +289,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
ipnsps, _ := req.Options[enableIPNSPubSubKwd].(bool)
pubsub, _ := req.Options[enablePubSubKwd].(bool)
mplex, _ := req.Options[enableMultiplexKwd].(bool)
follow, _ := req.Options[enableFollowKwd].(bool)

// Start assembling node config
ncfg := &core.BuildCfg{
Expand All @@ -298,6 +301,7 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
"pubsub": pubsub,
"ipnsps": ipnsps,
"mplex": mplex,
"follow": follow,
},
//TODO(Kubuxu): refactor Online vs Offline by adding Permanent vs Ephemeral
}
Expand Down
6 changes: 5 additions & 1 deletion core/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,11 @@ func setupNode(ctx context.Context, n *IpfsNode, cfg *BuildCfg) error {

if cfg.Online {
do := setupDiscoveryOption(rcfg.Discovery)
if err := n.startOnlineServices(ctx, cfg.Routing, hostOption, do, cfg.getOpt("pubsub"), cfg.getOpt("ipnsps"), cfg.getOpt("mplex")); err != nil {
pubsub := cfg.getOpt("pubsub")
ipnsps := cfg.getOpt("ipnsps")
mplex := cfg.getOpt("mplex")
follow := cfg.getOpt("follow")
if err := n.startOnlineServices(ctx, cfg.Routing, hostOption, do, pubsub, ipnsps, mplex, follow); err != nil {
return err
}
} else {
Expand Down
143 changes: 143 additions & 0 deletions core/commands/name/follow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package name

import (
"fmt"
"io"
"time"

"github.com/ipfs/go-ipfs/core/commands/cmdenv"
nc "github.com/ipfs/go-ipfs/namecache"

"gx/ipfs/QmR77mMvvh8mJBBWQmBfQBu8oD38NUN4KE9SL2gDgAQNc6/go-ipfs-cmds"
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
)

type ipnsFollowResult struct {
Result string
}

var IpnsFollowCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Follow IPNS names.",
ShortDescription: `
Periodically resolve and optionally pin IPNS names in the background.
`,
},
Subcommands: map[string]*cmds.Command{
"add": ipnsFollowAddCmd,
"list": ipnsFollowListCmd,
"cancel": ipnsFollowCancelCmd,
},
}

var ipnsFollowAddCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Follow one or more names",
ShortDescription: `
Follows an IPNS name by periodically resolving in the backround.
`,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("name", true, true, "IPNS Name to follow."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("pin", "Recursively pin the resolved pointer"),
cmdkit.StringOption("refresh-interval", "Follow refresh interval; defaults to 1hr."),
},

Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
return err
}

if n.Namecache == nil {
return cmdkit.Errorf(cmdkit.ErrClient, "IPNS Namecache is not available")
}

prefetch, _ := req.Options["prefetch"].(bool)
refrS, _ := req.Options["refresh-interval"].(string)
refr := nc.DefaultFollowInterval

if refrS != "" {
refr, err = time.ParseDuration(refrS)
if err != nil {
return err
}
}

for _, name := range req.Arguments {
err = n.Namecache.Follow(name, prefetch, refr)
if err != nil {
return err
}
}

return cmds.EmitOnce(res, &ipnsFollowResult{"ok"})
},
Type: ipnsFollowResult{},
Encoders: cmds.EncoderMap{
cmds.Text: encodeFollowResult(),
},
}

var ipnsFollowListCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List names followed by the daemon",
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
return err
}

if n.Namecache == nil {
return cmdkit.Errorf(cmdkit.ErrClient, "IPNS Namecache is not available")
}

return cmds.EmitOnce(res, &stringList{n.Namecache.ListFollows()})
},
Type: stringList{},
Encoders: cmds.EncoderMap{
cmds.Text: stringListEncoder(),
},
}

var ipnsFollowCancelCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Cancels a follow",
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("name", true, true, "Name follow to cancel."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
return err
}

if n.Namecache == nil {
return cmdkit.Errorf(cmdkit.ErrClient, "IPNS Namecache is not available")
}

for _, name := range req.Arguments {
err = n.Namecache.Unfollow(name)
if err != nil {
return err
}
}

return cmds.EmitOnce(res, &ipnsFollowResult{"ok"})
},
Type: ipnsFollowResult{},
Encoders: cmds.EncoderMap{
cmds.Text: encodeFollowResult(),
},
}

func encodeFollowResult() cmds.EncoderFunc {
return cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, list *ipnsFollowResult) error {
_, err := fmt.Fprintf(w, "%s\n", list.Result)
return err
})
}
1 change: 1 addition & 0 deletions core/commands/name/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,6 @@ Resolve the value of a dnslink:
"publish": PublishCmd,
"resolve": IpnsCmd,
"pubsub": IpnsPubsubCmd,
"follow": IpnsFollowCmd,
},
}
14 changes: 12 additions & 2 deletions core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
rp "github.com/ipfs/go-ipfs/exchange/reprovide"
filestore "github.com/ipfs/go-ipfs/filestore"
mount "github.com/ipfs/go-ipfs/fuse/mount"
namecache "github.com/ipfs/go-ipfs/namecache"
namesys "github.com/ipfs/go-ipfs/namesys"
ipnsrp "github.com/ipfs/go-ipfs/namesys/republisher"
p2p "github.com/ipfs/go-ipfs/p2p"
Expand Down Expand Up @@ -133,7 +134,8 @@ type IpfsNode struct {
Routing routing.IpfsRouting // the routing system. recommend ipfs-dht
Exchange exchange.Interface // the block exchange + strategy (bitswap)
Namesys namesys.NameSystem // the name system, resolves paths to hashes
Reprovider *rp.Reprovider // the value reprovider system
Namecache namecache.NameCache // the name system follower cache
Reprovider *rp.Reprovider // the value reprovider system
IpnsRepub *ipnsrp.Republisher

AutoNAT *autonat.AutoNATService
Expand All @@ -157,7 +159,7 @@ type Mounts struct {
Ipns mount.Mount
}

func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption, do DiscoveryOption, pubsub, ipnsps, mplex bool) error {
func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption, do DiscoveryOption, pubsub, ipnsps, mplex, follow bool) error {
if n.PeerHost != nil { // already online.
return errors.New("node already online")
}
Expand Down Expand Up @@ -293,6 +295,14 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption Routin

n.P2P = p2p.NewP2P(n.Identity, n.PeerHost, n.Peerstore)

if follow {
n.Namecache = namecache.NewNameCache(ctx, n.Namesys, n.DAG)
n.Namecache, err = namecache.NewPersistentCache(n.Namecache, n.Repo.Datastore())
if err != nil {
return err
}
}

// setup local discovery
if do != nil {
service, err := do(ctx, n.PeerHost)
Expand Down
2 changes: 1 addition & 1 deletion dagutils/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func ApplyChange(ctx context.Context, ds ipld.DAGService, nd *dag.ProtoNode, cs
// 1. two node's links number are greater than 0.
// 2. both of two nodes are ProtoNode.
// Otherwise, it compares the cid and emits a Mod change object.
func Diff(ctx context.Context, ds ipld.DAGService, a, b ipld.Node) ([]*Change, error) {
func Diff(ctx context.Context, ds ipld.NodeGetter, a, b ipld.Node) ([]*Change, error) {
// Base case where both nodes are leaves, just compare
// their CIDs.
if len(a.Links()) == 0 && len(b.Links()) == 0 {
Expand Down
Loading