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

Switch name publish/resolve to coreapi #5563

Merged
merged 3 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
53 changes: 16 additions & 37 deletions core/commands/name/ipns.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import (

cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
namesys "github.com/ipfs/go-ipfs/namesys"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
nsopts "github.com/ipfs/go-ipfs/namesys/opts"

"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
offline "gx/ipfs/QmScZySgru9jaoDa12sSfvh21sWbqF5eXkieTmJzAHJXkQ/go-ipfs-routing/offline"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
Expand Down Expand Up @@ -80,44 +79,21 @@ Resolve the value of a dnslink:
cmdkit.StringOption(dhtTimeoutOptionName, "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
api, err := cmdenv.GetApi(env)
if err != nil {
return err
}

if !n.OnlineMode() {
err := n.SetupOfflineRouting()
if err != nil {
return err
}
}

nocache, _ := req.Options["nocache"].(bool)
local, _ := req.Options["local"].(bool)

// default to nodes namesys resolver
var resolver namesys.Resolver = n.Namesys

if local && nocache {
return errors.New("cannot specify both local and nocache")
}

if local {
offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.RecordValidator)
resolver = namesys.NewIpnsResolver(offroute)
}

if nocache {
resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0)
}

var name string
if len(req.Arguments) == 0 {
if n.Identity == "" {
return errors.New("identity not loaded")
self, err := api.Key().Self(req.Context)
if err != nil {
return err
}
name = n.Identity.Pretty()

name = self.ID().Pretty()
} else {
name = req.Arguments[0]
}
Expand All @@ -126,12 +102,16 @@ Resolve the value of a dnslink:
rc, rcok := req.Options[dhtRecordCountOptionName].(int)
dhtt, dhttok := req.Options[dhtTimeoutOptionName].(string)

var ropts []nsopts.ResolveOpt
opts := []options.NameResolveOption{
options.Name.Local(local),
options.Name.Cache(!nocache),
}

if !recursive {
ropts = append(ropts, nsopts.Depth(1))
opts = append(opts, options.Name.ResolveOption(nsopts.Depth(1)))
}
if rcok {
ropts = append(ropts, nsopts.DhtRecordCount(uint(rc)))
opts = append(opts, options.Name.ResolveOption(nsopts.DhtRecordCount(uint(rc))))
}
if dhttok {
d, err := time.ParseDuration(dhtt)
Expand All @@ -141,20 +121,19 @@ Resolve the value of a dnslink:
if d < 0 {
return errors.New("DHT timeout value must be >= 0")
}
ropts = append(ropts, nsopts.DhtTimeout(d))
opts = append(opts, options.Name.ResolveOption(nsopts.DhtTimeout(d)))
}

if !strings.HasPrefix(name, "/ipns/") {
name = "/ipns/" + name
}

output, err := resolver.Resolve(req.Context, name, ropts...)
output, err := api.Name().Resolve(req.Context, name, opts...)
if err != nil {
return err
}

// TODO: better errors (in the case of not finding the name, we get "failed to find any peer in table")
return cmds.EmitOnce(res, &ResolvedPath{output})
return cmds.EmitOnce(res, &ResolvedPath{path.FromString(output.String())})
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
Expand Down
139 changes: 26 additions & 113 deletions core/commands/name/publish.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
package name

import (
"context"
"errors"
"fmt"
"io"
"time"

core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
keystore "github.com/ipfs/go-ipfs/keystore"
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"

crypto "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
)

var (
errAllowOffline = errors.New("can't publish while offline: pass `--allow-offline` to override")
errIpnsMount = errors.New("cannot manually publish while IPNS is mounted")
errIdentityLoad = errors.New("identity not loaded")
)

const (
Expand Down Expand Up @@ -90,71 +84,59 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
cmdkit.BoolOption(quieterOptionName, "Q", "Write only final hash."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
api, err := cmdenv.GetApi(env)
if err != nil {
return err
}

allowOffline, _ := req.Options[allowOfflineOptionName].(bool)
if !n.OnlineMode() {
if !allowOffline {
return errAllowOffline
}
err := n.SetupOfflineRouting()
if err != nil {
return err
}
}

if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() {
return errIpnsMount
}

pstr := req.Arguments[0]

if n.Identity == "" {
return errIdentityLoad
}

popts := new(publishOpts)

popts.verifyExists, _ = req.Options[resolveOptionName].(bool)
kname, _ := req.Options[keyOptionName].(string)

validtime, _ := req.Options[lifeTimeOptionName].(string)
d, err := time.ParseDuration(validtime)
validTimeOpt, _ := req.Options[lifeTimeOptionName].(string)
validTime, err := time.ParseDuration(validTimeOpt)
if err != nil {
return fmt.Errorf("error parsing lifetime option: %s", err)
}

popts.pubValidTime = d
opts := []options.NamePublishOption{
options.Name.AllowOffline(allowOffline),
options.Name.Key(kname),
options.Name.ValidTime(validTime),
}

ctx := req.Context
if ttl, found := req.Options[ttlOptionName].(string); found {
d, err := time.ParseDuration(ttl)
if err != nil {
return err
}

ctx = context.WithValue(ctx, "ipns-publish-ttl", d)
opts = append(opts, options.Name.TTL(d))
}

kname, _ := req.Options[keyOptionName].(string)
k, err := keylookup(n, kname)
p, err := iface.ParsePath(req.Arguments[0])
if err != nil {
return err
}

pth, err := path.ParsePath(pstr)
if err != nil {
return err
if verifyExists, _ := req.Options[resolveOptionName].(bool); verifyExists {
_, err := api.ResolveNode(req.Context, p)
if err != nil {
return err
}
}

output, err := publish(ctx, n, k, pth, popts)
out, err := api.Name().Publish(req.Context, p, opts...)
if err != nil {
if err == iface.ErrOffline {
err = errAllowOffline
}
return err
}

return cmds.EmitOnce(res, output)
return cmds.EmitOnce(res, &IpnsEntry{
Name: out.Name(),
Value: out.Value().String(),
})
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
Expand All @@ -175,72 +157,3 @@ Alternatively, publish an <ipfs-path> using a valid PeerID (as listed by
},
Type: IpnsEntry{},
}

type publishOpts struct {
verifyExists bool
pubValidTime time.Duration
}

func publish(ctx context.Context, n *core.IpfsNode, k crypto.PrivKey, ref path.Path, opts *publishOpts) (*IpnsEntry, error) {

if opts.verifyExists {
// verify the path exists
_, err := core.Resolve(ctx, n.Namesys, n.Resolver, ref)
if err != nil {
return nil, err
}
}

eol := time.Now().Add(opts.pubValidTime)
err := n.Namesys.PublishWithEOL(ctx, k, ref, eol)
if err != nil {
return nil, err
}

pid, err := peer.IDFromPrivateKey(k)
if err != nil {
return nil, err
}

return &IpnsEntry{
Name: pid.Pretty(),
Value: ref.String(),
}, nil
}

func keylookup(n *core.IpfsNode, k string) (crypto.PrivKey, error) {

res, err := n.GetKey(k)
if res != nil {
return res, nil
}

if err != nil && err != keystore.ErrNoSuchKey {
return nil, err
}

keys, err := n.Repo.Keystore().List()
if err != nil {
return nil, err
}

for _, key := range keys {
privKey, err := n.Repo.Keystore().Get(key)
if err != nil {
return nil, err
}

pubKey := privKey.GetPublic()

pid, err := peer.IDFromPublicKey(pubKey)
if err != nil {
return nil, err
}

if pid.Pretty() == k {
return privKey, nil
}
}

return nil, fmt.Errorf("no key by the given name or PeerID was found")
}
24 changes: 24 additions & 0 deletions core/coreapi/interface/options/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const (
type NamePublishSettings struct {
ValidTime time.Duration
Key string

TTL *time.Duration

AllowOffline bool
}

type NameResolveSettings struct {
Expand All @@ -29,6 +33,8 @@ func NamePublishOptions(opts ...NamePublishOption) (*NamePublishSettings, error)
options := &NamePublishSettings{
ValidTime: DefaultNameValidTime,
Key: "self",

AllowOffline: false,
}

for _, opt := range opts {
Expand Down Expand Up @@ -82,6 +88,24 @@ func (nameOpts) Key(key string) NamePublishOption {
}
}

// AllowOffline is an option for Name.Publish which specifies whether to allow
// publishing when the node is offline. Default value is false
func (nameOpts) AllowOffline(allow bool) NamePublishOption {
return func(settings *NamePublishSettings) error {
settings.AllowOffline = allow
return nil
}
}

// TTL is an option for Name.Publish which specifies the time duration the
// published record should be cached for (caution: experimental).
func (nameOpts) TTL(ttl time.Duration) NamePublishOption {
return func(settings *NamePublishSettings) error {
settings.TTL = &ttl
return nil
}
}

// Local is an option for Name.Resolve which specifies if the lookup should be
// offline. Default value is false
func (nameOpts) Local(local bool) NameResolveOption {
Expand Down
5 changes: 5 additions & 0 deletions core/coreapi/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package coreapi
import (
"context"
"crypto/rand"
"errors"
"fmt"
"sort"

Expand Down Expand Up @@ -218,5 +219,9 @@ func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, erro
}

func (api *KeyAPI) Self(ctx context.Context) (coreiface.Key, error) {
if api.node.Identity == "" {
return nil, errors.New("identity not loaded")
}

return &key{"self", api.node.Identity}, nil
}
7 changes: 7 additions & 0 deletions core/coreapi/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, opts ...caopt
n := api.node

if !n.OnlineMode() {
if !options.AllowOffline {
return nil, coreiface.ErrOffline
}
err := n.SetupOfflineRouting()
if err != nil {
return nil, err
Expand All @@ -65,6 +68,10 @@ func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, opts ...caopt
return nil, err
}

if options.TTL != nil {
ctx = context.WithValue(ctx, "ipns-publish-ttl", *options.TTL)
}

eol := time.Now().Add(options.ValidTime)
err = n.Namesys.PublishWithEOL(ctx, k, pth, eol)
if err != nil {
Expand Down