1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-05 07:29:02 +08:00

make publish more configurable and add test for repub

License: MIT
Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
Jeromy
2015-09-30 11:03:44 -07:00
parent e202c6592f
commit e5512b4115
9 changed files with 203 additions and 34 deletions

View File

@ -173,10 +173,13 @@ func (i *cmdInvocation) Run(ctx context.Context) (output io.Reader, err error) {
if err != nil {
return nil, err
}
if debug || u.GetenvBool("DEBUG") || os.Getenv("IPFS_LOGGING") == "debug" {
if debug || os.Getenv("IPFS_LOGGING") == "debug" {
u.Debug = true
logging.SetDebugLogging()
}
if u.GetenvBool("DEBUG") {
u.Debug = true
}
res, err := callCommand(ctx, i.req, Root, i.cmd)
if err != nil {
@ -668,6 +671,6 @@ func apiClientForAddr(addr ma.Multiaddr) (cmdsHttp.Client, error) {
}
func isConnRefused(err error) bool {
return strings.Contains(err.Error(), "connection refused") ||
strings.Contains(err.Error(), "target machine actively refused it")
return strings.Contains(err.Error(), "connection refused") ||
strings.Contains(err.Error(), "target machine actively refused it")
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"io"
"strings"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
@ -46,8 +47,11 @@ Publish an <ipfs-path> to another public key (not implemented):
},
Arguments: []cmds.Argument{
cmds.StringArg("name", false, false, "The IPNS name to publish to. Defaults to your node's peerID"),
cmds.StringArg("ipfs-path", true, false, "IPFS path of the obejct to be published at <name>").EnableStdin(),
cmds.StringArg("ipfs-path", true, false, "IPFS path of the obejct to be published").EnableStdin(),
},
Options: []cmds.Option{
cmds.BoolOption("resolve", "resolve given path before publishing (default=true)"),
cmds.StringOption("lifetime", "t", "time duration that the record will be valid for (default: 24hrs)"),
},
Run: func(req cmds.Request, res cmds.Response) {
log.Debug("Begin Publish")
@ -65,32 +69,34 @@ Publish an <ipfs-path> to another public key (not implemented):
}
}
args := req.Arguments()
pstr := req.Arguments()[0]
if n.Identity == "" {
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
return
}
var name string
var pstr string
switch len(args) {
case 2:
name = args[0]
pstr = args[1]
if name != n.Identity.Pretty() {
res.SetError(errors.New("keychains not yet implemented"), cmds.ErrNormal)
return
}
case 1:
// name = n.Identity.Pretty()
pstr = args[0]
popts := &publishOpts{
verifyExists: true,
pubValidTime: time.Hour * 24,
}
// TODO n.Keychain.Get(name).PrivKey
// TODO(cryptix): is req.Context().Context a child of n.Context()?
output, err := publish(req.Context(), n, n.PrivateKey, path.Path(pstr))
verif, found, _ := req.Option("resolve").Bool()
if found {
popts.verifyExists = verif
}
validtime, found, _ := req.Option("lifetime").String()
if found {
d, err := time.ParseDuration(validtime)
if err != nil {
res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmds.ErrNormal)
return
}
popts.pubValidTime = d
}
output, err := publish(req.Context(), n, n.PrivateKey, path.Path(pstr), popts)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
@ -107,14 +113,23 @@ Publish an <ipfs-path> to another public key (not implemented):
Type: IpnsEntry{},
}
func publish(ctx context.Context, n *core.IpfsNode, k crypto.PrivKey, ref path.Path) (*IpnsEntry, error) {
// First, verify the path exists
_, err := core.Resolve(ctx, n, ref)
if err != nil {
return nil, err
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, ref)
if err != nil {
return nil, err
}
}
err = n.Namesys.Publish(ctx, k, ref)
eol := time.Now().Add(opts.pubValidTime)
err := n.Namesys.PublishWithEOL(ctx, k, ref, eol)
if err != nil {
return nil, err
}

View File

@ -56,6 +56,7 @@ import (
pin "github.com/ipfs/go-ipfs/pin"
repo "github.com/ipfs/go-ipfs/repo"
config "github.com/ipfs/go-ipfs/repo/config"
u "github.com/ipfs/go-ipfs/util"
)
const IpnsValidatorTag = "ipns"
@ -229,26 +230,45 @@ func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost
n.Namesys = namesys.NewNameSystem(n.Routing)
// setup ipns republishing
n.IpnsRepub = ipnsrp.NewRepublisher(n.Routing, n.Repo.Datastore(), n.Peerstore)
n.IpnsRepub.AddName(n.Identity)
err = n.setupIpnsRepublisher()
if err != nil {
return err
}
return nil
}
func (n *IpfsNode) setupIpnsRepublisher() error {
cfg, err := n.Repo.Config()
if err != nil {
return err
}
n.IpnsRepub = ipnsrp.NewRepublisher(n.Routing, n.Repo.Datastore(), n.Peerstore)
n.IpnsRepub.AddName(n.Identity)
if cfg.Ipns.RepublishPeriod != "" {
d, err := time.ParseDuration(cfg.Ipns.RepublishPeriod)
if err != nil {
return fmt.Errorf("failure to parse config setting IPNS.RepublishPeriod: %s", err)
}
if d < time.Minute || d > (time.Hour*24) {
if !u.Debug && (d < time.Minute || d > (time.Hour*24)) {
return fmt.Errorf("config setting IPNS.RepublishPeriod is not between 1min and 1day: %s", d)
}
n.IpnsRepub.Interval = d
}
if cfg.Ipns.RecordLifetime != "" {
d, err := time.ParseDuration(cfg.Ipns.RepublishPeriod)
if err != nil {
return fmt.Errorf("failure to parse config setting IPNS.RecordLifetime: %s", err)
}
n.IpnsRepub.RecordLifetime = d
}
n.Process().Go(n.IpnsRepub.Run)
return nil

View File

@ -7,6 +7,7 @@ import (
"net/http/httptest"
"strings"
"testing"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
core "github.com/ipfs/go-ipfs/core"
@ -37,6 +38,10 @@ func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Pa
return errors.New("not implemented for mockNamesys")
}
func (m mockNamesys) PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, _ time.Time) error {
return errors.New("not implemented for mockNamesys")
}
func newNodeWithMockNamesys(ns mockNamesys) (*core.IpfsNode, error) {
c := config.Config{
Identity: config.Identity{

View File

@ -31,6 +31,7 @@ package namesys
import (
"errors"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
@ -105,4 +106,8 @@ type Publisher interface {
// Publish establishes a name-value mapping.
// TODO make this not PrivKey specific.
Publish(ctx context.Context, name ci.PrivKey, value path.Path) error
// TODO: to be replaced by a more generic 'PublishWithValidity' type
// call once the records spec is implemented
PublishWithEOL(ctx context.Context, name ci.PrivKey, value path.Path, eol time.Time) error
}

View File

@ -2,6 +2,7 @@ package namesys
import (
"strings"
"time"
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
ci "github.com/ipfs/go-ipfs/p2p/crypto"
@ -81,3 +82,7 @@ func (ns *mpns) resolveOnce(ctx context.Context, name string) (path.Path, error)
func (ns *mpns) Publish(ctx context.Context, name ci.PrivKey, value path.Path) error {
return ns.publishers["/ipns/"].Publish(ctx, name, value)
}
func (ns *mpns) PublishWithEOL(ctx context.Context, name ci.PrivKey, val path.Path, eol time.Time) error {
return ns.publishers["/ipns/"].PublishWithEOL(ctx, name, val, eol)
}

View File

@ -2,4 +2,5 @@ package config
type Ipns struct {
RepublishPeriod string
RecordLifetime string
}

View File

@ -56,13 +56,14 @@ test_expect_success "resolve output looks good" '
# publish with an explicit node ID
test_expect_success "'ipfs name publish <local-id> <hash>' succeeds" '
test_expect_failure "'ipfs name publish <local-id> <hash>' succeeds" '
PEERID=`ipfs id --format="<id>"` &&
test_check_peerid "${PEERID}" &&
echo ipfs name publish "${PEERID}" "/ipfs/$HASH_WELCOME_DOCS" &&
ipfs name publish "${PEERID}" "/ipfs/$HASH_WELCOME_DOCS" >actual_node_id_publish
'
test_expect_success "publish with our explicit node ID looks good" '
test_expect_failure "publish with our explicit node ID looks good" '
echo "Published to ${PEERID}: /ipfs/$HASH_WELCOME_DOCS" >expected_node_id_publish &&
test_cmp expected_node_id_publish actual_node_id_publish
'

View File

@ -0,0 +1,114 @@
#!/bin/sh
#
# Copyright (c) 2014 Jeromy Johnson
# MIT Licensed; see the LICENSE file in this repository.
#
test_description="Test ipfs repo operations"
. lib/test-lib.sh
export IPTB_ROOT="`pwd`/.iptb"
export DEBUG=true
ipfsi() {
local dir=$1; shift; IPFS_PATH="$IPTB_ROOT/$dir" ipfs $@
}
setup_iptb() {
test_expect_success "iptb init" '
iptb init -n4 --bootstrap none --port 0
'
test_expect_success "set configs up" '
for i in `seq 0 3`
do
ipfsi $i config Ipns.RepublishPeriod 20s
done
'
test_expect_success "start up nodes" '
iptb start
'
test_expect_success "connect nodes" '
iptb connect 0 1 &&
iptb connect 0 2 &&
iptb connect 0 3
'
test_expect_success "nodes have connections" '
ipfsi 0 swarm peers | grep ipfs &&
ipfsi 1 swarm peers | grep ipfs &&
ipfsi 2 swarm peers | grep ipfs &&
ipfsi 3 swarm peers | grep ipfs
'
}
teardown_iptb() {
test_expect_success "shut down nodes" '
iptb kill
'
}
verify_can_resolve() {
node=$1
name=$2
expected=$3
test_expect_success "node can resolve entry" '
ipfsi $node name resolve $name > resolve
'
test_expect_success "output looks right" '
printf /ipfs/$expected > expected &&
test_cmp resolve expected
'
}
verify_cannot_resolve() {
node=$1
name=$2
echo "verifying resolution fails on node $node"
test_expect_success "node cannot resolve entry" '
# TODO: this should work without the timeout option
# but it currently hangs for some reason every so often
test_expect_code 1 ipfsi $node name resolve --timeout=300ms $name
'
}
setup_iptb
test_expect_success "publish succeeds" '
HASH=$(echo "foobar" | ipfsi 1 add -q) &&
ipfsi 1 name publish -t 5s $HASH
'
test_expect_success "other nodes can resolve" '
id=$(ipfsi 1 id -f "<id>") &&
verify_can_resolve 0 $id $HASH &&
verify_can_resolve 1 $id $HASH &&
verify_can_resolve 2 $id $HASH &&
verify_can_resolve 3 $id $HASH
'
test_expect_success "after five seconds, records are invalid" '
go-sleep 5s &&
verify_cannot_resolve 0 $id &&
verify_cannot_resolve 1 $id &&
verify_cannot_resolve 2 $id &&
verify_cannot_resolve 3 $id
'
test_expect_success "republisher fires after twenty seconds" '
go-sleep 15s &&
verify_can_resolve 0 $id $HASH &&
verify_can_resolve 1 $id $HASH &&
verify_can_resolve 2 $id $HASH &&
verify_can_resolve 3 $id $HASH
'
teardown_iptb
test_done