Merge branch 'master' into feat/namestream

License: MIT
Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
This commit is contained in:
Łukasz Magiera 2018-10-10 12:10:12 +02:00
commit 0bef4603e8
170 changed files with 4258 additions and 1757 deletions

View File

@ -5,3 +5,9 @@ Dockerfile.fast
!.git/refs/
!.git/packed-refs
test/sharness/lib/sharness/
# The Docker client might not be running on Linux
# so delete any compiled binaries
bin/gx
bin/gx*
bin/tmp

View File

@ -12,7 +12,7 @@ import (
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/core/coreunix"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
// this import keeps gx from thinking the dep isn't used
_ "gx/ipfs/QmdZ4PvPHFQVLLEve7DgoKDcSY19wwpGBB1GKjjKi2rEL1/dir-index-html"

View File

@ -8,8 +8,8 @@ import (
"github.com/ipfs/go-ipfs/pin"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
ds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
bs "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
ds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
bs "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
)
// RemovedBlock is used to respresent the result of removing a block.

View File

@ -412,22 +412,32 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
return nil, fmt.Errorf("serveHTTPApi: GetConfig() failed: %s", err)
}
apiAddrs := make([]string, 0, 2)
apiAddr, _ := req.Options[commands.ApiOption].(string)
if apiAddr == "" {
apiAddr = cfg.Addresses.API
}
apiMaddr, err := ma.NewMultiaddr(apiAddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", apiAddr, err)
apiAddrs = cfg.Addresses.API
} else {
apiAddrs = append(apiAddrs, apiAddr)
}
apiLis, err := manet.Listen(apiMaddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: manet.Listen(%s) failed: %s", apiMaddr, err)
listeners := make([]manet.Listener, 0, len(apiAddrs))
for _, addr := range apiAddrs {
apiMaddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: invalid API address: %q (err: %s)", apiAddr, err)
}
apiLis, err := manet.Listen(apiMaddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPApi: manet.Listen(%s) failed: %s", apiMaddr, err)
}
// we might have listened to /tcp/0 - lets see what we are listing on
apiMaddr = apiLis.Multiaddr()
fmt.Printf("API server listening on %s\n", apiMaddr)
listeners = append(listeners, apiLis)
}
// we might have listened to /tcp/0 - lets see what we are listing on
apiMaddr = apiLis.Multiaddr()
fmt.Printf("API server listening on %s\n", apiMaddr)
// by default, we don't let you load arbitrary ipfs objects through the api,
// because this would open up the api to scripting vulnerabilities.
@ -462,15 +472,25 @@ func serveHTTPApi(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, error
return nil, fmt.Errorf("serveHTTPApi: ConstructNode() failed: %s", err)
}
if err := node.Repo.SetAPIAddr(apiMaddr); err != nil {
if err := node.Repo.SetAPIAddr(listeners[0].Multiaddr()); err != nil {
return nil, fmt.Errorf("serveHTTPApi: SetAPIAddr() failed: %s", err)
}
errc := make(chan error)
var wg sync.WaitGroup
for _, apiLis := range listeners {
wg.Add(1)
go func(lis manet.Listener) {
defer wg.Done()
errc <- corehttp.Serve(node, manet.NetListener(lis), opts...)
}(apiLis)
}
go func() {
errc <- corehttp.Serve(node, manet.NetListener(apiLis), opts...)
wg.Wait()
close(errc)
}()
return errc, nil
}
@ -512,27 +532,33 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
return nil, fmt.Errorf("serveHTTPGateway: GetConfig() failed: %s", err)
}
gatewayMaddr, err := ma.NewMultiaddr(cfg.Addresses.Gateway)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: invalid gateway address: %q (err: %s)", cfg.Addresses.Gateway, err)
}
writable, writableOptionFound := req.Options[writableKwd].(bool)
if !writableOptionFound {
writable = cfg.Gateway.Writable
}
gwLis, err := manet.Listen(gatewayMaddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: manet.Listen(%s) failed: %s", gatewayMaddr, err)
}
// we might have listened to /tcp/0 - lets see what we are listing on
gatewayMaddr = gwLis.Multiaddr()
gatewayAddrs := cfg.Addresses.Gateway
listeners := make([]manet.Listener, 0, len(gatewayAddrs))
for _, addr := range gatewayAddrs {
gatewayMaddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: invalid gateway address: %q (err: %s)", addr, err)
}
if writable {
fmt.Printf("Gateway (writable) server listening on %s\n", gatewayMaddr)
} else {
fmt.Printf("Gateway (readonly) server listening on %s\n", gatewayMaddr)
gwLis, err := manet.Listen(gatewayMaddr)
if err != nil {
return nil, fmt.Errorf("serveHTTPGateway: manet.Listen(%s) failed: %s", gatewayMaddr, err)
}
// we might have listened to /tcp/0 - lets see what we are listing on
gatewayMaddr = gwLis.Multiaddr()
if writable {
fmt.Printf("Gateway (writable) server listening on %s\n", gatewayMaddr)
} else {
fmt.Printf("Gateway (readonly) server listening on %s\n", gatewayMaddr)
}
listeners = append(listeners, gwLis)
}
var opts = []corehttp.ServeOption{
@ -554,10 +580,20 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
}
errc := make(chan error)
var wg sync.WaitGroup
for _, lis := range listeners {
wg.Add(1)
go func(lis manet.Listener) {
defer wg.Done()
errc <- corehttp.Serve(node, manet.NetListener(lis), opts...)
}(lis)
}
go func() {
errc <- corehttp.Serve(node, manet.NetListener(gwLis), opts...)
wg.Wait()
close(errc)
}()
return errc, nil
}

View File

@ -17,7 +17,7 @@ import (
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
"gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
"gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
)

View File

@ -92,4 +92,5 @@ var cmdDetailsMap = map[string]cmdDetails{
"diag/cmds": {cannotRunOnClient: true},
"repo/fsck": {cannotRunOnDaemon: true},
"config/edit": {cannotRunOnDaemon: true, doesNotUseRepo: true},
"cid": {doesNotUseRepo: true},
}

View File

@ -26,8 +26,8 @@ import (
loggables "gx/ipfs/QmNLzS18jsmwTxXewTm3YnZVLftWCeegNZEBFjMrnvnBrH/go-libp2p-loggables"
u "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util"
"gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
manet "gx/ipfs/QmV6FjemM1K8oXjrvuq3wuVWWoU2TLDPmNnKrxHzY3v6Ai/go-multiaddr-net"
"gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds/cli"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds/http"

View File

@ -16,7 +16,7 @@ import (
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
process "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
homedir "gx/ipfs/QmdcULN1WCzgoQmcCaUAmEhwcxHYsDrbZ2LvRJKCL8dMrK/go-homedir"
fsnotify "gx/ipfs/QmfNjggF4Pt6erqg3NDafD3MdvDHk1qqCVr8pL5hnPucS8/fsnotify"
)

View File

@ -19,12 +19,12 @@ import (
"os/signal"
"syscall"
secio "gx/ipfs/QmPJ6U14u5D2abGVkF3dopCeM1JqigVTUJ7jbAHjTnGZrt/go-libp2p-secio"
ci "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
pstoremem "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore/pstoremem"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
secio "gx/ipfs/QmZSHe9kqEcqUG6DSBrKYULk8EeZLDd1skpHNoSaK6rW4M/go-libp2p-secio"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
pstoremem "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore/pstoremem"
)
var verbose = false

View File

@ -12,7 +12,7 @@ import (
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
)

View File

@ -12,14 +12,14 @@ import (
math2 "github.com/ipfs/go-ipfs/thirdparty/math2"
lgbl "gx/ipfs/QmNLzS18jsmwTxXewTm3YnZVLftWCeegNZEBFjMrnvnBrH/go-libp2p-loggables"
host "gx/ipfs/QmQKod7iLxQK6X3aFYvhDDnFdXo3QjxKeL2F7UrPtdKQR2/go-libp2p-host"
goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
procctx "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess/context"
periodicproc "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess/periodic"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
inet "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
host "gx/ipfs/QmeA5hsqgLryvkeyqeQdvGDqurLkYi3XEPLZP3pzuBJXh2/go-libp2p-host"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
inet "gx/ipfs/QmfDPh144WGBqRxZb1TGDHerbMnZATrHZggAPw7putNnBq/go-libp2p-net"
)
// ErrNotEnoughBootstrapPeers signals that we do not have enough bootstrap

View File

@ -5,8 +5,8 @@ import (
"testing"
testutil "gx/ipfs/QmNfQbgBfARAtrYsBguChX6VJ5nbjeoYy1KdC36aaYWqG8/go-testutil"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
)
func TestSubsetWhenMaxIsGreaterThanLengthOfSlice(t *testing.T) {

View File

@ -14,27 +14,27 @@ import (
repo "github.com/ipfs/go-ipfs/repo"
cidv0v1 "github.com/ipfs/go-ipfs/thirdparty/cidv0v1"
"github.com/ipfs/go-ipfs/thirdparty/verifbs"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
bserv "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
resolver "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path/resolver"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bserv "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
ci "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
p2phost "gx/ipfs/QmQKod7iLxQK6X3aFYvhDDnFdXo3QjxKeL2F7UrPtdKQR2/go-libp2p-host"
goprocessctx "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess/context"
record "gx/ipfs/QmSb4B8ZAAj5ALe9LjfzPyF8Ma6ezC1NTnDF2JQPUJxEXb/go-libp2p-record"
ds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
retry "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/retrystore"
dsync "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
cfg "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
libp2p "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p"
ipns "gx/ipfs/QmZrmn2BPZbSviQAWeyY2iXkCukmJHv9n7zrLgWU5KgbTb/go-ipns"
cfg "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
libp2p "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p"
ipns "gx/ipfs/QmWhm9qS3NZdvTgAsB1cX4q9UbNu8yFybCcAMchCN88w7o/go-ipns"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
pstoremem "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore/pstoremem"
ds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
retry "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/retrystore"
dsync "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
p2phost "gx/ipfs/QmeA5hsqgLryvkeyqeQdvGDqurLkYi3XEPLZP3pzuBJXh2/go-libp2p-host"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
metrics "gx/ipfs/QmekzFM3hPZjTjUFGTABdQkEnQ3PTiMstY198PwSFr5w1Q/go-metrics-interface"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
pstoremem "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore/pstoremem"
)
type BuildCfg struct {

View File

@ -14,6 +14,10 @@ import (
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
)
const (
verboseOptionName = "v"
)
var ActiveReqsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List commands run on this IPFS node.",
@ -25,7 +29,7 @@ Lists running and recently run commands.
res.SetOutput(req.InvocContext().ReqLog.Report())
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("verbose", verboseOptionName, "Print extra information."),
},
Subcommands: map[string]*cmds.Command{
"clear": clearInactiveCmd,
@ -44,7 +48,7 @@ Lists running and recently run commands.
}
buf := new(bytes.Buffer)
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(verboseOptionName).Bool()
w := tabwriter.NewWriter(buf, 4, 4, 2, ' ', 0)
if verbose {

View File

@ -6,24 +6,15 @@ import (
"os"
"strings"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/core/coreunix"
filestore "github.com/ipfs/go-ipfs/filestore"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
dagtest "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag/test"
blockservice "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
pb "gx/ipfs/QmPtj12fdwuAqj9sBSTNUxBNu8kCGNp8b3o8yUzMm5GHpq/pb"
cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
mfs "gx/ipfs/QmahrY1adY4wvtYEtoGjpZ2GUohTyukrkMkwUR9ytRjTG2/go-mfs"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
)
// ErrDepthLimitExceeded indicates that the max depth has been exceeded.
@ -148,23 +139,11 @@ You can now check what blocks have been created by:
return nil
},
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
}
cfg, err := n.Repo.Config()
if err != nil {
return err
}
// check if repo will exceed storage limit if added
// TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated)
// TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon
//if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil {
// res.SetError(err, cmdkit.ErrNormal)
// return
//}
progress, _ := req.Options[progressOptionName].(bool)
trickle, _ := req.Options[trickleOptionName].(bool)
wrap, _ := req.Options[wrapOptionName].(bool)
@ -181,161 +160,59 @@ You can now check what blocks have been created by:
inline, _ := req.Options[inlineOptionName].(bool)
inlineLimit, _ := req.Options[inlineLimitOptionName].(int)
pathName, _ := req.Options[stdinPathName].(string)
// The arguments are subject to the following constraints.
//
// nocopy -> filestoreEnabled
// nocopy -> rawblocks
// (hash != sha2-256) -> cidv1
// NOTE: 'rawblocks -> cidv1' is missing. Legacy reasons.
// nocopy -> filestoreEnabled
if nocopy && !cfg.Experimental.FilestoreEnabled {
return cmdkit.Errorf(cmdkit.ErrClient, filestore.ErrFilestoreNotEnabled.Error())
}
// nocopy -> rawblocks
if nocopy && !rawblks {
// fixed?
if rbset {
return fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well")
}
// No, satisfy mandatory constraint.
rawblks = true
}
// (hash != "sha2-256") -> CIDv1
if hashFunStr != "sha2-256" && cidVer == 0 {
if cidVerSet {
return cmdkit.Errorf(cmdkit.ErrClient, "CIDv0 only supports sha2-256")
}
cidVer = 1
}
// cidV1 -> raw blocks (by default)
if cidVer > 0 && !rbset {
rawblks = true
}
prefix, err := dag.PrefixForCidVersion(cidVer)
if err != nil {
return err
}
local, _ := req.Options["local"].(bool)
hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)]
if !ok {
return fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr))
}
prefix.MhType = hashFunCode
prefix.MhLength = -1
events := make(chan interface{}, adderOutChanSize)
if hash {
nilnode, err := core.NewNode(n.Context(), &core.BuildCfg{
//TODO: need this to be true or all files
// hashed will be stored in memory!
NilRepo: true,
})
if err != nil {
return err
}
n = nilnode
opts := []options.UnixfsAddOption{
options.Unixfs.Hash(hashFunCode),
options.Unixfs.Inline(inline),
options.Unixfs.InlineLimit(inlineLimit),
options.Unixfs.Chunker(chunker),
options.Unixfs.Pin(dopin),
options.Unixfs.HashOnly(hash),
options.Unixfs.Local(local),
options.Unixfs.FsCache(fscache),
options.Unixfs.Nocopy(nocopy),
options.Unixfs.Wrap(wrap),
options.Unixfs.Hidden(hidden),
options.Unixfs.StdinName(pathName),
options.Unixfs.Progress(progress),
options.Unixfs.Silent(silent),
options.Unixfs.Events(events),
}
addblockstore := n.Blockstore
if !(fscache || nocopy) {
addblockstore = bstore.NewGCBlockstore(n.BaseBlocks, n.GCLocker)
if cidVerSet {
opts = append(opts, options.Unixfs.CidVersion(cidVer))
}
exch := n.Exchange
local, _ := req.Options["local"].(bool)
if local {
exch = offline.Exchange(addblockstore)
if rbset {
opts = append(opts, options.Unixfs.RawLeaves(rawblks))
}
bserv := blockservice.New(addblockstore, exch) // hash security 001
dserv := dag.NewDAGService(bserv)
outChan := make(chan interface{}, adderOutChanSize)
fileAdder, err := coreunix.NewAdder(req.Context, n.Pinning, n.Blockstore, dserv)
if err != nil {
return err
}
fileAdder.Out = outChan
fileAdder.Chunker = chunker
fileAdder.Progress = progress
fileAdder.Hidden = hidden
fileAdder.Trickle = trickle
fileAdder.Wrap = wrap
fileAdder.Pin = dopin
fileAdder.Silent = silent
fileAdder.RawLeaves = rawblks
fileAdder.NoCopy = nocopy
fileAdder.Name = pathName
fileAdder.CidBuilder = prefix
if inline {
fileAdder.CidBuilder = cidutil.InlineBuilder{
Builder: fileAdder.CidBuilder,
Limit: inlineLimit,
}
}
if hash {
md := dagtest.Mock()
emptyDirNode := ft.EmptyDirNode()
// Use the same prefix for the "empty" MFS root as for the file adder.
emptyDirNode.SetCidBuilder(fileAdder.CidBuilder)
mr, err := mfs.NewRoot(req.Context, md, emptyDirNode, nil)
if err != nil {
return err
}
fileAdder.SetMfsRoot(mr)
}
addAllAndPin := func(f files.File) error {
// Iterate over each top-level file and add individually. Otherwise the
// single files.File f is treated as a directory, affecting hidden file
// semantics.
for {
file, err := f.NextFile()
if err == io.EOF {
// Finished the list of files.
break
} else if err != nil {
return err
}
if err := fileAdder.AddFile(file); err != nil {
return err
}
}
// copy intermediary nodes from editor to our actual dagservice
_, err := fileAdder.Finalize()
if err != nil {
return err
}
if hash {
return nil
}
return fileAdder.PinRoot()
if trickle {
opts = append(opts, options.Unixfs.Layout(options.TrickleLayout))
}
errCh := make(chan error)
go func() {
var err error
defer func() { errCh <- err }()
defer close(outChan)
err = addAllAndPin(req.Files)
defer close(events)
_, err = api.Unixfs().Add(req.Context, req.Files, opts...)
}()
err = res.Emit(outChan)
err = res.Emit(events)
if err != nil {
return err
}
@ -401,7 +278,7 @@ You can now check what blocks have been created by:
break LOOP
}
output := out.(*coreunix.AddedObject)
output := out.(*coreiface.AddEvent)
if len(output.Hash) > 0 {
lastHash = output.Hash
if quieter {
@ -481,5 +358,5 @@ You can now check what blocks have been created by:
}
},
},
Type: coreunix.AddedObject{},
Type: coreiface.AddEvent{},
}

View File

@ -9,8 +9,8 @@ import (
lgc "github.com/ipfs/go-ipfs/commands/legacy"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
e "github.com/ipfs/go-ipfs/core/commands/e"
bitswap "gx/ipfs/QmUdtRsAr9RYxqNwUzeHDhv5bnVppiHLixP1SU4YysVj2S/go-bitswap"
decision "gx/ipfs/QmUdtRsAr9RYxqNwUzeHDhv5bnVppiHLixP1SU4YysVj2S/go-bitswap/decision"
bitswap "gx/ipfs/QmQHbKeMWRNT8koMhh2DrTXZWepYVoGPNXni6JG1L3BhGq/go-bitswap"
decision "gx/ipfs/QmQHbKeMWRNT8koMhh2DrTXZWepYVoGPNXni6JG1L3BhGq/go-bitswap/decision"
"gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
@ -32,6 +32,10 @@ var BitswapCmd = &cmds.Command{
},
}
const (
peerOptionName = "peer"
)
var showWantlistCmd = &oldcmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Show blocks currently on the wantlist.",
@ -39,7 +43,7 @@ var showWantlistCmd = &oldcmds.Command{
Print out all blocks currently on the bitswap wantlist for the local peer.`,
},
Options: []cmdkit.Option{
cmdkit.StringOption("peer", "p", "Specify which peer to show wantlist for. Default: self."),
cmdkit.StringOption(peerOptionName, "p", "Specify which peer to show wantlist for. Default: self."),
},
Type: KeyList{},
Run: func(req oldcmds.Request, res oldcmds.Response) {
@ -60,7 +64,7 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`,
return
}
pstr, found, err := req.Option("peer").String()
pstr, found, err := req.Option(peerOptionName).String()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return

View File

@ -126,6 +126,12 @@ It outputs to stdout, and <key> is a base58 encoded multihash.
},
}
const (
blockFormatOptionName = "format"
mhtypeOptionName = "mhtype"
mhlenOptionName = "mhlen"
)
var blockPutCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Store input as an IPFS block.",
@ -142,9 +148,9 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1.
cmdkit.FileArg("data", true, false, "The data to be stored as an IPFS block.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.StringOption("format", "f", "cid format for blocks to be created with."),
cmdkit.StringOption("mhtype", "multihash hash function").WithDefault("sha2-256"),
cmdkit.IntOption("mhlen", "multihash hash length").WithDefault(-1),
cmdkit.StringOption(blockFormatOptionName, "f", "cid format for blocks to be created with."),
cmdkit.StringOption(mhtypeOptionName, "multihash hash function").WithDefault("sha2-256"),
cmdkit.IntOption(mhlenOptionName, "multihash hash length").WithDefault(-1),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
@ -157,18 +163,18 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1.
return err
}
mhtype, _ := req.Options["mhtype"].(string)
mhtype, _ := req.Options[mhtypeOptionName].(string)
mhtval, ok := mh.Names[mhtype]
if !ok {
return fmt.Errorf("unrecognized multihash function: %s", mhtype)
}
mhlen, ok := req.Options["mhlen"].(int)
mhlen, ok := req.Options[mhlenOptionName].(int)
if !ok {
return errors.New("missing option \"mhlen\"")
}
format, formatSet := req.Options["format"].(string)
format, formatSet := req.Options[blockFormatOptionName].(string)
if !formatSet {
if mhtval != mh.SHA2_256 || (mhlen != -1 && mhlen != 32) {
format = "protobuf"
@ -200,6 +206,11 @@ than 'sha2-256' or format to anything other than 'v0' will result in CIDv1.
Type: BlockStat{},
}
const (
forceOptionName = "force"
blockQuietOptionName = "quiet"
)
var blockRmCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Remove IPFS block(s).",
@ -212,8 +223,8 @@ It takes a list of base58 encoded multihashes to remove.
cmdkit.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("force", "f", "Ignore nonexistent blocks."),
cmdkit.BoolOption("quiet", "q", "Write minimal output."),
cmdkit.BoolOption(forceOptionName, "f", "Ignore nonexistent blocks."),
cmdkit.BoolOption(blockQuietOptionName, "q", "Write minimal output."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
@ -221,8 +232,8 @@ It takes a list of base58 encoded multihashes to remove.
return err
}
force, _ := req.Options["force"].(bool)
quiet, _ := req.Options["quiet"].(bool)
force, _ := req.Options[forceOptionName].(bool)
quiet, _ := req.Options[blockQuietOptionName].(bool)
// TODO: use batching coreapi when done
for _, b := range req.Arguments {

View File

@ -12,7 +12,7 @@ import (
"github.com/ipfs/go-ipfs/repo/fsrepo"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
)
type BootstrapOutput struct {
@ -40,6 +40,10 @@ Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
},
}
const (
defaultOptionName = "default"
)
var bootstrapAddCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Add peers to the bootstrap list.",
@ -53,14 +57,14 @@ in the bootstrap list).
},
Options: []cmdkit.Option{
cmdkit.BoolOption("default", "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"),
cmdkit.BoolOption(defaultOptionName, "Add default bootstrap nodes. (Deprecated, use 'default' subcommand instead)"),
},
Subcommands: map[string]*cmds.Command{
"default": bootstrapAddDefaultCmd,
},
Run: func(req cmds.Request, res cmds.Response) {
deflt, _, err := req.Option("default").Bool()
deflt, _, err := req.Option(defaultOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -191,6 +195,10 @@ in the bootstrap list).`,
},
}
const (
bootstrapAllOptionName = "all"
)
var bootstrapRemoveCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Remove peers from the bootstrap list.",
@ -202,13 +210,13 @@ var bootstrapRemoveCmd = &cmds.Command{
cmdkit.StringArg("peer", false, true, peerOptionDesc).EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("all", "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"),
cmdkit.BoolOption(bootstrapAllOptionName, "Remove all bootstrap peers. (Deprecated, use 'all' subcommand)"),
},
Subcommands: map[string]*cmds.Command{
"all": bootstrapRemoveAllCmd,
},
Run: func(req cmds.Request, res cmds.Response) {
all, _, err := req.Option("all").Bool()
all, _, err := req.Option(bootstrapAllOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return

View File

@ -6,15 +6,18 @@ import (
"io"
"os"
core "github.com/ipfs/go-ipfs/core"
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
)
const progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
const (
progressBarMinSize = 1024 * 1024 * 8 // show progress bar for outputs > 8MiB
offsetOptionName = "offset"
lengthOptionName = "length"
)
var CatCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
@ -26,8 +29,8 @@ var CatCmd = &cmds.Command{
cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.IntOption("offset", "o", "Byte offset to begin reading from."),
cmdkit.IntOption("length", "l", "Maximum number of bytes to read."),
cmdkit.IntOption(offsetOptionName, "o", "Byte offset to begin reading from."),
cmdkit.IntOption(lengthOptionName, "l", "Maximum number of bytes to read."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
node, err := cmdenv.GetNode(env)
@ -35,18 +38,23 @@ var CatCmd = &cmds.Command{
return err
}
api, err := cmdenv.GetApi(env)
if err != nil {
return err
}
if !node.OnlineMode() {
if err := node.SetupOfflineRouting(); err != nil {
return err
}
}
offset, _ := req.Options["offset"].(int)
offset, _ := req.Options[offsetOptionName].(int)
if offset < 0 {
return fmt.Errorf("cannot specify negative offset")
}
max, found := req.Options["length"].(int)
max, found := req.Options[lengthOptionName].(int)
if err != nil {
return err
}
@ -62,7 +70,7 @@ var CatCmd = &cmds.Command{
return err
}
readers, length, err := cat(req.Context, node, req.Arguments, int64(offset), int64(max))
readers, length, err := cat(req.Context, api, req.Arguments, int64(offset), int64(max))
if err != nil {
return err
}
@ -115,14 +123,19 @@ var CatCmd = &cmds.Command{
},
}
func cat(ctx context.Context, node *core.IpfsNode, paths []string, offset int64, max int64) ([]io.Reader, uint64, error) {
func cat(ctx context.Context, api iface.CoreAPI, paths []string, offset int64, max int64) ([]io.Reader, uint64, error) {
readers := make([]io.Reader, 0, len(paths))
length := uint64(0)
if max == 0 {
return nil, 0, nil
}
for _, fpath := range paths {
read, err := coreunix.Cat(ctx, node, fpath)
for _, p := range paths {
fpath, err := iface.ParsePath(p)
if err != nil {
return nil, 0, err
}
read, err := api.Unixfs().Cat(ctx, fpath)
if err != nil {
return nil, 0, err
}

364
core/commands/cid.go Normal file
View File

@ -0,0 +1,364 @@
package commands
import (
"fmt"
"io"
"sort"
"strings"
"unicode"
"github.com/ipfs/go-ipfs/core/commands/e"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mhash "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
verifcid "gx/ipfs/QmVkMRSkXrpjqrroEXWuYBvDBnXCdMMY6gsKicBGVGUqKT/go-verifcid"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
)
var CidCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Convert and discover properties of CIDs",
},
Subcommands: map[string]*cmds.Command{
"format": cidFmtCmd,
"base32": base32Cmd,
"bases": basesCmd,
"codecs": codecsCmd,
"hashes": hashesCmd,
},
}
const (
cidFormatOptionName = "f"
cidVerisonOptionName = "v"
cidMultibaseOptionName = "b"
)
var cidFmtCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Format and convert a CID in various useful ways.",
LongDescription: `
Format and converts <cid>'s in various useful ways.
The optional format string is a printf style format string:
` + cidutil.FormatRef,
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("cid", true, true, "Cids to format.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.StringOption(cidFormatOptionName, "Printf style format string.").WithDefault("%s"),
cmdkit.StringOption(cidVerisonOptionName, "CID version to convert to."),
cmdkit.StringOption(cidMultibaseOptionName, "Multibase to display CID in."),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
fmtStr, _ := req.Options[cidFormatOptionName].(string)
verStr, _ := req.Options[cidVerisonOptionName].(string)
baseStr, _ := req.Options[cidMultibaseOptionName].(string)
opts := cidFormatOpts{}
if strings.IndexByte(fmtStr, '%') == -1 {
return fmt.Errorf("invalid format string: %s", fmtStr)
}
opts.fmtStr = fmtStr
switch verStr {
case "":
// noop
case "0":
opts.verConv = toCidV0
case "1":
opts.verConv = toCidV1
default:
return fmt.Errorf("invalid cid version: %s", verStr)
}
if baseStr != "" {
encoder, err := mbase.EncoderByName(baseStr)
if err != nil {
return err
}
opts.newBase = encoder.Encoding()
} else {
opts.newBase = mbase.Encoding(-1)
}
return emitCids(req, resp, opts)
},
PostRun: cmds.PostRunMap{
cmds.CLI: streamResult(func(v interface{}, out io.Writer) nonFatalError {
r := v.(*CidFormatRes)
if r.ErrorMsg != "" {
return nonFatalError(fmt.Sprintf("%s: %s", r.CidStr, r.ErrorMsg))
}
fmt.Fprintf(out, "%s\n", r.Formatted)
return ""
}),
},
Type: CidFormatRes{},
}
type CidFormatRes struct {
CidStr string // Original Cid String passed in
Formatted string // Formated Result
ErrorMsg string // Error
}
var base32Cmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Convert CIDs to Base32 CID version 1.",
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("cid", true, true, "Cids to convert.").EnableStdin(),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
opts := cidFormatOpts{
fmtStr: "%s",
newBase: mbase.Encoding(mbase.Base32),
verConv: toCidV1,
}
return emitCids(req, resp, opts)
},
PostRun: cidFmtCmd.PostRun,
Type: cidFmtCmd.Type,
}
type cidFormatOpts struct {
fmtStr string
newBase mbase.Encoding
verConv func(cid cid.Cid) (cid.Cid, error)
}
type argumentIterator struct {
args []string
body cmds.StdinArguments
}
func (i *argumentIterator) next() (string, bool) {
if len(i.args) > 0 {
arg := i.args[0]
i.args = i.args[1:]
return arg, true
}
if i.body == nil || !i.body.Scan() {
return "", false
}
return strings.TrimSpace(i.body.Argument()), true
}
func (i *argumentIterator) err() error {
if i.body == nil {
return nil
}
return i.body.Err()
}
func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts) error {
itr := argumentIterator{req.Arguments, req.BodyArgs()}
var emitErr error
for emitErr == nil {
cidStr, ok := itr.next()
if !ok {
break
}
res := &CidFormatRes{CidStr: cidStr}
c, err := cid.Decode(cidStr)
if err != nil {
res.ErrorMsg = err.Error()
emitErr = resp.Emit(res)
continue
}
base := opts.newBase
if base == -1 {
base, _ = cid.ExtractEncoding(cidStr)
}
if opts.verConv != nil {
c, err = opts.verConv(c)
if err != nil {
res.ErrorMsg = err.Error()
emitErr = resp.Emit(res)
continue
}
}
str, err := cidutil.Format(opts.fmtStr, base, c)
if _, ok := err.(cidutil.FormatStringError); ok {
// no point in continuing if there is a problem with the format string
return err
}
if err != nil {
res.ErrorMsg = err.Error()
} else {
res.Formatted = str
}
emitErr = resp.Emit(res)
}
if emitErr != nil {
return emitErr
}
err := itr.err()
if err != nil {
return err
}
return nil
}
func toCidV0(c cid.Cid) (cid.Cid, error) {
if c.Type() != cid.DagProtobuf {
return cid.Cid{}, fmt.Errorf("can't convert non-protobuf nodes to cidv0")
}
return cid.NewCidV0(c.Hash()), nil
}
func toCidV1(c cid.Cid) (cid.Cid, error) {
return cid.NewCidV1(c.Type(), c.Hash()), nil
}
type CodeAndName struct {
Code int
Name string
}
const (
prefixOptionName = "prefix"
numericOptionName = "numeric"
)
var basesCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List available multibase encodings.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption(prefixOptionName, "also include the single leter prefixes in addition to the code"),
cmdkit.BoolOption(numericOptionName, "also include numeric codes"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
var res []CodeAndName
// use EncodingToStr in case at some point there are multiple names for a given code
for code, name := range mbase.EncodingToStr {
res = append(res, CodeAndName{int(code), name})
}
cmds.EmitOnce(resp, res)
return nil
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
prefixes, _ := req.Options[prefixOptionName].(bool)
numeric, _ := req.Options[numericOptionName].(bool)
val, ok := val0.([]CodeAndName)
if !ok {
return e.TypeErr(val, val0)
}
sort.Sort(multibaseSorter{val})
for _, v := range val {
code := v.Code
if code < 32 || code >= 127 {
// don't display non-printable prefixes
code = ' '
}
switch {
case prefixes && numeric:
fmt.Fprintf(w, "%c %5d %s\n", code, v.Code, v.Name)
case prefixes:
fmt.Fprintf(w, "%c %s\n", code, v.Name)
case numeric:
fmt.Fprintf(w, "%5d %s\n", v.Code, v.Name)
default:
fmt.Fprintf(w, "%s\n", v.Name)
}
}
return nil
}),
},
Type: []CodeAndName{},
}
const (
codecsNumericOptionName = "numeric"
)
var codecsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List available CID codecs.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption(codecsNumericOptionName, "also include numeric codes"),
},
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
var res []CodeAndName
// use CodecToStr as there are multiple names for a given code
for code, name := range cid.CodecToStr {
res = append(res, CodeAndName{int(code), name})
}
cmds.EmitOnce(resp, res)
return nil
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, val0 interface{}) error {
numeric, _ := req.Options[codecsNumericOptionName].(bool)
val, ok := val0.([]CodeAndName)
if !ok {
return e.TypeErr(val, val0)
}
sort.Sort(codeAndNameSorter{val})
for _, v := range val {
if numeric {
fmt.Fprintf(w, "%5d %s\n", v.Code, v.Name)
} else {
fmt.Fprintf(w, "%s\n", v.Name)
}
}
return nil
}),
},
Type: []CodeAndName{},
}
var hashesCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List available multihashes.",
},
Options: codecsCmd.Options,
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
var res []CodeAndName
// use mhash.Codes in case at some point there are multiple names for a given code
for code, name := range mhash.Codes {
if !verifcid.IsGoodHash(code) {
continue
}
res = append(res, CodeAndName{int(code), name})
}
cmds.EmitOnce(resp, res)
return nil
},
Encoders: codecsCmd.Encoders,
Type: codecsCmd.Type,
}
type multibaseSorter struct {
data []CodeAndName
}
func (s multibaseSorter) Len() int { return len(s.data) }
func (s multibaseSorter) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (s multibaseSorter) Less(i, j int) bool {
a := unicode.ToLower(rune(s.data[i].Code))
b := unicode.ToLower(rune(s.data[j].Code))
if a != b {
return a < b
}
// lowecase letters should come before uppercase
return s.data[i].Code > s.data[j].Code
}
type codeAndNameSorter struct {
data []CodeAndName
}
func (s codeAndNameSorter) Len() int { return len(s.data) }
func (s codeAndNameSorter) Swap(i, j int) { s.data[i], s.data[j] = s.data[j], s.data[i] }
func (s codeAndNameSorter) Less(i, j int) bool { return s.data[i].Code < s.data[j].Code }

View File

@ -7,7 +7,7 @@ import (
"github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
)

View File

@ -8,6 +8,7 @@ package commands
import (
"fmt"
"io"
"os"
"sort"
"strings"
@ -149,3 +150,42 @@ func unwrapOutput(i interface{}) (interface{}, error) {
return <-ch, nil
}
type nonFatalError string
// streamResult is a helper function to stream results that possibly
// contain non-fatal errors. The helper function is allowed to panic
// on internal errors.
func streamResult(procVal func(interface{}, io.Writer) nonFatalError) func(cmds.Response, cmds.ResponseEmitter) error {
return func(res cmds.Response, re cmds.ResponseEmitter) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("internal error: %v", r)
}
re.Close()
}()
var errors bool
for {
v, err := res.Next()
if err != nil {
if err == io.EOF {
break
}
return err
}
errorMsg := procVal(v, os.Stdout)
if errorMsg != "" {
errors = true
fmt.Fprintf(os.Stderr, "%s\n", errorMsg)
}
}
if errors {
return fmt.Errorf("errors while displaying some entries")
}
return nil
}
}

View File

@ -211,6 +211,12 @@ func TestCommands(t *testing.T) {
"/urlstore",
"/urlstore/add",
"/version",
"/cid",
"/cid/format",
"/cid/base32",
"/cid/codecs",
"/cid/bases",
"/cid/hashes",
}
cmdSet := make(map[string]struct{})

View File

@ -17,7 +17,7 @@ import (
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
)
type ConfigField struct {
@ -25,6 +25,11 @@ type ConfigField struct {
Value interface{}
}
const (
configBoolOptionName = "bool"
configJSONOptionName = "json"
)
var ConfigCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Get and set ipfs config values.",
@ -54,8 +59,8 @@ Set the value of the 'Datastore.Path' key:
cmdkit.StringArg("value", false, false, "The value to set the config entry to."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("bool", "Set a boolean value."),
cmdkit.BoolOption("json", "Parse stringified JSON."),
cmdkit.BoolOption(configBoolOptionName, "Set a boolean value."),
cmdkit.BoolOption(configJSONOptionName, "Parse stringified JSON."),
},
Run: func(req cmds.Request, res cmds.Response) {
args := req.Arguments()
@ -87,7 +92,7 @@ Set the value of the 'Datastore.Path' key:
if len(args) == 2 {
value := args[1]
if parseJson, _, _ := req.Option("json").Bool(); parseJson {
if parseJSON, _, _ := req.Option(configJSONOptionName).Bool(); parseJSON {
var jsonVal interface{}
if err := json.Unmarshal([]byte(value), &jsonVal); err != nil {
err = fmt.Errorf("failed to unmarshal json. %s", err)
@ -96,7 +101,7 @@ Set the value of the 'Datastore.Path' key:
}
output, err = setConfig(r, key, jsonVal)
} else if isbool, _, _ := req.Option("bool").Bool(); isbool {
} else if isbool, _, _ := req.Option(configBoolOptionName).Bool(); isbool {
output, err = setConfig(r, key, value == "true")
} else {
output, err = setConfig(r, key, value)

View File

@ -11,7 +11,7 @@ import (
e "github.com/ipfs/go-ipfs/core/commands/e"
coredag "github.com/ipfs/go-ipfs/core/coredag"
pin "github.com/ipfs/go-ipfs/pin"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"

View File

@ -10,17 +10,17 @@ import (
cmds "github.com/ipfs/go-ipfs/commands"
e "github.com/ipfs/go-ipfs/core/commands/e"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
routing "gx/ipfs/QmVBnJDKhtFXTRVjXKinqpwGu8t1DyNqPKan2iGX8PR8xG/go-libp2p-routing"
notif "gx/ipfs/QmVBnJDKhtFXTRVjXKinqpwGu8t1DyNqPKan2iGX8PR8xG/go-libp2p-routing/notifications"
routing "gx/ipfs/QmVQPj6rHdqz6dDQrjcdP36zDYLaoB7xwqRg39kx2PqqKU/go-libp2p-routing"
notif "gx/ipfs/QmVQPj6rHdqz6dDQrjcdP36zDYLaoB7xwqRg39kx2PqqKU/go-libp2p-routing/notifications"
b58 "gx/ipfs/QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY/go-base58-fast/base58"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
var ErrNotDHT = errors.New("routing service is not a DHT")
@ -44,6 +44,10 @@ var DhtCmd = &cmds.Command{
},
}
const (
dhtVerboseOptionName = "v"
)
var queryDhtCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Find the closest Peer IDs to a given Peer ID by querying the DHT.",
@ -54,7 +58,7 @@ var queryDhtCmd = &cmds.Command{
cmdkit.StringArg("peerID", true, true, "The peerID to run the query against."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -128,7 +132,7 @@ var queryDhtCmd = &cmds.Command{
return nil, e.TypeErr(obj, v)
}
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
buf := new(bytes.Buffer)
printEvent(obj, buf, verbose, pfm)
@ -139,6 +143,10 @@ var queryDhtCmd = &cmds.Command{
Type: notif.QueryEvent{},
}
const (
numProvidersOptionName = "num-providers"
)
var findProvidersDhtCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Find peers that can provide a specific value, given a key.",
@ -149,8 +157,8 @@ var findProvidersDhtCmd = &cmds.Command{
cmdkit.StringArg("key", true, true, "The key to find providers for."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.IntOption("num-providers", "n", "The number of providers to find.").WithDefault(20),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
cmdkit.IntOption(numProvidersOptionName, "n", "The number of providers to find.").WithDefault(20),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -164,7 +172,7 @@ var findProvidersDhtCmd = &cmds.Command{
return
}
numProviders, _, err := res.Request().Option("num-providers").Int()
numProviders, _, err := res.Request().Option(numProvidersOptionName).Int()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -232,7 +240,7 @@ var findProvidersDhtCmd = &cmds.Command{
}
return func(res cmds.Response) (io.Reader, error) {
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
@ -252,6 +260,10 @@ var findProvidersDhtCmd = &cmds.Command{
Type: notif.QueryEvent{},
}
const (
recursiveOptionName = "recursive"
)
var provideRefDhtCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Announce to the network that you are providing given values.",
@ -261,8 +273,8 @@ var provideRefDhtCmd = &cmds.Command{
cmdkit.StringArg("key", true, true, "The key[s] to send provide records for.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("recursive", "r", "Recursively provide entire graph."),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
cmdkit.BoolOption(recursiveOptionName, "r", "Recursively provide entire graph."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -281,7 +293,7 @@ var provideRefDhtCmd = &cmds.Command{
return
}
rec, _, _ := req.Option("recursive").Bool()
rec, _, _ := req.Option(recursiveOptionName).Bool()
var cids []cid.Cid
for _, arg := range req.Arguments() {
@ -349,7 +361,7 @@ var provideRefDhtCmd = &cmds.Command{
}
return func(res cmds.Response) (io.Reader, error) {
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
@ -414,7 +426,7 @@ var findPeerDhtCmd = &cmds.Command{
cmdkit.StringArg("peerID", true, true, "The ID of the peer to search for."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -480,7 +492,7 @@ var findPeerDhtCmd = &cmds.Command{
}
return func(res cmds.Response) (io.Reader, error) {
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
@ -519,7 +531,7 @@ Different key types can specify other 'best' rules.
cmdkit.StringArg("key", true, true, "The key to find a value for."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -584,7 +596,7 @@ Different key types can specify other 'best' rules.
}
return func(res cmds.Response) (io.Reader, error) {
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
@ -633,7 +645,7 @@ NOTE: A value may not exceed 2048 bytes.
cmdkit.StringArg("value", true, false, "The value to store.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "Print extra information."),
cmdkit.BoolOption("verbose", dhtVerboseOptionName, "Print extra information."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -697,7 +709,7 @@ NOTE: A value may not exceed 2048 bytes.
}
return func(res cmds.Response) (io.Reader, error) {
verbose, _, _ := res.Request().Option("v").Bool()
verbose, _, _ := res.Request().Option(dhtVerboseOptionName).Bool()
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err

View File

@ -6,7 +6,7 @@ import (
"github.com/ipfs/go-ipfs/namesys"
tu "gx/ipfs/QmNfQbgBfARAtrYsBguChX6VJ5nbjeoYy1KdC36aaYWqG8/go-testutil"
ipns "gx/ipfs/QmZrmn2BPZbSviQAWeyY2iXkCukmJHv9n7zrLgWU5KgbTb/go-ipns"
ipns "gx/ipfs/QmWhm9qS3NZdvTgAsB1cX4q9UbNu8yFybCcAMchCN88w7o/go-ipns"
)
func TestKeyTranslation(t *testing.T) {

View File

@ -13,6 +13,10 @@ import (
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
)
const (
dnsRecursiveOptionName = "recursive"
)
var DNSCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Resolve DNS links.",
@ -51,11 +55,11 @@ The resolver can recursively resolve:
cmdkit.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Resolve until the result is not a DNS link."),
cmdkit.BoolOption(dnsRecursiveOptionName, "r", "Resolve until the result is not a DNS link."),
},
Run: func(req cmds.Request, res cmds.Response) {
recursive, _, _ := req.Option("recursive").Bool()
recursive, _, _ := req.Option(dnsRecursiveOptionName).Bool()
name := req.Arguments()[0]
resolver := namesys.NewDNSResolver()

View File

@ -16,21 +16,19 @@ import (
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"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
bservice "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mfs "gx/ipfs/QmPbuswDwcPT4WquGqGoeBBDuuBaUmbZJFYiaes6vkgXYJ/go-mfs"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bservice "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
mfs "gx/ipfs/QmahrY1adY4wvtYEtoGjpZ2GUohTyukrkMkwUR9ytRjTG2/go-mfs"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
@ -71,8 +69,13 @@ operations.
},
}
var cidVersionOption = cmdkit.IntOption("cid-version", "cid-ver", "Cid version to use. (experimental)")
var hashOption = cmdkit.StringOption("hash", "Hash function to use. Will set Cid version to 1 if used. (experimental)")
const (
filesCidVersionOptionName = "cid-version"
filesHashOptionName = "hash"
)
var cidVersionOption = cmdkit.IntOption(filesCidVersionOptionName, "cid-ver", "Cid version to use. (experimental)")
var hashOption = cmdkit.StringOption(filesHashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)")
var errFormat = errors.New("format was set by multiple options. Only one format option is allowed")
@ -87,11 +90,16 @@ type statOutput struct {
SizeLocal uint64 `json:",omitempty"`
}
const defaultStatFormat = `<hash>
const (
defaultStatFormat = `<hash>
Size: <size>
CumulativeSize: <cumulsize>
ChildBlocks: <childs>
Type: <type>`
filesFormatOptionName = "format"
filesSizeOptionName = "size"
filesWithLocalOptionName = "with-local"
)
var filesStatCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
@ -102,11 +110,11 @@ var filesStatCmd = &cmds.Command{
cmdkit.StringArg("path", true, false, "Path to node to stat."),
},
Options: []cmdkit.Option{
cmdkit.StringOption("format", "Print statistics in given format. Allowed tokens: "+
cmdkit.StringOption(filesFormatOptionName, "Print statistics in given format. Allowed tokens: "+
"<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").WithDefault(defaultStatFormat),
cmdkit.BoolOption("hash", "Print only hash. Implies '--format=<hash>'. Conflicts with other format options."),
cmdkit.BoolOption("size", "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options."),
cmdkit.BoolOption("with-local", "Compute the amount of the dag that is local, and if possible the total size"),
cmdkit.BoolOption(filesHashOptionName, "Print only hash. Implies '--format=<hash>'. Conflicts with other format options."),
cmdkit.BoolOption(filesSizeOptionName, "Print only size. Implies '--format=<cumulsize>'. Conflicts with other format options."),
cmdkit.BoolOption(filesWithLocalOptionName, "Compute the amount of the dag that is local, and if possible the total size"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
@ -120,12 +128,17 @@ var filesStatCmd = &cmds.Command{
return err
}
api, err := cmdenv.GetApi(env)
if err != nil {
return err
}
path, err := checkPath(req.Arguments[0])
if err != nil {
return err
}
withLocal, _ := req.Options["with-local"].(bool)
withLocal, _ := req.Options[filesWithLocalOptionName].(bool)
var dagserv ipld.DAGService
if withLocal {
@ -138,7 +151,7 @@ var filesStatCmd = &cmds.Command{
dagserv = node.DAG
}
nd, err := getNodeFromPath(req.Context, node, dagserv, path)
nd, err := getNodeFromPath(req.Context, node, api, path)
if err != nil {
return err
}
@ -196,9 +209,9 @@ func moreThanOne(a, b, c bool) bool {
func statGetFormatOptions(req *cmds.Request) (string, error) {
hash, _ := req.Options["hash"].(bool)
size, _ := req.Options["size"].(bool)
format, _ := req.Options["format"].(string)
hash, _ := req.Options[filesHashOptionName].(bool)
size, _ := req.Options[filesSizeOptionName].(bool)
format, _ := req.Options[filesFormatOptionName].(string)
if moreThanOne(hash, size, format != defaultStatFormat) {
return "", errFormat
@ -305,6 +318,12 @@ var filesCpCmd = &oldcmds.Command{
return
}
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
flush, _, _ := req.Option("flush").Bool()
src, err := checkPath(req.Arguments()[0])
@ -324,7 +343,7 @@ var filesCpCmd = &oldcmds.Command{
dst += gopath.Base(src)
}
nd, err := getNodeFromPath(req.Context(), node, node.DAG, src)
nd, err := getNodeFromPath(req.Context(), node, api, src)
if err != nil {
res.SetError(fmt.Errorf("cp: cannot get node from path %s: %s", src, err), cmdkit.ErrNormal)
return
@ -348,20 +367,15 @@ var filesCpCmd = &oldcmds.Command{
},
}
func getNodeFromPath(ctx context.Context, node *core.IpfsNode, dagservice ipld.DAGService, p string) (ipld.Node, error) {
func getNodeFromPath(ctx context.Context, node *core.IpfsNode, api iface.CoreAPI, p string) (ipld.Node, error) {
switch {
case strings.HasPrefix(p, "/ipfs/"):
np, err := path.ParsePath(p)
np, err := iface.ParsePath(p)
if err != nil {
return nil, err
}
resolver := &resolver.Resolver{
DAG: dagservice,
ResolveOnce: uio.ResolveUnixfsOnce,
}
return core.Resolve(ctx, node.Namesys, resolver, np)
return api.ResolveNode(ctx, np)
default:
fsn, err := mfs.Lookup(node.FilesRoot, p)
if err != nil {
@ -376,6 +390,11 @@ type filesLsOutput struct {
Entries []mfs.NodeListing
}
const (
longOptionName = "l"
dontSortOptionName = "U"
)
var filesLsCmd = &oldcmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List directories in the local mutable namespace.",
@ -401,8 +420,8 @@ Examples:
cmdkit.StringArg("path", false, false, "Path to show listing for. Defaults to '/'."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("l", "Use long listing format."),
cmdkit.BoolOption("U", "Do not sort; list entries in directory order."),
cmdkit.BoolOption(longOptionName, "Use long listing format."),
cmdkit.BoolOption(dontSortOptionName, "Do not sort; list entries in directory order."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
var arg string
@ -431,7 +450,7 @@ Examples:
return
}
long, _, _ := req.Option("l").Bool()
long, _, _ := req.Option(longOptionName).Bool()
switch fsn := fsn.(type) {
case *mfs.Directory:
@ -498,14 +517,14 @@ Examples:
buf := new(bytes.Buffer)
noSort, _, _ := res.Request().Option("U").Bool()
noSort, _, _ := res.Request().Option(dontSortOptionName).Bool()
if !noSort {
sort.Slice(out.Entries, func(i, j int) bool {
return strings.Compare(out.Entries[i].Name, out.Entries[j].Name) < 0
})
}
long, _, _ := res.Request().Option("l").Bool()
long, _, _ := res.Request().Option(longOptionName).Bool()
for _, o := range out.Entries {
if long {
fmt.Fprintf(buf, "%s\t%s\t%d\n", o.Name, o.Hash, o.Size)
@ -519,6 +538,11 @@ Examples:
Type: filesLsOutput{},
}
const (
filesOffsetOptionName = "offset"
filesCountOptionName = "count"
)
var filesReadCmd = &oldcmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Read a file in a given mfs.",
@ -537,8 +561,8 @@ Examples:
cmdkit.StringArg("path", true, false, "Path to file to be read."),
},
Options: []cmdkit.Option{
cmdkit.IntOption("offset", "o", "Byte offset to begin reading from."),
cmdkit.IntOption("count", "n", "Maximum number of bytes to read."),
cmdkit.IntOption(filesOffsetOptionName, "o", "Byte offset to begin reading from."),
cmdkit.IntOption(filesCountOptionName, "n", "Maximum number of bytes to read."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
n, err := req.InvocContext().GetNode()
@ -573,7 +597,7 @@ Examples:
defer rfd.Close()
offset, _, err := req.Option("offset").Int()
offset, _, err := req.Option(offsetOptionName).Int()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -601,7 +625,7 @@ Examples:
}
var r io.Reader = &contextReaderWrapper{R: rfd, ctx: req.Context()}
count, found, err := req.Option("count").Int()
count, found, err := req.Option(filesCountOptionName).Int()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -676,6 +700,14 @@ Example:
},
}
const (
filesCreateOptionName = "create"
filesParentsOptionName = "parents"
filesTruncateOptionName = "truncate"
filesRawLeavesOptionName = "raw-leaves"
filesFlushOptionName = "flush"
)
var filesWriteCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Write to a mutable file in a given filesystem.",
@ -715,12 +747,12 @@ stat' on the file or any of its ancestors.
cmdkit.FileArg("data", true, false, "Data to write.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.IntOption("offset", "o", "Byte offset to begin writing at."),
cmdkit.BoolOption("create", "e", "Create the file if it does not exist."),
cmdkit.BoolOption("parents", "p", "Make parent directories as needed."),
cmdkit.BoolOption("truncate", "t", "Truncate the file to size zero before writing."),
cmdkit.IntOption("count", "n", "Maximum number of bytes to read."),
cmdkit.BoolOption("raw-leaves", "Use raw blocks for newly created leaf nodes. (experimental)"),
cmdkit.IntOption(filesOffsetOptionName, "o", "Byte offset to begin writing at."),
cmdkit.BoolOption(filesCreateOptionName, "e", "Create the file if it does not exist."),
cmdkit.BoolOption(filesParentsOptionName, "p", "Make parent directories as needed."),
cmdkit.BoolOption(filesTruncateOptionName, "t", "Truncate the file to size zero before writing."),
cmdkit.IntOption(filesCountOptionName, "n", "Maximum number of bytes to read."),
cmdkit.BoolOption(filesRawLeavesOptionName, "Use raw blocks for newly created leaf nodes. (experimental)"),
cidVersionOption,
hashOption,
},
@ -730,11 +762,11 @@ stat' on the file or any of its ancestors.
return err
}
create, _ := req.Options["create"].(bool)
mkParents, _ := req.Options["parents"].(bool)
trunc, _ := req.Options["truncate"].(bool)
flush, _ := req.Options["flush"].(bool)
rawLeaves, rawLeavesDef := req.Options["raw-leaves"].(bool)
create, _ := req.Options[filesCreateOptionName].(bool)
mkParents, _ := req.Options[filesParentsOptionName].(bool)
trunc, _ := req.Options[filesTruncateOptionName].(bool)
flush, _ := req.Options[filesFlushOptionName].(bool)
rawLeaves, rawLeavesDef := req.Options[filesRawLeavesOptionName].(bool)
prefix, err := getPrefixNew(req)
if err != nil {
@ -746,7 +778,7 @@ stat' on the file or any of its ancestors.
return err
}
offset, _ := req.Options["offset"].(int)
offset, _ := req.Options[filesOffsetOptionName].(int)
if offset < 0 {
return fmt.Errorf("cannot have negative write offset")
}
@ -788,7 +820,7 @@ stat' on the file or any of its ancestors.
}
}
count, countfound := req.Options["count"].(int)
count, countfound := req.Options[filesCountOptionName].(int)
if countfound && count < 0 {
return fmt.Errorf("cannot have negative byte count")
}
@ -836,7 +868,7 @@ Examples:
cmdkit.StringArg("path", true, false, "Path to dir to make."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("parents", "p", "No error if existing, make parent directories as needed."),
cmdkit.BoolOption(filesParentsOptionName, "p", "No error if existing, make parent directories as needed."),
cidVersionOption,
hashOption,
},
@ -847,14 +879,14 @@ Examples:
return
}
dashp, _, _ := req.Option("parents").Bool()
dashp, _, _ := req.Option(filesParentsOptionName).Bool()
dirtomake, err := checkPath(req.Arguments()[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
flush, _, _ := req.Option("flush").Bool()
flush, _, _ := req.Option(filesFlushOptionName).Bool()
prefix, err := getPrefix(req)
if err != nil {
@ -936,7 +968,7 @@ Change the cid version or hash function of the root node of a given path.
path = req.Arguments()[0]
}
flush, _, _ := req.Option("flush").Bool()
flush, _, _ := req.Option(filesFlushOptionName).Bool()
prefix, err := getPrefix(req)
if err != nil {
@ -998,6 +1030,7 @@ Remove files or directories.
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Recursively remove directories."),
cmdkit.BoolOption("force", "Forcibly remove target at path; implies -r for directories"),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
defer res.SetOutput(nil)
@ -1037,8 +1070,6 @@ Remove files or directories.
return
}
dashr, _, _ := req.Option("r").Bool()
var success bool
defer func() {
if success {
@ -1050,8 +1081,10 @@ Remove files or directories.
}
}()
// if '-r' specified, don't check file type (in bad scenarios, the block may not exist)
if dashr {
// if '--force' specified, it will remove anything else,
// including file, directory, corrupted node, etc
force, _, _ := req.Option("force").Bool()
if force {
err := pdir.Unlink(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
@ -1062,31 +1095,37 @@ Remove files or directories.
return
}
childi, err := pdir.Child(name)
// get child node by name, when the node is corrupted and nonexistent,
// it will return specific error.
child, err := pdir.Child(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
switch childi.(type) {
dashr, _, _ := req.Option("r").Bool()
switch child.(type) {
case *mfs.Directory:
res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmdkit.ErrNormal)
return
default:
err := pdir.Unlink(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
if !dashr {
res.SetError(fmt.Errorf("%s is a directory, use -r to remove directories", path), cmdkit.ErrNormal)
return
}
success = true
}
err = pdir.Unlink(name)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
success = true
},
}
func getPrefixNew(req *cmds.Request) (cid.Builder, error) {
cidVer, cidVerSet := req.Options["cid-version"].(int)
hashFunStr, hashFunSet := req.Options["hash"].(string)
cidVer, cidVerSet := req.Options[filesCidVersionOptionName].(int)
hashFunStr, hashFunSet := req.Options[filesHashOptionName].(string)
if !cidVerSet && !hashFunSet {
return nil, nil
@ -1114,8 +1153,8 @@ func getPrefixNew(req *cmds.Request) (cid.Builder, error) {
}
func getPrefix(req oldcmds.Request) (cid.Builder, error) {
cidVer, cidVerSet, _ := req.Option("cid-version").Int()
hashFunStr, hashFunSet, _ := req.Option("hash").String()
cidVer, cidVerSet, _ := req.Option(filesCidVersionOptionName).Int()
hashFunStr, hashFunSet, _ := req.Option(filesHashOptionName).String()
if !cidVerSet && !hashFunSet {
return nil, nil

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"io"
"os"
oldCmds "github.com/ipfs/go-ipfs/commands"
lgc "github.com/ipfs/go-ipfs/commands/legacy"
@ -29,6 +28,10 @@ var FileStoreCmd = &cmds.Command{
},
}
const (
fileOrderOptionName = "file-order"
)
var lsFileStore = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List objects in filestore.",
@ -47,7 +50,7 @@ The output is:
cmdkit.StringArg("obj", false, true, "Cid of objects to list."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("file-order", "sort the results based on the path of the backing file"),
cmdkit.BoolOption(fileOrderOptionName, "sort the results based on the path of the backing file"),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
_, fs, err := getFilestore(env)
@ -63,7 +66,7 @@ The output is:
return res.Emit(out)
}
fileOrder, _ := req.Options["file-order"].(bool)
fileOrder, _ := req.Options[fileOrderOptionName].(bool)
next, err := filestore.ListAll(fs, fileOrder)
if err != nil {
return err
@ -73,36 +76,14 @@ The output is:
return res.Emit(out)
},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
var errors bool
for {
v, err := res.Next()
if err != nil {
if err == io.EOF {
break
}
return err
}
r, ok := v.(*filestore.ListRes)
if !ok {
return e.New(e.TypeErr(r, v))
}
if r.ErrorMsg != "" {
errors = true
fmt.Fprintf(os.Stderr, "%s\n", r.ErrorMsg)
} else {
fmt.Fprintf(os.Stdout, "%s\n", r.FormatLong())
}
cmds.CLI: streamResult(func(v interface{}, out io.Writer) nonFatalError {
r := v.(*filestore.ListRes)
if r.ErrorMsg != "" {
return nonFatalError(r.ErrorMsg)
}
if errors {
return fmt.Errorf("errors while displaying some entries")
}
return nil
},
fmt.Fprintf(out, "%s\n", r.FormatLong())
return ""
}),
},
Type: filestore.ListRes{},
}
@ -135,7 +116,7 @@ For ERROR entries the error will also be printed to stderr.
cmdkit.StringArg("obj", false, true, "Cid of objects to verify."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("file-order", "verify the objects based on the order of the backing file"),
cmdkit.BoolOption(fileOrderOptionName, "verify the objects based on the order of the backing file"),
},
Run: func(req oldCmds.Request, res oldCmds.Response) {
_, fs, err := getFilestore(req.InvocContext())
@ -150,7 +131,7 @@ For ERROR entries the error will also be printed to stderr.
})
res.SetOutput(out)
} else {
fileOrder, _, _ := req.Option("file-order").Bool()
fileOrder, _, _ := req.Option(fileOrderOptionName).Bool()
next, err := filestore.VerifyAll(fs, fileOrder)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)

View File

@ -14,16 +14,23 @@ import (
e "github.com/ipfs/go-ipfs/core/commands/e"
"gx/ipfs/QmPtj12fdwuAqj9sBSTNUxBNu8kCGNp8b3o8yUzMm5GHpq/pb"
uarchive "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/archive"
tar "gx/ipfs/QmQine7gvHncNevKtG9QXxf3nXcwSj6aDDmMm52mHofEEp/tar-utils"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
uarchive "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/archive"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
)
var ErrInvalidCompressionLevel = errors.New("compression level must be between 1 and 9")
const (
outputOptionName = "output"
archiveOptionName = "archive"
compressOptionName = "compress"
compressionLevelOptionName = "compression-level"
)
var GetCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Download IPFS objects.",
@ -44,10 +51,10 @@ may also specify the level of compression by specifying '-l=<1-9>'.
cmdkit.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.StringOption("output", "o", "The path where the output should be stored."),
cmdkit.BoolOption("archive", "a", "Output a TAR archive."),
cmdkit.BoolOption("compress", "C", "Compress the output with GZIP compression."),
cmdkit.IntOption("compression-level", "l", "The level of compression (1-9)."),
cmdkit.StringOption(outputOptionName, "o", "The path where the output should be stored."),
cmdkit.BoolOption(archiveOptionName, "a", "Output a TAR archive."),
cmdkit.BoolOption(compressOptionName, "C", "Compress the output with GZIP compression."),
cmdkit.IntOption(compressionLevelOptionName, "l", "The level of compression (1-9)."),
},
PreRun: func(req *cmds.Request, env cmds.Environment) error {
_, err := getCompressOptions(req)
@ -84,7 +91,7 @@ may also specify the level of compression by specifying '-l=<1-9>'.
return err
}
archive, _ := req.Options["archive"].(bool)
archive, _ := req.Options[archiveOptionName].(bool)
reader, err := uarchive.DagArchive(ctx, dn, p.String(), node.DAG, archive, cmplvl)
if err != nil {
return err
@ -113,7 +120,7 @@ may also specify the level of compression by specifying '-l=<1-9>'.
return err
}
archive, _ := req.Options["archive"].(bool)
archive, _ := req.Options[archiveOptionName].(bool)
gw := getWriter{
Out: os.Stdout,
@ -165,7 +172,7 @@ func makeProgressBar(out io.Writer, l int64) *pb.ProgressBar {
}
func getOutPath(req *cmds.Request) string {
outPath, _ := req.Options["output"].(string)
outPath, _ := req.Options[outputOptionName].(string)
if outPath == "" {
trimmed := strings.TrimRight(req.Arguments[0], "/")
_, outPath = filepath.Split(trimmed)
@ -233,8 +240,8 @@ func (gw *getWriter) writeExtracted(r io.Reader, fpath string) error {
}
func getCompressOptions(req *cmds.Request) (int, error) {
cmprs, _ := req.Options["compress"].(bool)
cmplvl, cmplvlFound := req.Options["compression-level"].(int)
cmprs, _ := req.Options[compressOptionName].(bool)
cmplvl, cmplvlFound := req.Options[compressionLevelOptionName].(int)
switch {
case !cmprs:
return gzip.NoCompression, nil

View File

@ -13,11 +13,11 @@ import (
e "github.com/ipfs/go-ipfs/core/commands/e"
ic "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
kb "gx/ipfs/QmRtUtF42geEhpRg9z45ZfBqRMC6xyeNW7i1iqha3nRMFe/go-libp2p-kbucket"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
identify "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/protocol/identify"
identify "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/protocol/identify"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
kb "gx/ipfs/Qmb4AZNKg9yQVKkQqejEcg86AaT6EqGemGV8mBjkfJBeGf/go-libp2p-kbucket"
"gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
const offlineIdErrorMessage = `'ipfs id' currently cannot query information on remote
@ -37,6 +37,10 @@ type IdOutput struct {
ProtocolVersion string
}
const (
formatOptionName = "format"
)
var IDCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Show ipfs node id info.",
@ -60,7 +64,7 @@ EXAMPLE:
cmdkit.StringArg("peerid", false, false, "Peer.ID of node to look up."),
},
Options: []cmdkit.Option{
cmdkit.StringOption("format", "f", "Optional output format."),
cmdkit.StringOption(formatOptionName, "f", "Optional output format."),
},
Run: func(req cmds.Request, res cmds.Response) {
node, err := req.InvocContext().GetNode()
@ -126,7 +130,7 @@ EXAMPLE:
return nil, e.TypeErr(val, v)
}
format, found, err := res.Request().Option("format").String()
format, found, err := res.Request().Option(formatOptionName).String()
if err != nil {
return nil, err
}

View File

@ -55,13 +55,18 @@ type KeyRenameOutput struct {
Overwrite bool
}
const (
keyStoreTypeOptionName = "type"
keyStoreSizeOptionName = "size"
)
var keyGenCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Create a new keypair",
},
Options: []cmdkit.Option{
cmdkit.StringOption("type", "t", "type of the key to create [rsa, ed25519]"),
cmdkit.IntOption("size", "s", "size of the key to generate"),
cmdkit.StringOption(keyStoreTypeOptionName, "t", "type of the key to create [rsa, ed25519]"),
cmdkit.IntOption(keyStoreSizeOptionName, "s", "size of the key to generate"),
},
Arguments: []cmdkit.Argument{
cmdkit.StringArg("name", true, false, "name of key to create"),
@ -72,7 +77,7 @@ var keyGenCmd = &cmds.Command{
return err
}
typ, f := req.Options["type"].(string)
typ, f := req.Options[keyStoreTypeOptionName].(string)
if !f {
return fmt.Errorf("please specify a key type with --type")
}
@ -84,7 +89,7 @@ var keyGenCmd = &cmds.Command{
opts := []options.KeyGenerateOption{options.Key.Type(typ)}
size, sizefound := req.Options["size"].(int)
size, sizefound := req.Options[keyStoreSizeOptionName].(int)
if sizefound {
opts = append(opts, options.Key.Size(size))
}
@ -146,6 +151,10 @@ var keyListCmd = &cmds.Command{
Type: KeyOutputList{},
}
const (
keyStoreForceOptionName = "force"
)
var keyRenameCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Rename a keypair",
@ -155,7 +164,7 @@ var keyRenameCmd = &cmds.Command{
cmdkit.StringArg("newName", true, false, "new name of the key"),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("force", "f", "Allow to overwrite an existing key."),
cmdkit.BoolOption(keyStoreForceOptionName, "f", "Allow to overwrite an existing key."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
@ -165,7 +174,7 @@ var keyRenameCmd = &cmds.Command{
name := req.Arguments[0]
newName := req.Arguments[1]
force, _ := req.Options["force"].(bool)
force, _ := req.Options[keyStoreForceOptionName].(bool)
key, overwritten, err := api.Key().Rename(req.Context, name, newName, options.Key.Force(force))
if err != nil {

View File

@ -1,10 +1,12 @@
package commands
import (
"bytes"
"fmt"
"io"
cmds "github.com/ipfs/go-ipfs/commands"
e "github.com/ipfs/go-ipfs/core/commands/e"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
@ -110,3 +112,23 @@ Outputs event log messages (not other log messages) as they are generated.
res.SetOutput(r)
},
}
func stringListMarshaler(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
list, ok := v.(*stringList)
if !ok {
return nil, e.TypeErr(list, v)
}
buf := new(bytes.Buffer)
for _, s := range list.Strings {
buf.WriteString(s)
buf.WriteString("\n")
}
return buf, nil
}

View File

@ -7,19 +7,17 @@ import (
"text/tabwriter"
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
e "github.com/ipfs/go-ipfs/core/commands/e"
unixfs "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
unixfspb "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/pb"
merkledag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
blockservice "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
unixfs "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
unixfspb "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/pb"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
merkledag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
blockservice "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
@ -38,6 +36,11 @@ type LsOutput struct {
Objects []LsObject
}
const (
lsHeadersOptionNameTime = "headers"
lsResolveTypeOptionName = "resolve-type"
)
var LsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List directory contents for Unix filesystem objects.",
@ -55,8 +58,8 @@ The JSON output contains type information.
cmdkit.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("headers", "v", "Print table headers (Hash, Size, Name)."),
cmdkit.BoolOption("resolve-type", "Resolve linked objects to find out their types.").WithDefault(true),
cmdkit.BoolOption(lsHeadersOptionNameTime, "v", "Print table headers (Hash, Size, Name)."),
cmdkit.BoolOption(lsResolveTypeOptionName, "Resolve linked objects to find out their types.").WithDefault(true),
},
Run: func(req cmds.Request, res cmds.Response) {
nd, err := req.InvocContext().GetNode()
@ -65,13 +68,19 @@ The JSON output contains type information.
return
}
// get options early -> exit early in case of error
if _, _, err := req.Option("headers").Bool(); err != nil {
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
resolve, _, err := req.Option("resolve-type").Bool()
// get options early -> exit early in case of error
if _, _, err := req.Option(lsHeadersOptionNameTime).Bool(); err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
resolve, _, err := req.Option(lsResolveTypeOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -88,18 +97,13 @@ The JSON output contains type information.
var dagnodes []ipld.Node
for _, fpath := range paths {
p, err := path.ParsePath(fpath)
p, err := iface.ParsePath(fpath)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
r := &resolver.Resolver{
DAG: nd.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
dagnode, err := core.Resolve(req.Context(), nd.Namesys, r, p)
dagnode, err := api.ResolveNode(req.Context(), p)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -108,9 +112,11 @@ The JSON output contains type information.
}
output := make([]LsObject, len(req.Arguments()))
ng := merkledag.NewSession(req.Context(), nd.DAG)
ro := merkledag.NewReadOnlyDagService(ng)
for i, dagnode := range dagnodes {
dir, err := uio.NewDirectoryFromNode(nd.DAG, dagnode)
dir, err := uio.NewDirectoryFromNode(ro, dagnode)
if err != nil && err != uio.ErrNotADir {
res.SetError(fmt.Errorf("the data in %s (at %q) is not a UnixFS directory: %s", dagnode.Cid(), paths[i], err), cmdkit.ErrNormal)
return
@ -177,7 +183,7 @@ The JSON output contains type information.
return nil, err
}
headers, _, _ := res.Request().Option("headers").Bool()
headers, _, _ := res.Request().Option(lsHeadersOptionNameTime).Bool()
output, ok := v.(*LsOutput)
if !ok {
return nil, e.TypeErr(output, v)

View File

@ -12,7 +12,7 @@ import (
nodeMount "github.com/ipfs/go-ipfs/fuse/node"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
)
var MountCmd = &cmds.Command{

View File

@ -9,14 +9,13 @@ 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"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
"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"
)
var log = logging.Logger("core/commands/ipns")
@ -82,44 +81,21 @@ Resolve the value of a dnslink:
cmdkit.BoolOption(streamOptionName, "s", "Stream entries as they are found."),
},
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]
}
@ -128,12 +104,17 @@ Resolve the value of a dnslink:
rc, rcok := req.Options[dhtRecordCountOptionName].(int)
dhtt, dhttok := req.Options[dhtTimeoutOptionName].(string)
stream, _ := req.Options[streamOptionName].(bool)
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)
@ -143,34 +124,37 @@ 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
}
// TODO: better errors (in the case of not finding the name, we get "failed to find any peer in table")
if !stream {
output, err := resolver.Resolve(req.Context, name, ropts...)
output, err := api.Name().Resolve(req.Context, name, opts...)
if err != nil {
return err
}
return cmds.EmitOnce(res, &ResolvedPath{output})
return cmds.EmitOnce(res, &ResolvedPath{path.FromString(output.String())})
}
output, err := api.Name().Search(req.Context, name, opts...)
if err != nil {
return err
}
output := resolver.ResolveAsync(req.Context, name, ropts...)
for v := range output {
if v.Err != nil {
return err
}
if err := res.Emit(&ResolvedPath{v.Path}); err != nil {
if err := res.Emit(&ResolvedPath{path.FromString(v.Path.String())}); err != nil {
return err
}
}
return nil
},
Encoders: cmds.EncoderMap{

View File

@ -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 (
@ -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
}
}
kname, _ := req.Options[keyOptionName].(string)
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)
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 verifyExists, _ := req.Options[resolveOptionName].(bool); verifyExists {
_, err := api.ResolveNode(req.Context, p)
if err != nil {
return err
}
}
out, err := api.Name().Publish(req.Context, p, opts...)
if err != nil {
if err == iface.ErrOffline {
err = errAllowOffline
}
return err
}
output, err := publish(ctx, n, k, pth, popts)
if err != nil {
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 {
@ -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")
}

View File

@ -19,7 +19,7 @@ import (
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)

View File

@ -9,16 +9,18 @@ import (
"strconv"
"strings"
"text/tabwriter"
"time"
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
p2p "github.com/ipfs/go-ipfs/p2p"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
"gx/ipfs/QmSzdvo9aPzLj4HXWTcgGAp8N84tZc8LbLmFZFwUb1dpWk/go-ipfs-addr"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
"gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
"gx/ipfs/QmesXvbRGyKQn1XbPHx1Mr5E6RTJYR9c8zwFVuGZq9Aa1j/go-ipfs-addr"
madns "gx/ipfs/QmfXU2MhWoegxHoeMd3A2ytL2P6CY4FfqGWc23LTNWBwZt/go-multiaddr-dns"
)
// P2PProtoPrefix is the default required prefix for protocol names
@ -49,6 +51,12 @@ type P2PStreamsOutput struct {
Streams []P2PStreamInfoOutput
}
const (
allowCustomProtocolOptionName = "allow-custom-protocol"
)
var resolveTimeout = 10 * time.Second
// P2PCmd is the 'ipfs p2p' command
var P2PCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
@ -91,7 +99,7 @@ Example:
cmdkit.StringArg("target-address", true, false, "Target endpoint."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("allow-custom-protocol", "Don't require /x/ prefix"),
cmdkit.BoolOption(allowCustomProtocolOptionName, "Don't require /x/ prefix"),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := p2pGetNode(req)
@ -112,13 +120,13 @@ Example:
return
}
target, err := ipfsaddr.ParseString(targetOpt)
targets, err := parseIpfsAddr(targetOpt)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
allowCustom, _, err := req.Option("allow-custom-protocol").Bool()
allowCustom, _, err := req.Option(allowCustomProtocolOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -129,7 +137,7 @@ Example:
return
}
if err := forwardLocal(n.Context(), n.P2P, n.Peerstore, proto, listen, target); err != nil {
if err := forwardLocal(n.Context(), n.P2P, n.Peerstore, proto, listen, targets); err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
@ -137,6 +145,37 @@ Example:
},
}
// parseIpfsAddr is a function that takes in addr string and return ipfsAddrs
func parseIpfsAddr(addr string) ([]ipfsaddr.IPFSAddr, error) {
mutiladdr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
if _, err := mutiladdr.ValueForProtocol(ma.P_IPFS); err == nil {
iaddrs := make([]ipfsaddr.IPFSAddr, 1)
iaddrs[0], err = ipfsaddr.ParseMultiaddr(mutiladdr)
if err != nil {
return nil, err
}
return iaddrs, nil
}
// resolve mutiladdr whose protocol is not ma.P_IPFS
ctx, cancel := context.WithTimeout(context.Background(), resolveTimeout)
addrs, err := madns.Resolve(ctx, mutiladdr)
cancel()
if len(addrs) == 0 {
return nil, errors.New("fail to resolve the multiaddr:" + mutiladdr.String())
}
iaddrs := make([]ipfsaddr.IPFSAddr, len(addrs))
for i, addr := range addrs {
iaddrs[i], err = ipfsaddr.ParseMultiaddr(addr)
if err != nil {
return nil, err
}
}
return iaddrs, nil
}
var p2pListenCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Create libp2p service",
@ -156,7 +195,7 @@ Example:
cmdkit.StringArg("target-address", true, false, "Target endpoint."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("allow-custom-protocol", "Don't require /x/ prefix"),
cmdkit.BoolOption(allowCustomProtocolOptionName, "Don't require /x/ prefix"),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := p2pGetNode(req)
@ -176,7 +215,7 @@ Example:
return
}
allowCustom, _, err := req.Option("allow-custom-protocol").Bool()
allowCustom, _, err := req.Option(allowCustomProtocolOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -204,22 +243,27 @@ func forwardRemote(ctx context.Context, p *p2p.P2P, proto protocol.ID, target ma
}
// forwardLocal forwards local connections to a libp2p service
func forwardLocal(ctx context.Context, p *p2p.P2P, ps pstore.Peerstore, proto protocol.ID, bindAddr ma.Multiaddr, addr ipfsaddr.IPFSAddr) error {
if addr != nil {
func forwardLocal(ctx context.Context, p *p2p.P2P, ps pstore.Peerstore, proto protocol.ID, bindAddr ma.Multiaddr, addrs []ipfsaddr.IPFSAddr) error {
for _, addr := range addrs {
ps.AddAddr(addr.ID(), addr.Multiaddr(), pstore.TempAddrTTL)
}
// TODO: return some info
_, err := p.ForwardLocal(ctx, addr.ID(), proto, bindAddr)
// the length of the addrs must large than 0
// peerIDs in addr must be the same and choose addr[0] to connect
_, err := p.ForwardLocal(ctx, addrs[0].ID(), proto, bindAddr)
return err
}
const (
p2pHeadersOptionName = "headers"
)
var p2pLsCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List active p2p listeners.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("headers", "v", "Print table headers (Protocol, Listen, Target)."),
cmdkit.BoolOption(p2pHeadersOptionName, "v", "Print table headers (Protocol, Listen, Target)."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := p2pGetNode(req)
@ -260,7 +304,7 @@ var p2pLsCmd = &cmds.Command{
return nil, err
}
headers, _, _ := res.Request().Option("headers").Bool()
headers, _, _ := res.Request().Option(p2pHeadersOptionName).Bool()
list := v.(*P2PLsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
@ -278,15 +322,22 @@ var p2pLsCmd = &cmds.Command{
},
}
const (
p2pAllOptionName = "all"
p2pProtocolOptionName = "protocol"
p2pListenAddressOptionName = "listen-address"
p2pTargetAddressOptionName = "target-address"
)
var p2pCloseCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Stop listening for new connections to forward.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("all", "a", "Close all listeners."),
cmdkit.StringOption("protocol", "p", "Match protocol name"),
cmdkit.StringOption("listen-address", "l", "Match listen address"),
cmdkit.StringOption("target-address", "t", "Match target address"),
cmdkit.BoolOption(p2pAllOptionName, "a", "Close all listeners."),
cmdkit.StringOption(p2pProtocolOptionName, "p", "Match protocol name"),
cmdkit.StringOption(p2pListenAddressOptionName, "l", "Match listen address"),
cmdkit.StringOption(p2pTargetAddressOptionName, "t", "Match target address"),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := p2pGetNode(req)
@ -295,10 +346,10 @@ var p2pCloseCmd = &cmds.Command{
return
}
closeAll, _, _ := req.Option("all").Bool()
protoOpt, p, _ := req.Option("protocol").String()
listenOpt, l, _ := req.Option("listen-address").String()
targetOpt, t, _ := req.Option("target-address").String()
closeAll, _, _ := req.Option(p2pAllOptionName).Bool()
protoOpt, p, _ := req.Option(p2pProtocolOptionName).String()
listenOpt, l, _ := req.Option(p2pListenAddressOptionName).String()
targetOpt, t, _ := req.Option(p2pTargetAddressOptionName).String()
proto := protocol.ID(protoOpt)
@ -384,7 +435,7 @@ var p2pStreamLsCmd = &cmds.Command{
Tagline: "List active p2p streams.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("headers", "v", "Print table headers (ID, Protocol, Local, Remote)."),
cmdkit.BoolOption(p2pHeadersOptionName, "v", "Print table headers (ID, Protocol, Local, Remote)."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := p2pGetNode(req)
@ -418,7 +469,7 @@ var p2pStreamLsCmd = &cmds.Command{
return nil, err
}
headers, _, _ := res.Request().Option("headers").Bool()
headers, _, _ := res.Request().Option(p2pHeadersOptionName).Bool()
list := v.(*P2PStreamsOutput)
buf := new(bytes.Buffer)
w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0)
@ -444,7 +495,7 @@ var p2pStreamCloseCmd = &cmds.Command{
cmdkit.StringArg("id", false, false, "Stream identifier"),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("all", "a", "Close all streams."),
cmdkit.BoolOption(p2pAllOptionName, "a", "Close all streams."),
},
Run: func(req cmds.Request, res cmds.Response) {
res.SetOutput(nil)
@ -455,7 +506,7 @@ var p2pStreamCloseCmd = &cmds.Command{
return
}
closeAll, _, _ := req.Option("all").Bool()
closeAll, _, _ := req.Option(p2pAllOptionName).Bool()
var handlerID uint64
if !closeAll {

View File

@ -10,18 +10,17 @@ import (
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
e "github.com/ipfs/go-ipfs/core/commands/e"
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
corerepo "github.com/ipfs/go-ipfs/core/corerepo"
pin "github.com/ipfs/go-ipfs/pin"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
"gx/ipfs/QmVkMRSkXrpjqrroEXWuYBvDBnXCdMMY6gsKicBGVGUqKT/go-verifcid"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
bserv "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bserv "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
)
var PinCmd = &cmds.Command{
@ -47,6 +46,11 @@ type AddPinOutput struct {
Progress int `json:",omitempty"`
}
const (
pinRecursiveOptionName = "recursive"
pinProgressOptionName = "progress"
)
var addPinCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Pin objects to local storage.",
@ -57,8 +61,8 @@ var addPinCmd = &cmds.Command{
cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be pinned.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s).").WithDefault(true),
cmdkit.BoolOption("progress", "Show progress"),
cmdkit.BoolOption(pinRecursiveOptionName, "r", "Recursively pin the object linked to by the specified object(s).").WithDefault(true),
cmdkit.BoolOption(pinProgressOptionName, "Show progress"),
},
Type: AddPinOutput{},
Run: func(req cmds.Request, res cmds.Response) {
@ -68,18 +72,24 @@ var addPinCmd = &cmds.Command{
return
}
defer n.Blockstore.PinLock().Unlock()
// set recursive flag
recursive, _, err := req.Option("recursive").Bool()
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
showProgress, _, _ := req.Option("progress").Bool()
defer n.Blockstore.PinLock().Unlock()
// set recursive flag
recursive, _, err := req.Option(pinRecursiveOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
showProgress, _, _ := req.Option(pinProgressOptionName).Bool()
if !showProgress {
added, err := corerepo.Pin(n, req.Context(), req.Arguments(), recursive)
added, err := corerepo.Pin(n, api, req.Context(), req.Arguments(), recursive)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -99,7 +109,7 @@ var addPinCmd = &cmds.Command{
}
ch := make(chan pinResult, 1)
go func() {
added, err := corerepo.Pin(n, ctx, req.Arguments(), recursive)
added, err := corerepo.Pin(n, api, ctx, req.Arguments(), recursive)
ch <- pinResult{pins: added, err: err}
}()
@ -183,7 +193,7 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
cmdkit.StringArg("ipfs-path", true, true, "Path to object(s) to be unpinned.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s).").WithDefault(true),
cmdkit.BoolOption(pinRecursiveOptionName, "r", "Recursively unpin the object linked to by the specified object(s).").WithDefault(true),
},
Type: PinOutput{},
Run: func(req cmds.Request, res cmds.Response) {
@ -193,14 +203,20 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
return
}
// set recursive flag
recursive, _, err := req.Option("recursive").Bool()
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
removed, err := corerepo.Unpin(n, req.Context(), req.Arguments(), recursive)
// set recursive flag
recursive, _, err := req.Option(pinRecursiveOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
removed, err := corerepo.Unpin(n, api, req.Context(), req.Arguments(), recursive)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -229,6 +245,11 @@ collected if needed. (By default, recursively. Use -r=false for direct pins.)
},
}
const (
pinTypeOptionName = "type"
pinQuietOptionName = "quiet"
)
var listPinCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List objects pinned to local storage.",
@ -277,8 +298,8 @@ Example:
cmdkit.StringArg("ipfs-path", false, true, "Path to object(s) to be listed."),
},
Options: []cmdkit.Option{
cmdkit.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"),
cmdkit.BoolOption("quiet", "q", "Write just hashes of objects."),
cmdkit.StringOption(pinTypeOptionName, "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\".").WithDefault("all"),
cmdkit.BoolOption(pinQuietOptionName, "q", "Write just hashes of objects."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -287,7 +308,13 @@ Example:
return
}
typeStr, _, err := req.Option("type").String()
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
typeStr, _, err := req.Option(pinTypeOptionName).String()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -304,7 +331,7 @@ Example:
var keys map[string]RefKeyObject
if len(req.Arguments()) > 0 {
keys, err = pinLsKeys(req.Context(), req.Arguments(), typeStr, n)
keys, err = pinLsKeys(req.Context(), req.Arguments(), typeStr, n, api)
} else {
keys, err = pinLsAll(req.Context(), typeStr, n)
}
@ -323,7 +350,7 @@ Example:
return nil, err
}
quiet, _, err := res.Request().Option("quiet").Bool()
quiet, _, err := res.Request().Option(pinQuietOptionName).Bool()
if err != nil {
return nil, err
}
@ -345,6 +372,10 @@ Example:
},
}
const (
pinUnpinOptionName = "unpin"
)
var updatePinCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Update a recursive pin",
@ -360,58 +391,35 @@ new pin and removing the old one.
cmdkit.StringArg("to-path", true, false, "Path to new object to be pinned."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("unpin", "Remove the old pin.").WithDefault(true),
cmdkit.BoolOption(pinUnpinOptionName, "Remove the old pin.").WithDefault(true),
},
Type: PinOutput{},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
unpin, _, err := req.Option("unpin").Bool()
unpin, _, err := req.Option(pinUnpinOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
from, err := path.ParsePath(req.Arguments()[0])
from, err := iface.ParsePath(req.Arguments()[0])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
to, err := path.ParsePath(req.Arguments()[1])
to, err := iface.ParsePath(req.Arguments()[1])
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
r := &resolver.Resolver{
DAG: n.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
fromc, err := core.ResolveToCid(req.Context(), n.Namesys, r, from)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
toc, err := core.ResolveToCid(req.Context(), n.Namesys, r, to)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
err = n.Pinning.Update(req.Context(), fromc, toc, unpin)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
err = n.Pinning.Flush()
err = api.Pin().Update(req.Context(), from, to, options.Pin.Unpin(unpin))
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -437,13 +445,17 @@ new pin and removing the old one.
},
}
const (
pinVerboseOptionName = "verbose"
)
var verifyPinCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Verify that recursive pins are complete.",
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "Also write the hashes of non-broken pins."),
cmdkit.BoolOption("quiet", "q", "Write just hashes of broken pins."),
cmdkit.BoolOption(pinVerboseOptionName, "Also write the hashes of non-broken pins."),
cmdkit.BoolOption(pinQuietOptionName, "q", "Write just hashes of broken pins."),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
@ -452,8 +464,8 @@ var verifyPinCmd = &cmds.Command{
return
}
verbose, _, _ := res.Request().Option("verbose").Bool()
quiet, _, _ := res.Request().Option("quiet").Bool()
verbose, _, _ := res.Request().Option(pinVerboseOptionName).Bool()
quiet, _, _ := res.Request().Option(pinQuietOptionName).Bool()
if verbose && quiet {
res.SetError(fmt.Errorf("the --verbose and --quiet options can not be used at the same time"), cmdkit.ErrNormal)
@ -470,7 +482,7 @@ var verifyPinCmd = &cmds.Command{
Type: PinVerifyRes{},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
quiet, _, _ := res.Request().Option("quiet").Bool()
quiet, _, _ := res.Request().Option(pinQuietOptionName).Bool()
out, err := unwrapOutput(res.Output())
if err != nil {
@ -501,7 +513,7 @@ type RefKeyList struct {
Keys map[string]RefKeyObject
}
func pinLsKeys(ctx context.Context, args []string, typeStr string, n *core.IpfsNode) (map[string]RefKeyObject, error) {
func pinLsKeys(ctx context.Context, args []string, typeStr string, n *core.IpfsNode, api iface.CoreAPI) (map[string]RefKeyObject, error) {
mode, ok := pin.StringToMode(typeStr)
if !ok {
@ -510,23 +522,18 @@ func pinLsKeys(ctx context.Context, args []string, typeStr string, n *core.IpfsN
keys := make(map[string]RefKeyObject)
r := &resolver.Resolver{
DAG: n.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
for _, p := range args {
pth, err := path.ParsePath(p)
pth, err := iface.ParsePath(p)
if err != nil {
return nil, err
}
c, err := core.ResolveToCid(ctx, n.Namesys, r, pth)
c, err := api.ResolvePath(ctx, pth)
if err != nil {
return nil, err
}
pinType, pinned, err := n.Pinning.IsPinnedWithType(c, mode)
pinType, pinned, err := n.Pinning.IsPinnedWithType(c.Cid(), mode)
if err != nil {
return nil, err
}

View File

@ -14,9 +14,9 @@ import (
u "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
"gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
const kPingTimeout = 10 * time.Second
@ -27,6 +27,10 @@ type PingResult struct {
Text string
}
const (
pingCountOptionName = "count"
)
// ErrPingSelf is returned when the user attempts to ping themself.
var ErrPingSelf = errors.New("error: can't ping self")
@ -43,7 +47,7 @@ trip latency information.
cmdkit.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.IntOption("count", "n", "Number of ping messages to send.").WithDefault(10),
cmdkit.IntOption(pingCountOptionName, "n", "Number of ping messages to send.").WithDefault(10),
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
@ -97,7 +101,7 @@ trip latency information.
n.Peerstore.AddAddr(peerID, addr, pstore.TempAddrTTL) // temporary
}
numPings, _, err := req.Option("count").Int()
numPings, _, err := req.Option(pingCountOptionName).Int()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return

View File

@ -3,24 +3,17 @@ package commands
import (
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"net/http"
"sort"
"sync"
"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"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
floodsub "gx/ipfs/QmPbYVFhKxamZAN9MyrQMDeoGYa6zkQkhAPguwFfzxPM1J/go-libp2p-floodsub"
blocks "gx/ipfs/QmRcHuYzAyswytBuMF78rj3LTChYszomRFXNg4685ZN1WM/go-block-format"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
var PubsubCmd = &cmds.Command{
@ -44,6 +37,17 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
},
}
const (
pubsubDiscoverOptionName = "discover"
)
type pubsubMessage struct {
From []byte `json:"from,omitempty"`
Data []byte `json:"data,omitempty"`
Seqno []byte `json:"seqno,omitempty"`
TopicIDs []string `json:"topicIDs,omitempty"`
}
var PubsubSubCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Subscribe to messages on a given topic.",
@ -72,43 +76,22 @@ This command outputs data in the following encodings:
cmdkit.StringArg("topic", true, false, "String name of topic to subscribe to."),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("discover", "try to discover other peers subscribed to the same topic"),
cmdkit.BoolOption(pubsubDiscoverOptionName, "try to discover other peers subscribed to the same topic"),
},
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
}
// Must be online!
if !n.OnlineMode() {
return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
}
if n.Floodsub == nil {
return fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use")
}
topic := req.Arguments[0]
sub, err := n.Floodsub.Subscribe(topic)
discover, _ := req.Options[pubsubDiscoverOptionName].(bool)
sub, err := api.PubSub().Subscribe(req.Context, topic, options.PubSub.Discover(discover))
if err != nil {
return err
}
defer sub.Cancel()
discover, _ := req.Options["discover"].(bool)
if discover {
go func() {
blk := blocks.NewBlock([]byte("floodsub:" + topic))
err := n.Blocks.AddBlock(blk)
if err != nil {
log.Error("pubsub discovery: ", err)
return
}
connectToPubSubPeers(req.Context, n, blk.Cid())
}()
}
defer sub.Close()
if f, ok := res.(http.Flusher); ok {
f.Flush()
@ -122,15 +105,17 @@ This command outputs data in the following encodings:
return err
}
err = res.Emit(msg)
if err != nil {
return err
}
res.Emit(&pubsubMessage{
Data: msg.Data(),
From: []byte(msg.From()),
Seqno: msg.Seq(),
TopicIDs: msg.Topics(),
})
}
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
m, ok := v.(*floodsub.Message)
m, ok := v.(*pubsubMessage)
if !ok {
return fmt.Errorf("unexpected type: %T", v)
}
@ -139,7 +124,7 @@ This command outputs data in the following encodings:
return err
}),
"ndpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
m, ok := v.(*floodsub.Message)
m, ok := v.(*pubsubMessage)
if !ok {
return fmt.Errorf("unexpected type: %T", v)
}
@ -149,7 +134,7 @@ This command outputs data in the following encodings:
return err
}),
"lenpayload": cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
m, ok := v.(*floodsub.Message)
m, ok := v.(*pubsubMessage)
if !ok {
return fmt.Errorf("unexpected type: %T", v)
}
@ -162,31 +147,7 @@ This command outputs data in the following encodings:
return err
}),
},
Type: floodsub.Message{},
}
func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid cid.Cid) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
wg := &sync.WaitGroup{}
for p := range provs {
wg.Add(1)
go func(pi pstore.PeerInfo) {
defer wg.Done()
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
defer cancel()
err := n.PeerHost.Connect(ctx, pi)
if err != nil {
log.Info("pubsub discover: ", err)
return
}
log.Info("connected to pubsub peer:", pi.ID)
}(p)
}
wg.Wait()
Type: pubsubMessage{},
}
var PubsubPubCmd = &cmds.Command{
@ -206,20 +167,11 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
cmdkit.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(),
},
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
}
// Must be online!
if !n.OnlineMode() {
return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
}
if n.Floodsub == nil {
return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
}
topic := req.Arguments[0]
err = req.ParseBodyArgs()
@ -228,7 +180,7 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
}
for _, data := range req.Arguments[1:] {
if err := n.Floodsub.Publish(topic, []byte(data)); err != nil {
if err := api.PubSub().Publish(req.Context, topic, []byte(data)); err != nil {
return err
}
}
@ -250,21 +202,17 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
`,
},
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
}
// Must be online!
if !n.OnlineMode() {
return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
l, err := api.PubSub().Ls(req.Context)
if err != nil {
return err
}
if n.Floodsub == nil {
return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
}
return cmds.EmitOnce(res, stringList{n.Floodsub.GetTopics()})
return cmds.EmitOnce(res, stringList{l})
},
Type: stringList{},
Encoders: cmds.EncoderMap{
@ -304,26 +252,21 @@ To use, the daemon must be run with '--enable-pubsub-experiment'.
cmdkit.StringArg("topic", false, false, "topic to list connected peers of"),
},
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
}
// Must be online!
if !n.OnlineMode() {
return cmdkit.Errorf(cmdkit.ErrClient, ErrNotOnline.Error())
}
if n.Floodsub == nil {
return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use")
}
var topic string
if len(req.Arguments) == 1 {
topic = req.Arguments[0]
}
peers := n.Floodsub.ListPeers(topic)
peers, err := api.PubSub().Peers(req.Context, options.PubSub.Topic(topic))
if err != nil {
return err
}
list := &stringList{make([]string, 0, len(peers))}
for _, peer := range peers {

View File

@ -12,8 +12,8 @@ import (
e "github.com/ipfs/go-ipfs/core/commands/e"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
@ -22,6 +22,14 @@ type KeyList struct {
Keys []cid.Cid
}
const (
refsFormatOptionName = "format"
refsEdgesOptionName = "edges"
refsUniqueOptionName = "unique"
refsRecursiveOptionName = "recursive"
refsMaxDepthOptionName = "max-depth"
)
// KeyListTextMarshaler outputs a KeyList as plaintext, one key per line
func KeyListTextMarshaler(res cmds.Response) (io.Reader, error) {
out, err := unwrapOutput(res.Output())
@ -60,11 +68,11 @@ NOTE: List all references recursively by using the flag '-r'.
cmdkit.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.StringOption("format", "Emit edges with given format. Available tokens: <src> <dst> <linkname>.").WithDefault("<dst>"),
cmdkit.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`."),
cmdkit.BoolOption("unique", "u", "Omit duplicate refs from output."),
cmdkit.BoolOption("recursive", "r", "Recursively list links of child nodes."),
cmdkit.IntOption("max-depth", "Only for recursive refs, limits fetch and listing to the given depth").WithDefault(-1),
cmdkit.StringOption(refsFormatOptionName, "Emit edges with given format. Available tokens: <src> <dst> <linkname>.").WithDefault("<dst>"),
cmdkit.BoolOption(refsEdgesOptionName, "e", "Emit edge format: `<from> -> <to>`."),
cmdkit.BoolOption(refsUniqueOptionName, "u", "Omit duplicate refs from output."),
cmdkit.BoolOption(refsRecursiveOptionName, "r", "Recursively list links of child nodes."),
cmdkit.IntOption(refsMaxDepthOptionName, "Only for recursive refs, limits fetch and listing to the given depth").WithDefault(-1),
},
Run: func(req cmds.Request, res cmds.Response) {
ctx := req.Context()
@ -74,19 +82,19 @@ NOTE: List all references recursively by using the flag '-r'.
return
}
unique, _, err := req.Option("unique").Bool()
unique, _, err := req.Option(refsUniqueOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
recursive, _, err := req.Option("recursive").Bool()
recursive, _, err := req.Option(refsRecursiveOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
maxDepth, _, err := req.Option("max-depth").Int()
maxDepth, _, err := req.Option(refsMaxDepthOptionName).Int()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -96,13 +104,13 @@ NOTE: List all references recursively by using the flag '-r'.
maxDepth = 1 // write only direct refs
}
format, _, err := req.Option("format").String()
format, _, err := req.Option(refsFormatOptionName).String()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
edges, _, err := req.Option("edges").Bool()
edges, _, err := req.Option(refsEdgesOptionName).Bool()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return

View File

@ -19,9 +19,9 @@ import (
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
)
type RepoVersion struct {
@ -51,6 +51,11 @@ type GcResult struct {
Error string `json:",omitempty"`
}
const (
repoStreamErrorsOptionName = "stream-errors"
repoQuietOptionName = "quiet"
)
var repoGcCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Perform a garbage collection sweep on the repo.",
@ -61,8 +66,8 @@ order to reclaim hard disk space.
`,
},
Options: []cmdkit.Option{
cmdkit.BoolOption("stream-errors", "Stream errors."),
cmdkit.BoolOption("quiet", "q", "Write minimal output."),
cmdkit.BoolOption(repoStreamErrorsOptionName, "Stream errors."),
cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
},
Run: func(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
@ -70,7 +75,7 @@ order to reclaim hard disk space.
return err
}
streamErrors, _ := req.Options["stream-errors"].(bool)
streamErrors, _ := req.Options[repoStreamErrorsOptionName].(bool)
gcOutChan := corerepo.GarbageCollectAsync(n, req.Context)
@ -101,7 +106,7 @@ order to reclaim hard disk space.
Type: GcResult{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
quiet, _ := req.Options["quiet"].(bool)
quiet, _ := req.Options[repoQuietOptionName].(bool)
obj, ok := v.(*GcResult)
if !ok {
@ -124,6 +129,11 @@ order to reclaim hard disk space.
},
}
const (
repoSizeOnlyOptionName = "size-only"
repoHumanOptionName = "human"
)
var repoStatCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Get stats for the currently used repo.",
@ -139,8 +149,8 @@ Version string The repo version.
`,
},
Options: []cmdkit.Option{
cmdkit.BoolOption("size-only", "Only report RepoSize and StorageMax."),
cmdkit.BoolOption("human", "Output sizes in MiB."),
cmdkit.BoolOption(repoSizeOnlyOptionName, "Only report RepoSize and StorageMax."),
cmdkit.BoolOption(repoHumanOptionName, "Output sizes in MiB."),
},
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
@ -148,7 +158,7 @@ Version string The repo version.
return err
}
sizeOnly, _ := req.Options["size-only"].(bool)
sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)
if sizeOnly {
sizeStat, err := corerepo.RepoSize(req.Context, n)
if err != nil {
@ -178,8 +188,8 @@ Version string The repo version.
wtr := tabwriter.NewWriter(w, 0, 0, 1, ' ', 0)
defer wtr.Flush()
human, _ := req.Options["human"].(bool)
sizeOnly, _ := req.Options["size-only"].(bool)
human, _ := req.Options[repoHumanOptionName].(bool)
sizeOnly, _ := req.Options[repoSizeOnlyOptionName].(bool)
printSize := func(name string, size uint64) {
sizeInMiB := size / (1024 * 1024)
@ -360,7 +370,7 @@ var repoVersionCmd = &oldcmds.Command{
},
Options: []cmdkit.Option{
cmdkit.BoolOption("quiet", "q", "Write minimal output."),
cmdkit.BoolOption(repoQuietOptionName, "q", "Write minimal output."),
},
Run: func(req oldcmds.Request, res oldcmds.Response) {
res.SetOutput(&RepoVersion{

View File

@ -14,12 +14,18 @@ import (
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
ns "github.com/ipfs/go-ipfs/namesys"
nsopts "github.com/ipfs/go-ipfs/namesys/opts"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
)
const (
resolveRecursiveOptionName = "recursive"
resolveDhtRecordCountOptionName = "dht-record-count"
resolveDhtTimeoutOptionName = "dht-timeout"
)
var ResolveCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Resolve the value of names to IPFS.",
@ -64,9 +70,9 @@ Resolve the value of an IPFS DAG path:
cmdkit.StringArg("name", true, false, "The name to resolve.").EnableStdin(),
},
Options: []cmdkit.Option{
cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."),
cmdkit.IntOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."),
cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."),
cmdkit.BoolOption(resolveRecursiveOptionName, "r", "Resolve until the result is an IPFS name."),
cmdkit.IntOption(resolveDhtRecordCountOptionName, "dhtrc", "Number of records to request for DHT resolution."),
cmdkit.StringOption(resolveDhtTimeoutOptionName, "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 {
api, err := cmdenv.GetApi(env)
@ -87,12 +93,12 @@ Resolve the value of an IPFS DAG path:
}
name := req.Arguments[0]
recursive, _ := req.Options["recursive"].(bool)
recursive, _ := req.Options[resolveRecursiveOptionName].(bool)
// the case when ipns is resolved step by step
if strings.HasPrefix(name, "/ipns/") && !recursive {
rc, rcok := req.Options["dht-record-count"].(uint)
dhtt, dhttok := req.Options["dht-timeout"].(string)
rc, rcok := req.Options[resolveDhtRecordCountOptionName].(uint)
dhtt, dhttok := req.Options[resolveDhtTimeoutOptionName].(string)
ropts := []options.NameResolveOption{
options.Name.ResolveOption(nsopts.Depth(1)),
}

View File

@ -71,6 +71,7 @@ TOOL COMMANDS
version Show ipfs version information
update Download and apply go-ipfs updates
commands List all available commands
cid Convert and discover properties of CIDs
Use 'ipfs <command> --help' to learn more about each command.
@ -136,13 +137,14 @@ var rootSubcommands = map[string]*cmds.Command{
"p2p": lgc.NewCommand(P2PCmd),
"refs": lgc.NewCommand(RefsCmd),
"resolve": ResolveCmd,
"swarm": lgc.NewCommand(SwarmCmd),
"swarm": SwarmCmd,
"tar": lgc.NewCommand(TarCmd),
"file": lgc.NewCommand(unixfs.UnixFSCmd),
"update": lgc.NewCommand(ExternalBinary()),
"urlstore": urlStoreCmd,
"version": lgc.NewCommand(VersionCmd),
"shutdown": daemonShutdownCmd,
"cid": CidCmd,
}
// RootRO is the readonly version of Root

View File

@ -33,6 +33,13 @@ for your IPFS node.`,
},
}
const (
statPeerOptionName = "peer"
statProtoOptionName = "proto"
statPollOptionName = "poll"
statIntervalOptionName = "interval"
)
var statBwCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Print ipfs bandwidth information.",
@ -71,10 +78,10 @@ Example:
`,
},
Options: []cmdkit.Option{
cmdkit.StringOption("peer", "p", "Specify a peer to print bandwidth for."),
cmdkit.StringOption("proto", "t", "Specify a protocol to print bandwidth for."),
cmdkit.BoolOption("poll", "Print bandwidth at an interval."),
cmdkit.StringOption("interval", "i", `Time interval to wait between updating output, if 'poll' is true.
cmdkit.StringOption(statPeerOptionName, "p", "Specify a peer to print bandwidth for."),
cmdkit.StringOption(statProtoOptionName, "t", "Specify a protocol to print bandwidth for."),
cmdkit.BoolOption(statPollOptionName, "Print bandwidth at an interval."),
cmdkit.StringOption(statIntervalOptionName, "i", `Time interval to wait between updating output, if 'poll' is true.
This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are:
"ns", "us" (or "µs"), "ms", "s", "m", "h".`).WithDefault("1s"),
@ -95,7 +102,7 @@ Example:
return fmt.Errorf("bandwidth reporter disabled in config")
}
pstr, pfound := req.Options["peer"].(string)
pstr, pfound := req.Options[statPeerOptionName].(string)
tstr, tfound := req.Options["proto"].(string)
if pfound && tfound {
return cmdkit.Errorf(cmdkit.ErrClient, "please only specify peer OR protocol")
@ -110,13 +117,13 @@ Example:
pid = checkpid
}
timeS, _ := req.Options["interval"].(string)
timeS, _ := req.Options[statIntervalOptionName].(string)
interval, err := time.ParseDuration(timeS)
if err != nil {
return err
}
doPoll, _ := req.Options["poll"].(bool)
doPoll, _ := req.Options[statPollOptionName].(bool)
for {
if pfound {
stats := nd.Reporter.GetBandwidthForPeer(pid)
@ -142,7 +149,7 @@ Example:
Type: metrics.Stats{},
PostRun: cmds.PostRunMap{
cmds.CLI: func(res cmds.Response, re cmds.ResponseEmitter) error {
polling, _ := res.Request().Options["poll"].(bool)
polling, _ := res.Request().Options[statPollOptionName].(bool)
if polling {
fmt.Fprintln(os.Stdout, "Total Up Total Down Rate Up Rate Down")

View File

@ -1,7 +1,6 @@
package commands
import (
"bytes"
"errors"
"fmt"
"io"
@ -9,20 +8,22 @@ import (
"sort"
"strings"
cmds "github.com/ipfs/go-ipfs/commands"
e "github.com/ipfs/go-ipfs/core/commands/e"
repo "github.com/ipfs/go-ipfs/repo"
"github.com/ipfs/go-ipfs/commands"
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
"github.com/ipfs/go-ipfs/core/commands/e"
"github.com/ipfs/go-ipfs/repo"
"github.com/ipfs/go-ipfs/repo/fsrepo"
swarm "gx/ipfs/QmPQoCVRHaGD25VffyB7DFV5qP65hFSQJdSDy75P1vYBKe/go-libp2p-swarm"
mafilter "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
iaddr "gx/ipfs/QmSzdvo9aPzLj4HXWTcgGAp8N84tZc8LbLmFZFwUb1dpWk/go-ipfs-addr"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
"gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
inet "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
"gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
"gx/ipfs/Qmb55o5PuhvqwjdVLvc4VV3ouLziYc6TfwM9LC6GwBQokn/go-libp2p-swarm"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
inet "gx/ipfs/QmfDPh144WGBqRxZb1TGDHerbMnZATrHZggAPw7putNnBq/go-libp2p-net"
iaddr "gx/ipfs/QmesXvbRGyKQn1XbPHx1Mr5E6RTJYR9c8zwFVuGZq9Aa1j/go-ipfs-addr"
)
type stringList struct {
@ -51,6 +52,13 @@ ipfs peers in the internet.
},
}
const (
swarmVerboseOptionName = "verbose"
swarmStreamsOptionName = "streams"
swarmLatencyOptionName = "latency"
swarmDirectionOptionName = "direction"
)
var swarmPeersCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "List peers with open connections.",
@ -59,54 +67,45 @@ var swarmPeersCmd = &cmds.Command{
`,
},
Options: []cmdkit.Option{
cmdkit.BoolOption("verbose", "v", "display all extra information"),
cmdkit.BoolOption("streams", "Also list information about open streams for each peer"),
cmdkit.BoolOption("latency", "Also list information about latency to each peer"),
cmdkit.BoolOption("direction", "Also list information about the direction of connection"),
cmdkit.BoolOption(swarmVerboseOptionName, "v", "display all extra information"),
cmdkit.BoolOption(swarmStreamsOptionName, "Also list information about open streams for each peer"),
cmdkit.BoolOption(swarmLatencyOptionName, "Also list information about latency to each peer"),
cmdkit.BoolOption(swarmDirectionOptionName, "Also list information about the direction of connection"),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
verbose, _ := req.Options[swarmVerboseOptionName].(bool)
latency, _ := req.Options[swarmLatencyOptionName].(bool)
streams, _ := req.Options[swarmStreamsOptionName].(bool)
direction, _ := req.Options[swarmDirectionOptionName].(bool)
conns, err := api.Swarm().Peers(req.Context)
if err != nil {
return err
}
verbose, _, _ := req.Option("verbose").Bool()
latency, _, _ := req.Option("latency").Bool()
streams, _, _ := req.Option("streams").Bool()
direction, _, _ := req.Option("direction").Bool()
conns := n.PeerHost.Network().Conns()
var out connInfos
for _, c := range conns {
pid := c.RemotePeer()
addr := c.RemoteMultiaddr()
ci := connInfo{
Addr: addr.String(),
Peer: pid.Pretty(),
Addr: c.Address().String(),
Peer: c.ID().Pretty(),
}
/*
// FIXME(steb):
swcon, ok := c.(*swarm.Conn)
if ok {
ci.Muxer = fmt.Sprintf("%T", swcon.StreamConn().Conn())
}
*/
if verbose || direction {
// set direction
ci.Direction = c.Stat().Direction
ci.Direction = c.Direction()
}
if verbose || latency {
lat := n.Peerstore.LatencyEWMA(pid)
lat, err := c.Latency()
if err != nil {
return err
}
if lat == 0 {
ci.Latency = "n/a"
} else {
@ -114,10 +113,13 @@ var swarmPeersCmd = &cmds.Command{
}
}
if verbose || streams {
strs := c.GetStreams()
strs, err := c.Streams()
if err != nil {
return err
}
for _, s := range strs {
ci.Streams = append(ci.Streams, streamInfo{Protocol: string(s.Protocol())})
ci.Streams = append(ci.Streams, streamInfo{Protocol: string(s)})
}
}
sort.Sort(&ci)
@ -125,50 +127,43 @@ var swarmPeersCmd = &cmds.Command{
}
sort.Sort(&out)
res.SetOutput(&out)
return cmds.EmitOnce(res, &out)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
ci, ok := v.(*connInfos)
if !ok {
return nil, e.TypeErr(ci, v)
return e.TypeErr(ci, v)
}
buf := new(bytes.Buffer)
pipfs := ma.ProtocolWithCode(ma.P_IPFS).Name
for _, info := range ci.Peers {
ids := fmt.Sprintf("/%s/%s", pipfs, info.Peer)
if strings.HasSuffix(info.Addr, ids) {
fmt.Fprintf(buf, "%s", info.Addr)
fmt.Fprintf(w, "%s", info.Addr)
} else {
fmt.Fprintf(buf, "%s%s", info.Addr, ids)
fmt.Fprintf(w, "%s%s", info.Addr, ids)
}
if info.Latency != "" {
fmt.Fprintf(buf, " %s", info.Latency)
fmt.Fprintf(w, " %s", info.Latency)
}
if info.Direction != inet.DirUnknown {
fmt.Fprintf(buf, " %s", directionString(info.Direction))
fmt.Fprintf(w, " %s", directionString(info.Direction))
}
fmt.Fprintln(buf)
fmt.Fprintln(w)
for _, s := range info.Streams {
if s.Protocol == "" {
s.Protocol = "<no protocol name>"
}
fmt.Fprintf(buf, " %s\n", s.Protocol)
fmt.Fprintf(w, " %s\n", s.Protocol)
}
}
return buf, nil
},
return nil
}),
},
Type: connInfos{},
}
@ -237,41 +232,32 @@ var swarmAddrsCmd = &cmds.Command{
"local": swarmAddrsLocalCmd,
"listen": swarmAddrsListenCmd,
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
addrs, err := api.Swarm().KnownAddrs(req.Context)
if err != nil {
return err
}
addrs := make(map[string][]string)
ps := n.PeerHost.Network().Peerstore()
for _, p := range ps.Peers() {
out := make(map[string][]string)
for p, paddrs := range addrs {
s := p.Pretty()
for _, a := range ps.Addrs(p) {
addrs[s] = append(addrs[s], a.String())
for _, a := range paddrs {
out[s] = append(out[s], a.String())
}
sort.Sort(sort.StringSlice(addrs[s]))
}
res.SetOutput(&addrMap{Addrs: addrs})
return cmds.EmitOnce(res, &addrMap{Addrs: out})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(func(req *cmds.Request, w io.Writer, v interface{}) error {
m, ok := v.(*addrMap)
if !ok {
return nil, e.TypeErr(m, v)
return e.TypeErr(m, v)
}
// sort the ids first
@ -281,16 +267,15 @@ var swarmAddrsCmd = &cmds.Command{
}
sort.Sort(sort.StringSlice(ids))
buf := new(bytes.Buffer)
for _, p := range ids {
paddrs := m.Addrs[p]
buf.WriteString(fmt.Sprintf("%s (%d)\n", p, len(paddrs)))
fmt.Fprintf(w, "%s (%d)\n", p, len(paddrs))
for _, addr := range paddrs {
buf.WriteString("\t" + addr + "\n")
fmt.Fprintf(w, "\t"+addr+"\n")
}
}
return buf, nil
},
return nil
}),
},
Type: addrMap{},
}
@ -305,36 +290,37 @@ var swarmAddrsLocalCmd = &cmds.Command{
Options: []cmdkit.Option{
cmdkit.BoolOption("id", "Show peer ID in addresses."),
},
Run: func(req cmds.Request, res cmds.Response) {
iCtx := req.InvocContext()
n, err := iCtx.GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
showid, _ := req.Options["id"].(bool)
self, err := api.Key().Self(req.Context)
if err != nil {
return err
}
showid, _, _ := req.Option("id").Bool()
id := n.Identity.Pretty()
maddrs, err := api.Swarm().LocalAddrs(req.Context)
if err != nil {
return err
}
var addrs []string
for _, addr := range n.PeerHost.Addrs() {
for _, addr := range maddrs {
saddr := addr.String()
if showid {
saddr = path.Join(saddr, "ipfs", id)
saddr = path.Join(saddr, "ipfs", self.ID().Pretty())
}
addrs = append(addrs, saddr)
}
sort.Sort(sort.StringSlice(addrs))
res.SetOutput(&stringList{addrs})
return cmds.EmitOnce(res, &stringList{addrs})
},
Type: stringList{},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
}
@ -345,24 +331,16 @@ var swarmAddrsListenCmd = &cmds.Command{
'ipfs swarm addrs listen' lists all interface addresses the node is listening on.
`,
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
return err
}
var addrs []string
maddrs, err := n.PeerHost.Network().InterfaceListenAddresses()
maddrs, err := api.Swarm().ListenAddrs(req.Context)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
for _, addr := range maddrs {
@ -370,11 +348,11 @@ var swarmAddrsListenCmd = &cmds.Command{
}
sort.Sort(sort.StringSlice(addrs))
res.SetOutput(&stringList{addrs})
return cmds.EmitOnce(res, &stringList{addrs})
},
Type: stringList{},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
}
@ -392,53 +370,34 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3
Arguments: []cmdkit.Argument{
cmdkit.StringArg("address", true, true, "Address of peer to connect to.").EnableStdin(),
},
Run: func(req cmds.Request, res cmds.Response) {
ctx := req.Context()
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
addrs := req.Arguments()
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
}
// FIXME(steb): Nasty
swrm, ok := n.PeerHost.Network().(*swarm.Swarm)
if !ok {
res.SetError(fmt.Errorf("peerhost network was not swarm"), cmdkit.ErrNormal)
return
}
addrs := req.Arguments
pis, err := peersWithAddresses(addrs)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
output := make([]string, len(pis))
for i, pi := range pis {
swrm.Backoff().Clear(pi.ID)
output[i] = "connect " + pi.ID.Pretty()
err := n.PeerHost.Connect(ctx, pi)
err := api.Swarm().Connect(req.Context, pi)
if err != nil {
res.SetError(fmt.Errorf("%s failure: %s", output[i], err), cmdkit.ErrNormal)
return
return fmt.Errorf("%s failure: %s", output[i], err)
}
output[i] += " success"
}
res.SetOutput(&stringList{output})
return cmds.EmitOnce(res, &stringList{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
Type: stringList{},
}
@ -459,91 +418,35 @@ it will reconnect.
Arguments: []cmdkit.Argument{
cmdkit.StringArg("address", true, true, "Address of peer to disconnect from.").EnableStdin(),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
api, err := cmdenv.GetApi(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
addrs := req.Arguments()
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrClient)
return
}
iaddrs, err := parseAddresses(addrs)
iaddrs, err := parseAddresses(req.Arguments)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
output := make([]string, len(iaddrs))
for i, addr := range iaddrs {
taddr := addr.Transport()
id := addr.ID()
output[i] = "disconnect " + id.Pretty()
output[i] = "disconnect " + addr.ID().Pretty()
net := n.PeerHost.Network()
if taddr == nil {
if net.Connectedness(id) != inet.Connected {
output[i] += " failure: not connected"
} else if err := net.ClosePeer(id); err != nil {
output[i] += " failure: " + err.Error()
} else {
output[i] += " success"
}
if err := api.Swarm().Disconnect(req.Context, addr.Multiaddr()); err != nil {
output[i] += " failure: " + err.Error()
} else {
found := false
for _, conn := range net.ConnsToPeer(id) {
if !conn.RemoteMultiaddr().Equal(taddr) {
continue
}
if err := conn.Close(); err != nil {
output[i] += " failure: " + err.Error()
} else {
output[i] += " success"
}
found = true
break
}
if !found {
output[i] += " failure: conn not found"
}
output[i] += " success"
}
}
res.SetOutput(&stringList{output})
return cmds.EmitOnce(res, &stringList{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
Type: stringList{},
}
func stringListMarshaler(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
if err != nil {
return nil, err
}
list, ok := v.(*stringList)
if !ok {
return nil, e.TypeErr(list, v)
}
buf := new(bytes.Buffer)
for _, s := range list.Strings {
buf.WriteString(s)
buf.WriteString("\n")
}
return buf, nil
}
// parseAddresses is a function that takes in a slice of string peer addresses
// (multiaddr + peerid) and returns slices of multiaddrs and peerids.
func parseAddresses(addrs []string) (iaddrs []iaddr.IPFSAddr, err error) {
@ -608,38 +511,34 @@ Filters default to those specified under the "Swarm.AddrFilters" config key.
"add": swarmFiltersAddCmd,
"rm": swarmFiltersRmCmd,
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrNormal)
return
return ErrNotOnline
}
// FIXME(steb)
swrm, ok := n.PeerHost.Network().(*swarm.Swarm)
if !ok {
res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
return
return errors.New("failed to cast network to swarm network")
}
var output []string
for _, f := range swrm.Filters.Filters() {
s, err := mafilter.ConvertIPNet(f)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
output = append(output, s)
}
res.SetOutput(&stringList{output})
return cmds.EmitOnce(res, &stringList{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
Type: stringList{},
}
@ -656,63 +555,54 @@ add your filters to the ipfs config file.
Arguments: []cmdkit.Argument{
cmdkit.StringArg("address", true, true, "Multiaddr to filter.").EnableStdin(),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrNormal)
return
return ErrNotOnline
}
// FIXME(steb)
swrm, ok := n.PeerHost.Network().(*swarm.Swarm)
if !ok {
res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
return
return errors.New("failed to cast network to swarm network")
}
if len(req.Arguments()) == 0 {
res.SetError(errors.New("no filters to add"), cmdkit.ErrClient)
return
if len(req.Arguments) == 0 {
return errors.New("no filters to add")
}
r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
r, err := fsrepo.Open(env.(*commands.Context).ConfigRoot)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
defer r.Close()
cfg, err := r.Config()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
for _, arg := range req.Arguments() {
for _, arg := range req.Arguments {
mask, err := mafilter.NewMask(arg)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
swrm.Filters.AddDialFilter(mask)
}
added, err := filtersAdd(r, cfg, req.Arguments())
added, err := filtersAdd(r, cfg, req.Arguments)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
res.SetOutput(&stringList{added})
return cmds.EmitOnce(res, &stringList{added})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
Type: stringList{},
}
@ -729,37 +619,32 @@ remove your filters from the ipfs config file.
Arguments: []cmdkit.Argument{
cmdkit.StringArg("address", true, true, "Multiaddr filter to remove.").EnableStdin(),
},
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.InvocContext().GetNode()
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
n, err := cmdenv.GetNode(env)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if n.PeerHost == nil {
res.SetError(ErrNotOnline, cmdkit.ErrNormal)
return
return ErrNotOnline
}
swrm, ok := n.PeerHost.Network().(*swarm.Swarm)
if !ok {
res.SetError(errors.New("failed to cast network to swarm network"), cmdkit.ErrNormal)
return
return errors.New("failed to cast network to swarm network")
}
r, err := fsrepo.Open(req.InvocContext().ConfigRoot)
r, err := fsrepo.Open(env.(*commands.Context).ConfigRoot)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
defer r.Close()
cfg, err := r.Config()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
if req.Arguments()[0] == "all" || req.Arguments()[0] == "*" {
if req.Arguments[0] == "all" || req.Arguments[0] == "*" {
fs := swrm.Filters.Filters()
for _, f := range fs {
swrm.Filters.Remove(f)
@ -767,35 +652,30 @@ remove your filters from the ipfs config file.
removed, err := filtersRemoveAll(r, cfg)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
res.SetOutput(&stringList{removed})
return
return cmds.EmitOnce(res, &stringList{removed})
}
for _, arg := range req.Arguments() {
for _, arg := range req.Arguments {
mask, err := mafilter.NewMask(arg)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
swrm.Filters.Remove(mask)
}
removed, err := filtersRemove(r, cfg, req.Arguments())
removed, err := filtersRemove(r, cfg, req.Arguments)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
return err
}
res.SetOutput(&stringList{removed})
return cmds.EmitOnce(res, &stringList{removed})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeEncoder(stringListEncoder),
},
Type: stringList{},
}

View File

@ -7,10 +7,10 @@ import (
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
e "github.com/ipfs/go-ipfs/core/commands/e"
"github.com/ipfs/go-ipfs/core/coreunix"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
tar "github.com/ipfs/go-ipfs/tar"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
"gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
)
@ -60,12 +60,12 @@ represent it.
c := node.Cid()
fi.FileName()
res.SetOutput(&coreunix.AddedObject{
res.SetOutput(&coreiface.AddEvent{
Name: fi.FileName(),
Hash: c.String(),
})
},
Type: coreunix.AddedObject{},
Type: coreiface.AddEvent{},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
v, err := unwrapOutput(res.Output())
@ -73,7 +73,7 @@ represent it.
return nil, err
}
o, ok := v.(*coreunix.AddedObject)
o, ok := v.(*coreiface.AddEvent)
if !ok {
return nil, e.TypeErr(o, v)
}

View File

@ -7,16 +7,13 @@ import (
"sort"
"text/tabwriter"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
cmds "github.com/ipfs/go-ipfs/commands"
core "github.com/ipfs/go-ipfs/core"
e "github.com/ipfs/go-ipfs/core/commands/e"
unixfs "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
merkledag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
iface "github.com/ipfs/go-ipfs/core/coreapi/interface"
unixfs "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
merkledag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
)
type LsLink struct {
@ -82,6 +79,12 @@ possible, please use 'ipfs ls' instead.
return
}
api, err := req.InvocContext().GetApi()
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
paths := req.Arguments()
output := LsOutput{
@ -89,15 +92,16 @@ possible, please use 'ipfs ls' instead.
Objects: map[string]*LsObject{},
}
for _, fpath := range paths {
for _, p := range paths {
ctx := req.Context()
resolver := &resolver.Resolver{
DAG: node.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
fpath, err := iface.ParsePath(p)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
}
merkleNode, err := core.Resolve(ctx, node.Namesys, resolver, path.Path(fpath))
merkleNode, err := api.ResolveNode(ctx, fpath)
if err != nil {
res.SetError(err, cmdkit.ErrNormal)
return
@ -106,7 +110,7 @@ possible, please use 'ipfs ls' instead.
c := merkleNode.Cid()
hash := c.String()
output.Arguments[fpath] = hash
output.Arguments[p] = hash
if _, ok := output.Objects[hash]; ok {
// duplicate argument for an already-listed node

View File

@ -10,12 +10,12 @@ import (
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
balanced "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/balanced"
ihelper "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/helpers"
trickle "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/trickle"
cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
balanced "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/balanced"
ihelper "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/helpers"
trickle "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/trickle"
chunk "gx/ipfs/QmULKgr55cSWR8Kiwy3cVRcAiGVnR6EVSaB7hJcWS4138p/go-ipfs-chunker"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
chunk "gx/ipfs/QmbrQ27wGQeE8spxjbw9mk5Ef7as4tRFSnWLkEGg4xeg2f/go-ipfs-chunker"
)
var urlStoreCmd = &cmds.Command{

View File

@ -22,6 +22,13 @@ type VersionOutput struct {
Golang string
}
const (
versionNumberOptionName = "number"
versionCommitOptionName = "commit"
versionRepoOptionName = "repo"
versionAllOptionName = "all"
)
var VersionCmd = &cmds.Command{
Helptext: cmdkit.HelpText{
Tagline: "Show ipfs version information.",
@ -29,10 +36,10 @@ var VersionCmd = &cmds.Command{
},
Options: []cmdkit.Option{
cmdkit.BoolOption("number", "n", "Only show the version number."),
cmdkit.BoolOption("commit", "Show the commit hash."),
cmdkit.BoolOption("repo", "Show repo version."),
cmdkit.BoolOption("all", "Show all version information"),
cmdkit.BoolOption(versionNumberOptionName, "n", "Only show the version number."),
cmdkit.BoolOption(versionCommitOptionName, "Show the commit hash."),
cmdkit.BoolOption(versionRepoOptionName, "Show repo version."),
cmdkit.BoolOption(versionAllOptionName, "Show all version information"),
},
Run: func(req cmds.Request, res cmds.Response) {
res.SetOutput(&VersionOutput{
@ -55,7 +62,7 @@ var VersionCmd = &cmds.Command{
return nil, e.TypeErr(version, v)
}
repo, _, err := res.Request().Option("repo").Bool()
repo, _, err := res.Request().Option(versionRepoOptionName).Bool()
if err != nil {
return nil, err
}
@ -64,7 +71,7 @@ var VersionCmd = &cmds.Command{
return strings.NewReader(version.Repo + "\n"), nil
}
commit, _, err := res.Request().Option("commit").Bool()
commit, _, err := res.Request().Option(versionCommitOptionName).Bool()
commitTxt := ""
if err != nil {
return nil, err
@ -73,7 +80,7 @@ var VersionCmd = &cmds.Command{
commitTxt = "-" + version.Commit
}
number, _, err := res.Request().Option("number").Bool()
number, _, err := res.Request().Option(versionNumberOptionName).Bool()
if err != nil {
return nil, err
}
@ -81,7 +88,7 @@ var VersionCmd = &cmds.Command{
return strings.NewReader(fmt.Sprintln(version.Version + commitTxt)), nil
}
all, _, err := res.Request().Option("all").Bool()
all, _, err := res.Request().Option(versionAllOptionName).Bool()
if err != nil {
return nil, err
}

View File

@ -30,53 +30,53 @@ import (
pin "github.com/ipfs/go-ipfs/pin"
repo "github.com/ipfs/go-ipfs/repo"
pnet "gx/ipfs/QmNmyLmysLFuSRjNTW8XrbovrNYFbZoMknTcpYR2AvvDc3/go-libp2p-pnet"
metrics "gx/ipfs/QmNn6gcjBXpg8kccr9zEV7UVBpqAw8FZEiQ6DksvzyTQ5K/go-libp2p-metrics"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
quic "gx/ipfs/QmPWMfcxNC7txnUvT21xdivgRJfJ9e7YuC5nCn6JEALFQv/go-libp2p-quic-transport"
psrouter "gx/ipfs/QmPbLCBNGvyQhs3xK64cbobq7sN1Hdn6Ud9pkhsZME1sqT/go-libp2p-pubsub-router"
floodsub "gx/ipfs/QmPbYVFhKxamZAN9MyrQMDeoGYa6zkQkhAPguwFfzxPM1J/go-libp2p-floodsub"
mfs "gx/ipfs/QmPbuswDwcPT4WquGqGoeBBDuuBaUmbZJFYiaes6vkgXYJ/go-mfs"
u "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util"
ic "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
bitswap "gx/ipfs/QmQHbKeMWRNT8koMhh2DrTXZWepYVoGPNXni6JG1L3BhGq/go-bitswap"
bsnet "gx/ipfs/QmQHbKeMWRNT8koMhh2DrTXZWepYVoGPNXni6JG1L3BhGq/go-bitswap/network"
p2phost "gx/ipfs/QmQKod7iLxQK6X3aFYvhDDnFdXo3QjxKeL2F7UrPtdKQR2/go-libp2p-host"
"gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path/resolver"
nilrouting "gx/ipfs/QmQqPdGQfsfQTpRUUzgD3d2RzWHJffZsSqwopnZ2BkiezW/go-ipfs-routing/none"
offroute "gx/ipfs/QmQqPdGQfsfQTpRUUzgD3d2RzWHJffZsSqwopnZ2BkiezW/go-ipfs-routing/offline"
mplex "gx/ipfs/QmQvMxiavoMJzuLPuqrzVX4nXZpMks29hqpv13d81aJNEF/go-smux-multiplex"
exchange "gx/ipfs/QmR1nncPsZR14A4hWr39mq8Lm7BGgS68bHVT9nop8NpWEM/go-ipfs-exchange-interface"
circuit "gx/ipfs/QmS5X31wA86RSjQqCUHG2CLPoFNnBZ3UMy1ikfBHQ3G6LG/go-libp2p-circuit"
goprocess "gx/ipfs/QmSF8fPo3jgVBAy8fpdjjYqgG87dkJgUprRBHRd2tmfgpP/goprocess"
mamask "gx/ipfs/QmSMZwvs3n4GBikZ7hKzT17c3bk65FmyZo2JqtJ16swqCv/multiaddr-filter"
mafilter "gx/ipfs/QmSW4uNHbvQia8iZDXzbwjiyHQtnyo9aFqfQAMasj3TJ6Y/go-maddr-filter"
record "gx/ipfs/QmSb4B8ZAAj5ALe9LjfzPyF8Ma6ezC1NTnDF2JQPUJxEXb/go-libp2p-record"
nilrouting "gx/ipfs/QmScZySgru9jaoDa12sSfvh21sWbqF5eXkieTmJzAHJXkQ/go-ipfs-routing/none"
offroute "gx/ipfs/QmScZySgru9jaoDa12sSfvh21sWbqF5eXkieTmJzAHJXkQ/go-ipfs-routing/offline"
connmgr "gx/ipfs/QmSw6zWpuKvcHne7AjNS3LdmcPm1iUq5qd1z1KgVib7QnM/go-libp2p-connmgr"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
bitswap "gx/ipfs/QmUdtRsAr9RYxqNwUzeHDhv5bnVppiHLixP1SU4YysVj2S/go-bitswap"
bsnet "gx/ipfs/QmUdtRsAr9RYxqNwUzeHDhv5bnVppiHLixP1SU4YysVj2S/go-bitswap/network"
ds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
ifconnmgr "gx/ipfs/QmV9T3rTezwJhMJQBzVrGj2tncJwv23dTKdxzXrUxAvWFi/go-libp2p-interface-connmgr"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
routing "gx/ipfs/QmVBnJDKhtFXTRVjXKinqpwGu8t1DyNqPKan2iGX8PR8xG/go-libp2p-routing"
libp2p "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p"
discovery "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/discovery"
p2pbhost "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/host/basic"
rhost "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/host/routed"
identify "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/protocol/identify"
ping "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/protocol/ping"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
dht "gx/ipfs/QmTdMq4uYZXmGW3u6KgnpCRWjo1Y7dWjRuAaGPw7Qxqr1s/go-libp2p-kad-dht"
dhtopts "gx/ipfs/QmTdMq4uYZXmGW3u6KgnpCRWjo1Y7dWjRuAaGPw7Qxqr1s/go-libp2p-kad-dht/opts"
libp2p "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p"
discovery "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/discovery"
p2pbhost "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/host/basic"
rhost "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/host/routed"
identify "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/protocol/identify"
ping "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/protocol/ping"
routing "gx/ipfs/QmVQPj6rHdqz6dDQrjcdP36zDYLaoB7xwqRg39kx2PqqKU/go-libp2p-routing"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
ifconnmgr "gx/ipfs/QmXPqoktJEKkWPT6rSdhCM2G3E1yR7uUBdjnJrhJYeBgHU/go-libp2p-interface-connmgr"
merkledag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bserv "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
smux "gx/ipfs/QmY9JXR3FupnYAYJWK9aMr9bCpqWKcToQ1tz8DVGTrHpHw/go-stream-muxer"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
mplex "gx/ipfs/QmYsbnP57nNUKWijs8o2q3ZFrSUcAGTdKoQPuSJC3Uxt1Y/go-smux-multiplex"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
dht "gx/ipfs/QmZVakpN44VAUxs9eXAuUGLFYTCGmSyqSy6hyEKfMv68ME/go-libp2p-kad-dht"
dhtopts "gx/ipfs/QmZVakpN44VAUxs9eXAuUGLFYTCGmSyqSy6hyEKfMv68ME/go-libp2p-kad-dht/opts"
pnet "gx/ipfs/QmZaQ3K9PRd5sYYoG1xbTGPtd3N7TYiKBRmcBUTsx8HVET/go-libp2p-pnet"
mfs "gx/ipfs/QmahrY1adY4wvtYEtoGjpZ2GUohTyukrkMkwUR9ytRjTG2/go-mfs"
connmgr "gx/ipfs/QmZygFpFQfDwTNeU8AYTfEgAXfb7yfuQh9L4wYG7GgtcMH/go-libp2p-connmgr"
ds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
merkledag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
rhelpers "gx/ipfs/QmcRdSdYkL17qhuQAibF5D14XdQ1iunvaVnXGjDiQTdRm9/go-libp2p-routing-helpers"
bserv "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
"gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
yamux "gx/ipfs/QmcsgrV3nCAKjiHKZhKVXWc4oY3WBECJCqahXEMpHeMrev/go-smux-yamux"
floodsub "gx/ipfs/Qmbi2MdNz6bdqWJg9Fud3WCqTdzP4DXKBwYD16EJVkjzKX/go-libp2p-floodsub"
quic "gx/ipfs/QmbxTJyyqtyYYM7wLHWv529e2dwzt9a9o8FfVQALvPpadC/go-libp2p-quic-transport"
psrouter "gx/ipfs/QmbyoYqzgpaKt97AEoAx4zJCuHdQ71GNkpVZwhJ1wUtzba/go-libp2p-pubsub-router"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
p2phost "gx/ipfs/QmeA5hsqgLryvkeyqeQdvGDqurLkYi3XEPLZP3pzuBJXh2/go-libp2p-host"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
yamux "gx/ipfs/QmejxafYByb7s4rEMoKjmThZm6HfQ1seASNejVNKde6LBZ/go-smux-yamux"
circuit "gx/ipfs/Qmf5M8FECT1H1NGZ9kM6Ri4G4LfQGJcyMpfMPEA1herPuH/go-libp2p-circuit"
rhelpers "gx/ipfs/QmfGNszPuruiURVbgyvoj7eoVe9bkj2uHugMZVteX9zxD1/go-libp2p-routing-helpers"
)
const IpnsValidatorTag = "ipns"

View File

@ -7,9 +7,9 @@ import (
"github.com/ipfs/go-ipfs/repo"
datastore "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
syncds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
datastore "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
syncds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
)
func TestInitialization(t *testing.T) {
@ -21,7 +21,7 @@ func TestInitialization(t *testing.T) {
Identity: id,
Addresses: config.Addresses{
Swarm: []string{"/ip4/0.0.0.0/tcp/4001"},
API: "/ip4/127.0.0.1/tcp/8000",
API: []string{"/ip4/127.0.0.1/tcp/8000"},
},
},
@ -29,7 +29,7 @@ func TestInitialization(t *testing.T) {
Identity: id,
Addresses: config.Addresses{
Swarm: []string{"/ip4/0.0.0.0/tcp/4001"},
API: "/ip4/127.0.0.1/tcp/8000",
API: []string{"/ip4/127.0.0.1/tcp/8000"},
},
},
}

View File

@ -16,8 +16,12 @@ package coreapi
import (
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
)
var log = logging.Logger("core/coreapi")
type CoreAPI struct {
node *core.IpfsNode
}
@ -67,3 +71,13 @@ func (api *CoreAPI) Pin() coreiface.PinAPI {
func (api *CoreAPI) Dht() coreiface.DhtAPI {
return (*DhtAPI)(api)
}
// Swarm returns the SwarmAPI interface implementation backed by the go-ipfs node
func (api *CoreAPI) Swarm() coreiface.SwarmAPI {
return (*SwarmAPI)(api)
}
// PubSub returns the PubSubAPI interface implementation backed by the go-ipfs node
func (api *CoreAPI) PubSub() coreiface.PubSubAPI {
return (*PubSubAPI)(api)
}

View File

@ -10,13 +10,13 @@ import (
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
routing "gx/ipfs/QmVBnJDKhtFXTRVjXKinqpwGu8t1DyNqPKan2iGX8PR8xG/go-libp2p-routing"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
routing "gx/ipfs/QmVQPj6rHdqz6dDQrjcdP36zDYLaoB7xwqRg39kx2PqqKU/go-libp2p-routing"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
blockservice "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
blockservice "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
blockstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
blockstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
)
type DhtAPI CoreAPI

View File

@ -34,6 +34,12 @@ type CoreAPI interface {
// Dht returns an implementation of Dht API
Dht() DhtAPI
// Swarm returns an implementation of Swarm API
Swarm() SwarmAPI
// PubSub returns an implementation of PubSub API
PubSub() PubSubAPI
// ResolvePath resolves the path using Unixfs resolver
ResolvePath(context.Context, Path) (ResolvedPath, error)

View File

@ -5,8 +5,8 @@ import (
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
// DhtAPI specifies the interface to the DHT

View File

@ -4,5 +4,5 @@ import "errors"
var (
ErrIsDir = errors.New("object is a directory")
ErrOffline = errors.New("can't resolve, ipfs node is offline")
ErrOffline = errors.New("this action must be run in online mode, try running 'ipfs daemon' first")
)

View File

@ -33,6 +33,9 @@ type KeyAPI interface {
// List lists keys stored in keystore
List(ctx context.Context) ([]Key, error)
// Self returns the 'main' node key
Self(ctx context.Context) (Key, error)
// Remove removes keys from keystore. Returns ipns path of the removed key
Remove(ctx context.Context, name string) (Key, error)
}

View File

@ -3,9 +3,13 @@ package iface
import (
"context"
"errors"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
)
var ErrResolveFailed = errors.New("could not resolve name")
// IpnsEntry specifies the interface to IpnsEntries
type IpnsEntry interface {
// Name returns IpnsEntry name
@ -14,6 +18,11 @@ type IpnsEntry interface {
Value() Path
}
type IpnsResult struct {
Path
Err error
}
// NameAPI specifies the interface to IPNS.
//
// IPNS is a PKI namespace, where names are the hashes of public keys, and the
@ -28,4 +37,11 @@ type NameAPI interface {
// Resolve attempts to resolve the newest version of the specified name
Resolve(ctx context.Context, name string, opts ...options.NameResolveOption) (Path, error)
// Search is a version of Resolve which outputs paths as they are discovered,
// reducing the time to first entry
//
// Note that by default only the last path returned before the channel closes
// can be considered 'safe'.
Search(ctx context.Context, name string, opts ...options.NameResolveOption) (<-chan IpnsResult, error)
}

View File

@ -13,6 +13,10 @@ const (
type NamePublishSettings struct {
ValidTime time.Duration
Key string
TTL *time.Duration
AllowOffline bool
}
type NameResolveSettings struct {
@ -29,6 +33,8 @@ func NamePublishOptions(opts ...NamePublishOption) (*NamePublishSettings, error)
options := &NamePublishSettings{
ValidTime: DefaultNameValidTime,
Key: "self",
AllowOffline: false,
}
for _, opt := range opts {
@ -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 {

View File

@ -0,0 +1,58 @@
package options
type PubSubPeersSettings struct {
Topic string
}
type PubSubSubscribeSettings struct {
Discover bool
}
type PubSubPeersOption func(*PubSubPeersSettings) error
type PubSubSubscribeOption func(*PubSubSubscribeSettings) error
func PubSubPeersOptions(opts ...PubSubPeersOption) (*PubSubPeersSettings, error) {
options := &PubSubPeersSettings{
Topic: "",
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, err
}
}
return options, nil
}
func PubSubSubscribeOptions(opts ...PubSubSubscribeOption) (*PubSubSubscribeSettings, error) {
options := &PubSubSubscribeSettings{
Discover: false,
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, err
}
}
return options, nil
}
type pubsubOpts struct{}
var PubSub pubsubOpts
func (pubsubOpts) Topic(topic string) PubSubPeersOption {
return func(settings *PubSubPeersSettings) error {
settings.Topic = topic
return nil
}
}
func (pubsubOpts) Discover(discover bool) PubSubSubscribeOption {
return func(settings *PubSubSubscribeSettings) error {
settings.Discover = discover
return nil
}
}

View File

@ -0,0 +1,304 @@
package options
import (
"errors"
"fmt"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
)
type Layout int
const (
BalancedLayout Layout = iota
TrickleLayout
)
type UnixfsAddSettings struct {
CidVersion int
MhType uint64
Inline bool
InlineLimit int
RawLeaves bool
RawLeavesSet bool
Chunker string
Layout Layout
Pin bool
OnlyHash bool
Local bool
FsCache bool
NoCopy bool
Wrap bool
Hidden bool
StdinName string
Events chan<- interface{}
Silent bool
Progress bool
}
type UnixfsAddOption func(*UnixfsAddSettings) error
func UnixfsAddOptions(opts ...UnixfsAddOption) (*UnixfsAddSettings, cid.Prefix, error) {
options := &UnixfsAddSettings{
CidVersion: -1,
MhType: mh.SHA2_256,
Inline: false,
InlineLimit: 32,
RawLeaves: false,
RawLeavesSet: false,
Chunker: "size-262144",
Layout: BalancedLayout,
Pin: false,
OnlyHash: false,
Local: false,
FsCache: false,
NoCopy: false,
Wrap: false,
Hidden: false,
StdinName: "",
Events: nil,
Silent: false,
Progress: false,
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, cid.Prefix{}, err
}
}
// nocopy -> rawblocks
if options.NoCopy && !options.RawLeaves {
// fixed?
if options.RawLeavesSet {
return nil, cid.Prefix{}, fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well")
}
// No, satisfy mandatory constraint.
options.RawLeaves = true
}
// (hash != "sha2-256") -> CIDv1
if options.MhType != mh.SHA2_256 {
switch options.CidVersion {
case 0:
return nil, cid.Prefix{}, errors.New("CIDv0 only supports sha2-256")
case 1, -1:
options.CidVersion = 1
default:
return nil, cid.Prefix{}, fmt.Errorf("unknown CID version: %d", options.CidVersion)
}
} else {
if options.CidVersion < 0 {
// Default to CIDv0
options.CidVersion = 0
}
}
// cidV1 -> raw blocks (by default)
if options.CidVersion > 0 && !options.RawLeavesSet {
options.RawLeaves = true
}
prefix, err := dag.PrefixForCidVersion(options.CidVersion)
if err != nil {
return nil, cid.Prefix{}, err
}
prefix.MhType = options.MhType
prefix.MhLength = -1
return options, prefix, nil
}
type unixfsOpts struct{}
var Unixfs unixfsOpts
// CidVersion specifies which CID version to use. Defaults to 0 unless an option
// that depends on CIDv1 is passed.
func (unixfsOpts) CidVersion(version int) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.CidVersion = version
return nil
}
}
// Hash function to use. Implies CIDv1 if not set to sha2-256 (default).
//
// Table of functions is declared in https://github.com/multiformats/go-multihash/blob/master/multihash.go
func (unixfsOpts) Hash(mhtype uint64) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.MhType = mhtype
return nil
}
}
// RawLeaves specifies whether to use raw blocks for leaves (data nodes with no
// links) instead of wrapping them with unixfs structures.
func (unixfsOpts) RawLeaves(enable bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.RawLeaves = enable
settings.RawLeavesSet = true
return nil
}
}
// Inline tells the adder to inline small blocks into CIDs
func (unixfsOpts) Inline(enable bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Inline = enable
return nil
}
}
// InlineLimit sets the amount of bytes below which blocks will be encoded
// directly into CID instead of being stored and addressed by it's hash.
// Specifying this option won't enable block inlining. For that use `Inline`
// option. Default: 32 bytes
//
// Note that while there is no hard limit on the number of bytes, it should be
// kept at a reasonably low value, such as 64; implementations may choose to
// reject anything larger.
func (unixfsOpts) InlineLimit(limit int) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.InlineLimit = limit
return nil
}
}
// Chunker specifies settings for the chunking algorithm to use.
//
// Default: size-262144, formats:
// size-[bytes] - Simple chunker splitting data into blocks of n bytes
// rabin-[min]-[avg]-[max] - Rabin chunker
func (unixfsOpts) Chunker(chunker string) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Chunker = chunker
return nil
}
}
// Layout tells the adder how to balance data between leaves.
// options.BalancedLayout is the default, it's optimized for static seekable
// files.
// options.TrickleLayout is optimized for streaming data,
func (unixfsOpts) Layout(layout Layout) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Layout = layout
return nil
}
}
// Pin tells the adder to pin the file root recursively after adding
func (unixfsOpts) Pin(pin bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Pin = pin
return nil
}
}
// HashOnly will make the adder calculate data hash without storing it in the
// blockstore or announcing it to the network
func (unixfsOpts) HashOnly(hashOnly bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.OnlyHash = hashOnly
return nil
}
}
// Local will add the data to blockstore without announcing it to the network
//
// Note that this doesn't prevent other nodes from getting this data
func (unixfsOpts) Local(local bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Local = local
return nil
}
}
// Wrap tells the adder to wrap the added file structure with an additional
// directory.
func (unixfsOpts) Wrap(wrap bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Wrap = wrap
return nil
}
}
// Hidden enables adding of hidden files (files prefixed with '.')
func (unixfsOpts) Hidden(hidden bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Hidden = hidden
return nil
}
}
// StdinName is the name set for files which don specify FilePath as
// os.Stdin.Name()
func (unixfsOpts) StdinName(name string) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.StdinName = name
return nil
}
}
// Events specifies channel which will be used to report events about ongoing
// Add operation.
//
// Note that if this channel blocks it may slowdown the adder
func (unixfsOpts) Events(sink chan<- interface{}) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Events = sink
return nil
}
}
// Silent reduces event output
func (unixfsOpts) Silent(silent bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Silent = silent
return nil
}
}
// Progress tells the adder whether to enable progress events
func (unixfsOpts) Progress(enable bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.Progress = enable
return nil
}
}
// FsCache tells the adder to check the filestore for pre-existing blocks
//
// Experimental
func (unixfsOpts) FsCache(enable bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.FsCache = enable
return nil
}
}
// NoCopy tells the adder to add the files using filestore. Implies RawLeaves.
//
// Experimental
func (unixfsOpts) Nocopy(enable bool) UnixfsAddOption {
return func(settings *UnixfsAddSettings) error {
settings.NoCopy = enable
return nil
}
}

View File

@ -1,7 +1,7 @@
package iface
import (
ipfspath "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
ipfspath "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
)

View File

@ -0,0 +1,48 @@
package iface
import (
"context"
"io"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
)
// PubSubSubscription is an active PubSub subscription
type PubSubSubscription interface {
io.Closer
// Next return the next incoming message
Next(context.Context) (PubSubMessage, error)
}
// PubSubMessage is a single PubSub message
type PubSubMessage interface {
// From returns id of a peer from which the message has arrived
From() peer.ID
// Data returns the message body
Data() []byte
// Seq returns message identifier
Seq() []byte
// Topics returns list of topics this message was set to
Topics() []string
}
// PubSubAPI specifies the interface to PubSub
type PubSubAPI interface {
// Ls lists subscribed topics by name
Ls(context.Context) ([]string, error)
// Peers list peers we are currently pubsubbing with
Peers(context.Context, ...options.PubSubPeersOption) ([]peer.ID, error)
// Publish a message to a given pubsub topic
Publish(context.Context, string, []byte) error
// Subscribe to messages on a given topic
Subscribe(context.Context, string, ...options.PubSubSubscribeOption) (PubSubSubscription, error)
}

View File

@ -0,0 +1,57 @@
package iface
import (
"context"
"errors"
"time"
net "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
"gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
"gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
)
var (
ErrNotConnected = errors.New("not connected")
ErrConnNotFound = errors.New("conn not found")
)
// ConnectionInfo contains information about a peer
type ConnectionInfo interface {
// ID returns PeerID
ID() peer.ID
// Address returns the multiaddress via which we are connected with the peer
Address() ma.Multiaddr
// Direction returns which way the connection was established
Direction() net.Direction
// Latency returns last known round trip time to the peer
Latency() (time.Duration, error)
// Streams returns list of streams established with the peer
Streams() ([]protocol.ID, error)
}
// SwarmAPI specifies the interface to libp2p swarm
type SwarmAPI interface {
// Connect to a given peer
Connect(context.Context, pstore.PeerInfo) error
// Disconnect from a given address
Disconnect(context.Context, ma.Multiaddr) error
// Peers returns the list of peers we are connected to
Peers(context.Context) ([]ConnectionInfo, error)
// KnownAddrs returns the list of all addresses this node is aware of
KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, error)
// LocalAddrs returns the list of announced listening addresses
LocalAddrs(context.Context) ([]ma.Multiaddr, error)
// ListenAddrs returns the list of all listening addresses
ListenAddrs(context.Context) ([]ma.Multiaddr, error)
}

View File

@ -2,17 +2,37 @@ package iface
import (
"context"
"io"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
// TODO: ideas on making this more coreapi-ish without breaking the http API?
type AddEvent struct {
Name string
Hash string `json:",omitempty"`
Bytes int64 `json:",omitempty"`
Size string `json:",omitempty"`
}
// UnixfsAPI is the basic interface to immutable files in IPFS
// NOTE: This API is heavily WIP, things are guaranteed to break frequently
type UnixfsAPI interface {
// Add imports the data from the reader into merkledag file
Add(context.Context, io.Reader) (ResolvedPath, error)
//
// TODO: a long useful comment on how to use this for many different scenarios
Add(context.Context, files.File, ...options.UnixfsAddOption) (ResolvedPath, error)
// Get returns a read-only handle to a file tree referenced by a path
//
// Note that some implementations of this API may apply the specified context
// to operations performed on the returned file
Get(context.Context, Path) (files.File, error)
// Cat returns a reader for the file
// TODO: Remove in favour of Get (if we use Get on a file we still have reader directly, so..)
Cat(context.Context, Path) (Reader, error)
// Ls returns the list of links in a directory

View File

@ -1,10 +1,20 @@
package iface
import (
"context"
"io"
)
type Reader interface {
io.ReadSeeker
io.Closer
ReadSeekCloser
Size() uint64
CtxReadFull(context.Context, []byte) (int, error)
}
// A ReadSeekCloser implements interfaces to read, copy, seek and close.
type ReadSeekCloser interface {
io.Reader
io.Seeker
io.Closer
io.WriterTo
}

View File

@ -3,6 +3,7 @@ package coreapi
import (
"context"
"crypto/rand"
"errors"
"fmt"
"sort"
@ -10,8 +11,8 @@ import (
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
crypto "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
ipfspath "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
ipfspath "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
)
type KeyAPI CoreAPI
@ -216,3 +217,11 @@ func (api *KeyAPI) Remove(ctx context.Context, name string) (coreiface.Key, erro
return &key{"", pid}, nil
}
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
}

View File

@ -7,15 +7,16 @@ import (
"strings"
"time"
ipath "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
"github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"github.com/ipfs/go-ipfs/keystore"
"github.com/ipfs/go-ipfs/namesys"
ipath "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
"gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
"gx/ipfs/QmScZySgru9jaoDa12sSfvh21sWbqF5eXkieTmJzAHJXkQ/go-ipfs-routing/offline"
"gx/ipfs/QmQqPdGQfsfQTpRUUzgD3d2RzWHJffZsSqwopnZ2BkiezW/go-ipfs-routing/offline"
"gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
)
@ -45,6 +46,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
@ -65,6 +69,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 {
@ -82,9 +90,7 @@ func (api *NameAPI) Publish(ctx context.Context, p coreiface.Path, opts ...caopt
}, nil
}
// Resolve attempts to resolve the newest version of the specified name and
// returns its path.
func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.NameResolveOption) (coreiface.Path, error) {
func (api *NameAPI) Search(ctx context.Context, name string, opts ...caopts.NameResolveOption) (<-chan coreiface.IpnsResult, error) {
options, err := caopts.NameResolveOptions(opts...)
if err != nil {
return nil, err
@ -118,12 +124,42 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam
name = "/ipns/" + name
}
output, err := resolver.Resolve(ctx, name, options.ResolveOpts...)
out := make(chan coreiface.IpnsResult)
go func() {
defer close(out)
for res := range resolver.ResolveAsync(ctx, name, options.ResolveOpts...) {
p, _ := coreiface.ParsePath(res.Path.String())
select {
case out <- coreiface.IpnsResult{Path: p, Err: res.Err}:
case <-ctx.Done():
return
}
}
}()
return out, nil
}
// Resolve attempts to resolve the newest version of the specified name and
// returns its path.
func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.NameResolveOption) (coreiface.Path, error) {
results, err := api.Search(ctx, name, opts...)
if err != nil {
return nil, err
}
return coreiface.ParsePath(output.String())
err = coreiface.ErrResolveFailed
var p coreiface.Path
for res := range results {
p, err = res.Path, res.Err
if err != nil {
break
}
}
return p, err
}
func keylookup(n *core.IpfsNode, k string) (crypto.PrivKey, error) {

View File

@ -3,11 +3,13 @@ package coreapi_test
import (
"context"
"io"
"io/ioutil"
"math/rand"
"testing"
"time"
ipath "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
ipath "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
opt "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
@ -16,7 +18,7 @@ import (
var rnd = rand.New(rand.NewSource(0x62796532303137))
func addTestObject(ctx context.Context, api coreiface.CoreAPI) (coreiface.Path, error) {
return api.Unixfs().Add(ctx, &io.LimitedReader{R: rnd, N: 4092})
return api.Unixfs().Add(ctx, files.NewReaderFile("", "", ioutil.NopCloser(&io.LimitedReader{R: rnd, N: 4092}), nil))
}
func TestBasicPublishResolve(t *testing.T) {

View File

@ -17,8 +17,8 @@ import (
"github.com/ipfs/go-ipfs/pin"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)

View File

@ -7,9 +7,9 @@ import (
"github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
ipfspath "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
"gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
ipfspath "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
"gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path/resolver"
"gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"

View File

@ -7,11 +7,11 @@ import (
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
corerepo "github.com/ipfs/go-ipfs/core/corerepo"
merkledag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
bserv "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
merkledag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bserv "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
)
type PinAPI CoreAPI
@ -22,19 +22,19 @@ func (api *PinAPI) Add(ctx context.Context, p coreiface.Path, opts ...caopts.Pin
return err
}
defer api.node.Blockstore.PinLock().Unlock()
rp, err := api.core().ResolvePath(ctx, p)
if err != nil {
return err
}
_, err = corerepo.Pin(api.node, ctx, []string{rp.Cid().String()}, settings.Recursive)
defer api.node.Blockstore.PinLock().Unlock()
_, err = corerepo.Pin(api.node, api.core(), ctx, []string{rp.Cid().String()}, settings.Recursive)
if err != nil {
return err
}
return nil
return api.node.Pinning.Flush()
}
func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreiface.Pin, error) {
@ -53,12 +53,12 @@ func (api *PinAPI) Ls(ctx context.Context, opts ...caopts.PinLsOption) ([]coreif
}
func (api *PinAPI) Rm(ctx context.Context, p coreiface.Path) error {
_, err := corerepo.Unpin(api.node, ctx, []string{p.String()}, true)
_, err := corerepo.Unpin(api.node, api.core(), ctx, []string{p.String()}, true)
if err != nil {
return err
}
return nil
return api.node.Pinning.Flush()
}
func (api *PinAPI) Update(ctx context.Context, from coreiface.Path, to coreiface.Path, opts ...caopts.PinUpdateOption) error {
@ -77,7 +77,14 @@ func (api *PinAPI) Update(ctx context.Context, from coreiface.Path, to coreiface
return err
}
return api.node.Pinning.Update(ctx, fp.Cid(), tp.Cid(), settings.Unpin)
defer api.node.Blockstore.PinLock().Unlock()
err = api.node.Pinning.Update(ctx, fp.Cid(), tp.Cid(), settings.Unpin)
if err != nil {
return err
}
return api.node.Pinning.Flush()
}
type pinStatus struct {

View File

@ -15,7 +15,7 @@ func TestPinAdd(t *testing.T) {
t.Error(err)
}
p, err := api.Unixfs().Add(ctx, strings.NewReader("foo"))
p, err := api.Unixfs().Add(ctx, strFile("foo")())
if err != nil {
t.Error(err)
}
@ -33,7 +33,7 @@ func TestPinSimple(t *testing.T) {
t.Error(err)
}
p, err := api.Unixfs().Add(ctx, strings.NewReader("foo"))
p, err := api.Unixfs().Add(ctx, strFile("foo")())
if err != nil {
t.Error(err)
}
@ -82,12 +82,12 @@ func TestPinRecursive(t *testing.T) {
t.Error(err)
}
p0, err := api.Unixfs().Add(ctx, strings.NewReader("foo"))
p0, err := api.Unixfs().Add(ctx, strFile("foo")())
if err != nil {
t.Error(err)
}
p1, err := api.Unixfs().Add(ctx, strings.NewReader("bar"))
p1, err := api.Unixfs().Add(ctx, strFile("bar")())
if err != nil {
t.Error(err)
}

165
core/coreapi/pubsub.go Normal file
View File

@ -0,0 +1,165 @@
package coreapi
import (
"context"
"errors"
"strings"
"sync"
"time"
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
caopts "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
floodsub "gx/ipfs/Qmbi2MdNz6bdqWJg9Fud3WCqTdzP4DXKBwYD16EJVkjzKX/go-libp2p-floodsub"
)
type PubSubAPI CoreAPI
type pubSubSubscription struct {
cancel context.CancelFunc
subscription *floodsub.Subscription
}
type pubSubMessage struct {
msg *floodsub.Message
}
func (api *PubSubAPI) Ls(ctx context.Context) ([]string, error) {
if err := api.checkNode(); err != nil {
return nil, err
}
return api.node.Floodsub.GetTopics(), nil
}
func (api *PubSubAPI) Peers(ctx context.Context, opts ...caopts.PubSubPeersOption) ([]peer.ID, error) {
if err := api.checkNode(); err != nil {
return nil, err
}
settings, err := caopts.PubSubPeersOptions(opts...)
if err != nil {
return nil, err
}
peers := api.node.Floodsub.ListPeers(settings.Topic)
out := make([]peer.ID, len(peers))
for i, peer := range peers {
out[i] = peer
}
return out, nil
}
func (api *PubSubAPI) Publish(ctx context.Context, topic string, data []byte) error {
if err := api.checkNode(); err != nil {
return err
}
return api.node.Floodsub.Publish(topic, data)
}
func (api *PubSubAPI) Subscribe(ctx context.Context, topic string, opts ...caopts.PubSubSubscribeOption) (coreiface.PubSubSubscription, error) {
options, err := caopts.PubSubSubscribeOptions(opts...)
if err := api.checkNode(); err != nil {
return nil, err
}
sub, err := api.node.Floodsub.Subscribe(topic)
if err != nil {
return nil, err
}
pubctx, cancel := context.WithCancel(api.node.Context())
if options.Discover {
go func() {
blk, err := api.core().Block().Put(pubctx, strings.NewReader("floodsub:"+topic))
if err != nil {
log.Error("pubsub discovery: ", err)
return
}
connectToPubSubPeers(pubctx, api.node, blk.Path().Cid())
}()
}
return &pubSubSubscription{cancel, sub}, nil
}
func connectToPubSubPeers(ctx context.Context, n *core.IpfsNode, cid cid.Cid) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
provs := n.Routing.FindProvidersAsync(ctx, cid, 10)
var wg sync.WaitGroup
for p := range provs {
wg.Add(1)
go func(pi pstore.PeerInfo) {
defer wg.Done()
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
defer cancel()
err := n.PeerHost.Connect(ctx, pi)
if err != nil {
log.Info("pubsub discover: ", err)
return
}
log.Info("connected to pubsub peer:", pi.ID)
}(p)
}
wg.Wait()
}
func (api *PubSubAPI) checkNode() error {
if !api.node.OnlineMode() {
return coreiface.ErrOffline
}
if api.node.Floodsub == nil {
return errors.New("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use.")
}
return nil
}
func (sub *pubSubSubscription) Close() error {
sub.cancel()
sub.subscription.Cancel()
return nil
}
func (sub *pubSubSubscription) Next(ctx context.Context) (coreiface.PubSubMessage, error) {
msg, err := sub.subscription.Next(ctx)
if err != nil {
return nil, err
}
return &pubSubMessage{msg}, nil
}
func (msg *pubSubMessage) From() peer.ID {
return peer.ID(msg.msg.From)
}
func (msg *pubSubMessage) Data() []byte {
return msg.msg.Data
}
func (msg *pubSubMessage) Seq() []byte {
return msg.msg.Seqno
}
func (msg *pubSubMessage) Topics() []string {
return msg.msg.TopicIDs
}
func (api *PubSubAPI) core() coreiface.CoreAPI {
return (*CoreAPI)(api)
}

View File

@ -0,0 +1,96 @@
package coreapi_test
import (
"context"
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"testing"
"time"
)
func TestBasicPubSub(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
nds, apis, err := makeAPISwarm(ctx, true, 2)
if err != nil {
t.Fatal(err)
}
sub, err := apis[0].PubSub().Subscribe(ctx, "testch")
if err != nil {
t.Fatal(err)
}
go func() {
tick := time.Tick(100 * time.Millisecond)
for {
err = apis[1].PubSub().Publish(ctx, "testch", []byte("hello world"))
if err != nil {
t.Fatal(err)
}
select {
case <-tick:
case <-ctx.Done():
return
}
}
}()
m, err := sub.Next(ctx)
if err != nil {
t.Fatal(err)
}
if string(m.Data()) != "hello world" {
t.Errorf("got invalid data: %s", string(m.Data()))
}
if m.From() != nds[1].Identity {
t.Errorf("m.From didn't match")
}
peers, err := apis[1].PubSub().Peers(ctx, options.PubSub.Topic("testch"))
if err != nil {
t.Fatal(err)
}
if len(peers) != 1 {
t.Fatalf("got incorrect number of peers: %d", len(peers))
}
if peers[0] != nds[0].Identity {
t.Errorf("peer didn't match")
}
peers, err = apis[1].PubSub().Peers(ctx, options.PubSub.Topic("nottestch"))
if err != nil {
t.Fatal(err)
}
if len(peers) != 0 {
t.Fatalf("got incorrect number of peers: %d", len(peers))
}
topics, err := apis[0].PubSub().Ls(ctx)
if err != nil {
t.Fatal(err)
}
if len(topics) != 1 {
t.Fatalf("got incorrect number of topics: %d", len(peers))
}
if topics[0] != "testch" {
t.Errorf("topic didn't match")
}
topics, err = apis[1].PubSub().Ls(ctx)
if err != nil {
t.Fatal(err)
}
if len(topics) != 0 {
t.Fatalf("got incorrect number of topics: %d", len(peers))
}
}

175
core/coreapi/swarm.go Normal file
View File

@ -0,0 +1,175 @@
package coreapi
import (
"context"
"sort"
"time"
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
inet "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
net "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
swarm "gx/ipfs/Qmb55o5PuhvqwjdVLvc4VV3ouLziYc6TfwM9LC6GwBQokn/go-libp2p-swarm"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
iaddr "gx/ipfs/QmesXvbRGyKQn1XbPHx1Mr5E6RTJYR9c8zwFVuGZq9Aa1j/go-ipfs-addr"
)
type SwarmAPI CoreAPI
type connInfo struct {
node *core.IpfsNode
conn net.Conn
dir net.Direction
addr ma.Multiaddr
peer peer.ID
muxer string
}
func (api *SwarmAPI) Connect(ctx context.Context, pi pstore.PeerInfo) error {
if api.node.PeerHost == nil {
return coreiface.ErrOffline
}
if swrm, ok := api.node.PeerHost.Network().(*swarm.Swarm); ok {
swrm.Backoff().Clear(pi.ID)
}
return api.node.PeerHost.Connect(ctx, pi)
}
func (api *SwarmAPI) Disconnect(ctx context.Context, addr ma.Multiaddr) error {
if api.node.PeerHost == nil {
return coreiface.ErrOffline
}
ia, err := iaddr.ParseMultiaddr(ma.Multiaddr(addr))
if err != nil {
return err
}
taddr := ia.Transport()
id := ia.ID()
net := api.node.PeerHost.Network()
if taddr == nil {
if net.Connectedness(id) != inet.Connected {
return coreiface.ErrNotConnected
} else if err := net.ClosePeer(id); err != nil {
return err
}
} else {
for _, conn := range net.ConnsToPeer(id) {
if !conn.RemoteMultiaddr().Equal(taddr) {
continue
}
return conn.Close()
}
return coreiface.ErrConnNotFound
}
return nil
}
func (api *SwarmAPI) KnownAddrs(context.Context) (map[peer.ID][]ma.Multiaddr, error) {
if api.node.PeerHost == nil {
return nil, coreiface.ErrOffline
}
addrs := make(map[peer.ID][]ma.Multiaddr)
ps := api.node.PeerHost.Network().Peerstore()
for _, p := range ps.Peers() {
for _, a := range ps.Addrs(p) {
addrs[p] = append(addrs[p], a)
}
sort.Slice(addrs[p], func(i, j int) bool {
return addrs[p][i].String() < addrs[p][j].String()
})
}
return addrs, nil
}
func (api *SwarmAPI) LocalAddrs(context.Context) ([]ma.Multiaddr, error) {
if api.node.PeerHost == nil {
return nil, coreiface.ErrOffline
}
return api.node.PeerHost.Addrs(), nil
}
func (api *SwarmAPI) ListenAddrs(context.Context) ([]ma.Multiaddr, error) {
if api.node.PeerHost == nil {
return nil, coreiface.ErrOffline
}
return api.node.PeerHost.Network().InterfaceListenAddresses()
}
func (api *SwarmAPI) Peers(context.Context) ([]coreiface.ConnectionInfo, error) {
if api.node.PeerHost == nil {
return nil, coreiface.ErrOffline
}
conns := api.node.PeerHost.Network().Conns()
var out []coreiface.ConnectionInfo
for _, c := range conns {
pid := c.RemotePeer()
addr := c.RemoteMultiaddr()
ci := &connInfo{
node: api.node,
conn: c,
dir: c.Stat().Direction,
addr: addr,
peer: pid,
}
/*
// FIXME(steb):
swcon, ok := c.(*swarm.Conn)
if ok {
ci.muxer = fmt.Sprintf("%T", swcon.StreamConn().Conn())
}
*/
out = append(out, ci)
}
return out, nil
}
func (ci *connInfo) ID() peer.ID {
return ci.peer
}
func (ci *connInfo) Address() ma.Multiaddr {
return ci.addr
}
func (ci *connInfo) Direction() net.Direction {
return ci.dir
}
func (ci *connInfo) Latency() (time.Duration, error) {
return ci.node.Peerstore.LatencyEWMA(peer.ID(ci.ID())), nil
}
func (ci *connInfo) Streams() ([]protocol.ID, error) {
streams := ci.conn.GetStreams()
out := make([]protocol.ID, len(streams))
for i, s := range streams {
out[i] = s.Protocol()
}
return out, nil
}

190
core/coreapi/unixfile.go Normal file
View File

@ -0,0 +1,190 @@
package coreapi
import (
"context"
"errors"
"io"
"os"
gopath "path"
"time"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
// Number to file to prefetch in directories
// TODO: should we allow setting this via context hint?
const prefetchFiles = 4
// TODO: this probably belongs in go-unixfs (and could probably replace a chunk of it's interface in the long run)
type sizeInfo struct {
size int64
name string
modTime time.Time
}
func (s *sizeInfo) Name() string {
return s.name
}
func (s *sizeInfo) Size() int64 {
return s.size
}
func (s *sizeInfo) Mode() os.FileMode {
return 0444 // all read
}
func (s *sizeInfo) ModTime() time.Time {
return s.modTime
}
func (s *sizeInfo) IsDir() bool {
return false
}
func (s *sizeInfo) Sys() interface{} {
return nil
}
type ufsDirectory struct {
ctx context.Context
dserv ipld.DAGService
files chan *ipld.Link
name string
path string
}
func (d *ufsDirectory) Close() error {
return files.ErrNotReader
}
func (d *ufsDirectory) Read(_ []byte) (int, error) {
return 0, files.ErrNotReader
}
func (d *ufsDirectory) FileName() string {
return d.name
}
func (d *ufsDirectory) FullPath() string {
return d.path
}
func (d *ufsDirectory) IsDirectory() bool {
return true
}
func (d *ufsDirectory) NextFile() (files.File, error) {
l, ok := <-d.files
if !ok {
return nil, io.EOF
}
nd, err := l.GetNode(d.ctx, d.dserv)
if err != nil {
return nil, err
}
return newUnixfsFile(d.ctx, d.dserv, nd, l.Name, d)
}
type ufsFile struct {
uio.DagReader
name string
path string
}
func (f *ufsFile) IsDirectory() bool {
return false
}
func (f *ufsFile) NextFile() (files.File, error) {
return nil, files.ErrNotDirectory
}
func (f *ufsFile) FileName() string {
return f.name
}
func (f *ufsFile) FullPath() string {
return f.path
}
func (f *ufsFile) Size() (int64, error) {
return int64(f.DagReader.Size()), nil
}
func newUnixfsDir(ctx context.Context, dserv ipld.DAGService, nd ipld.Node, name string, path string) (files.File, error) {
dir, err := uio.NewDirectoryFromNode(dserv, nd)
if err != nil {
return nil, err
}
fileCh := make(chan *ipld.Link, prefetchFiles)
go func() {
dir.ForEachLink(ctx, func(link *ipld.Link) error {
select {
case fileCh <- link:
case <-ctx.Done():
return ctx.Err()
}
return nil
})
close(fileCh)
}()
return &ufsDirectory{
ctx: ctx,
dserv: dserv,
files: fileCh,
name: name,
path: path,
}, nil
}
func newUnixfsFile(ctx context.Context, dserv ipld.DAGService, nd ipld.Node, name string, parent files.File) (files.File, error) {
path := name
if parent != nil {
path = gopath.Join(parent.FullPath(), name)
}
switch dn := nd.(type) {
case *dag.ProtoNode:
fsn, err := ft.FSNodeFromBytes(dn.Data())
if err != nil {
return nil, err
}
if fsn.IsDir() {
return newUnixfsDir(ctx, dserv, nd, name, path)
}
case *dag.RawNode:
default:
return nil, errors.New("unknown node type")
}
dr, err := uio.NewDagReader(ctx, nd, dserv)
if err != nil {
return nil, err
}
return &ufsFile{
DagReader: dr,
name: name,
path: path,
}, nil
}
var _ os.FileInfo = &sizeInfo{}

View File

@ -2,13 +2,24 @@ package coreapi
import (
"context"
"io"
"fmt"
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/filestore"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"github.com/ipfs/go-ipfs/core/coreunix"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mfs "gx/ipfs/QmPbuswDwcPT4WquGqGoeBBDuuBaUmbZJFYiaes6vkgXYJ/go-mfs"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
cidutil "gx/ipfs/QmQJSeE3CX4zos9qeaG8EhecEK9zvrTEfTG84J8C5NVRwt/go-cidutil"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
dagtest "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag/test"
blockservice "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
@ -16,16 +27,118 @@ type UnixfsAPI CoreAPI
// Add builds a merkledag node from a reader, adds it to the blockstore,
// and returns the key representing that node.
func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (coreiface.ResolvedPath, error) {
k, err := coreunix.AddWithContext(ctx, api.node, r)
func (api *UnixfsAPI) Add(ctx context.Context, files files.File, opts ...options.UnixfsAddOption) (coreiface.ResolvedPath, error) {
settings, prefix, err := options.UnixfsAddOptions(opts...)
if err != nil {
return nil, err
}
c, err := cid.Decode(k)
n := api.node
cfg, err := n.Repo.Config()
if err != nil {
return nil, err
}
return coreiface.IpfsPath(c), nil
// check if repo will exceed storage limit if added
// TODO: this doesn't handle the case if the hashed file is already in blocks (deduplicated)
// TODO: conditional GC is disabled due to it is somehow not possible to pass the size to the daemon
//if err := corerepo.ConditionalGC(req.Context(), n, uint64(size)); err != nil {
// res.SetError(err, cmdkit.ErrNormal)
// return
//}
if settings.NoCopy && !cfg.Experimental.FilestoreEnabled {
return nil, filestore.ErrFilestoreNotEnabled
}
if settings.OnlyHash {
nilnode, err := core.NewNode(ctx, &core.BuildCfg{
//TODO: need this to be true or all files
// hashed will be stored in memory!
NilRepo: true,
})
if err != nil {
return nil, err
}
n = nilnode
}
addblockstore := n.Blockstore
if !(settings.FsCache || settings.NoCopy) {
addblockstore = bstore.NewGCBlockstore(n.BaseBlocks, n.GCLocker)
}
exch := n.Exchange
if settings.Local {
exch = offline.Exchange(addblockstore)
}
bserv := blockservice.New(addblockstore, exch) // hash security 001
dserv := dag.NewDAGService(bserv)
fileAdder, err := coreunix.NewAdder(ctx, n.Pinning, n.Blockstore, dserv)
if err != nil {
return nil, err
}
fileAdder.Chunker = settings.Chunker
if settings.Events != nil {
fileAdder.Out = settings.Events
fileAdder.Progress = settings.Progress
}
fileAdder.Hidden = settings.Hidden
fileAdder.Wrap = settings.Wrap
fileAdder.Pin = settings.Pin && !settings.OnlyHash
fileAdder.Silent = settings.Silent
fileAdder.RawLeaves = settings.RawLeaves
fileAdder.NoCopy = settings.NoCopy
fileAdder.Name = settings.StdinName
fileAdder.CidBuilder = prefix
switch settings.Layout {
case options.BalancedLayout:
// Default
case options.TrickleLayout:
fileAdder.Trickle = true
default:
return nil, fmt.Errorf("unknown layout: %d", settings.Layout)
}
if settings.Inline {
fileAdder.CidBuilder = cidutil.InlineBuilder{
Builder: fileAdder.CidBuilder,
Limit: settings.InlineLimit,
}
}
if settings.OnlyHash {
md := dagtest.Mock()
emptyDirNode := ft.EmptyDirNode()
// Use the same prefix for the "empty" MFS root as for the file adder.
emptyDirNode.SetCidBuilder(fileAdder.CidBuilder)
mr, err := mfs.NewRoot(ctx, md, emptyDirNode, nil)
if err != nil {
return nil, err
}
fileAdder.SetMfsRoot(mr)
}
nd, err := fileAdder.AddAllAndPin(files)
if err != nil {
return nil, err
}
return coreiface.IpfsPath(nd.Cid()), nil
}
func (api *UnixfsAPI) Get(ctx context.Context, p coreiface.Path) (files.File, error) {
nd, err := api.core().ResolveNode(ctx, p)
if err != nil {
return nil, err
}
return newUnixfsFile(ctx, api.node.DAG, nd, "", nil)
}
// Cat returns the data contained by an IPFS or IPNS object(s) at path `p`.

View File

@ -6,29 +6,35 @@ import (
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"math"
"os"
"strconv"
"strings"
"sync"
"testing"
core "github.com/ipfs/go-ipfs/core"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
"github.com/ipfs/go-ipfs/core"
"github.com/ipfs/go-ipfs/core/coreapi"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
options "github.com/ipfs/go-ipfs/core/coreapi/interface/options"
coreunix "github.com/ipfs/go-ipfs/core/coreunix"
"github.com/ipfs/go-ipfs/core/coreapi/interface/options"
"github.com/ipfs/go-ipfs/core/coreunix"
mock "github.com/ipfs/go-ipfs/core/mock"
keystore "github.com/ipfs/go-ipfs/keystore"
repo "github.com/ipfs/go-ipfs/repo"
"github.com/ipfs/go-ipfs/keystore"
"github.com/ipfs/go-ipfs/repo"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
ci "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
unixfs "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
cbor "gx/ipfs/QmSywXfm2v4Qkp4DcFqo8eehj49dJK3bdUnaLVxrdFLMQn/go-ipld-cbor"
unixfs "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
datastore "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
syncds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
mocknet "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/net/mock"
mocknet "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/net/mock"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
mdag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
datastore "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
syncds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
mdag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe"
@ -88,6 +94,9 @@ func makeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]*core.IpfsNo
Repo: r,
Host: mock.MockHostOption(mn),
Online: fullIdentity,
ExtraOpts: map[string]bool{
"pubsub": true,
},
})
if err != nil {
return nil, nil, err
@ -125,6 +134,37 @@ func makeAPI(ctx context.Context) (*core.IpfsNode, coreiface.CoreAPI, error) {
return nd[0], api[0], nil
}
func strFile(data string) func() files.File {
return func() files.File {
return files.NewReaderFile("", "", ioutil.NopCloser(strings.NewReader(data)), nil)
}
}
func twoLevelDir() func() files.File {
return func() files.File {
return files.NewSliceFile("t", "t", []files.File{
files.NewSliceFile("t/abc", "t/abc", []files.File{
files.NewReaderFile("t/abc/def", "t/abc/def", ioutil.NopCloser(strings.NewReader("world")), nil),
}),
files.NewReaderFile("t/bar", "t/bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/foo", "t/foo", ioutil.NopCloser(strings.NewReader("hello1")), nil),
})
}
}
func flatDir() files.File {
return files.NewSliceFile("t", "t", []files.File{
files.NewReaderFile("t/bar", "t/bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/foo", "t/foo", ioutil.NopCloser(strings.NewReader("hello1")), nil),
})
}
func wrapped(f files.File) files.File {
return files.NewSliceFile("", "", []files.File{
f,
})
}
func TestAdd(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
@ -132,84 +172,454 @@ func TestAdd(t *testing.T) {
t.Error(err)
}
str := strings.NewReader(helloStr)
p, err := api.Unixfs().Add(ctx, str)
if err != nil {
t.Error(err)
cases := []struct {
name string
data func() files.File
expect func(files.File) files.File
path string
err string
recursive bool
events []coreiface.AddEvent
opts []options.UnixfsAddOption
}{
// Simple cases
{
name: "simpleAdd",
data: strFile(helloStr),
path: hello,
opts: []options.UnixfsAddOption{},
},
{
name: "addEmpty",
data: strFile(""),
path: emptyFile,
},
// CIDv1 version / rawLeaves
{
name: "addCidV1",
data: strFile(helloStr),
path: "/ipfs/zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd",
opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(1)},
},
{
name: "addCidV1NoLeaves",
data: strFile(helloStr),
path: "/ipfs/zdj7WY4GbN8NDbTW1dfCShAQNVovams2xhq9hVCx5vXcjvT8g",
opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(1), options.Unixfs.RawLeaves(false)},
},
// Non sha256 hash vs CID
{
name: "addCidSha3",
data: strFile(helloStr),
path: "/ipfs/zb2wwnYtXBxpndNABjtYxWAPt3cwWNRnc11iT63fvkYV78iRb",
opts: []options.UnixfsAddOption{options.Unixfs.Hash(mh.SHA3_256)},
},
{
name: "addCidSha3Cid0",
data: strFile(helloStr),
err: "CIDv0 only supports sha2-256",
opts: []options.UnixfsAddOption{options.Unixfs.CidVersion(0), options.Unixfs.Hash(mh.SHA3_256)},
},
// Inline
{
name: "addInline",
data: strFile(helloStr),
path: "/ipfs/zaYomJdLndMku8P9LHngHB5w2CQ7NenLbv",
opts: []options.UnixfsAddOption{options.Unixfs.Inline(true)},
},
{
name: "addInlineLimit",
data: strFile(helloStr),
path: "/ipfs/zaYomJdLndMku8P9LHngHB5w2CQ7NenLbv",
opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(32), options.Unixfs.Inline(true)},
},
{
name: "addInlineZero",
data: strFile(""),
path: "/ipfs/z2yYDV",
opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(0), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true)},
},
{ //TODO: after coreapi add is used in `ipfs add`, consider making this default for inline
name: "addInlineRaw",
data: strFile(helloStr),
path: "/ipfs/zj7Gr8AcBreqGEfrnR5kPFe",
opts: []options.UnixfsAddOption{options.Unixfs.InlineLimit(32), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true)},
},
// Chunker / Layout
{
name: "addChunks",
data: strFile(strings.Repeat("aoeuidhtns", 200)),
path: "/ipfs/QmRo11d4QJrST47aaiGVJYwPhoNA4ihRpJ5WaxBWjWDwbX",
opts: []options.UnixfsAddOption{options.Unixfs.Chunker("size-4")},
},
{
name: "addChunksTrickle",
data: strFile(strings.Repeat("aoeuidhtns", 200)),
path: "/ipfs/QmNNhDGttafX3M1wKWixGre6PrLFGjnoPEDXjBYpTv93HP",
opts: []options.UnixfsAddOption{options.Unixfs.Chunker("size-4"), options.Unixfs.Layout(options.TrickleLayout)},
},
// Local
{
name: "addLocal", // better cases in sharness
data: strFile(helloStr),
path: hello,
opts: []options.UnixfsAddOption{options.Unixfs.Local(true)},
},
{
name: "hashOnly", // test (non)fetchability
data: strFile(helloStr),
path: hello,
opts: []options.UnixfsAddOption{options.Unixfs.HashOnly(true)},
},
// multi file
{
name: "simpleDir",
data: flatDir,
recursive: true,
path: "/ipfs/QmRKGpFfR32FVXdvJiHfo4WJ5TDYBsM1P9raAp1p6APWSp",
},
{
name: "twoLevelDir",
data: twoLevelDir(),
recursive: true,
path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
},
// wrapped
{
name: "addWrapped",
path: "/ipfs/QmVE9rNpj5doj7XHzp5zMUxD7BJgXEqx4pe3xZ3JBReWHE",
data: func() files.File {
return files.NewReaderFile("foo", "foo", ioutil.NopCloser(strings.NewReader(helloStr)), nil)
},
expect: wrapped,
opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
},
{
name: "stdinWrapped",
path: "/ipfs/QmU3r81oZycjHS9oaSHw37ootMFuFUw1DvMLKXPsezdtqU",
data: func() files.File {
return files.NewReaderFile("", os.Stdin.Name(), ioutil.NopCloser(strings.NewReader(helloStr)), nil)
},
expect: func(files.File) files.File {
return files.NewSliceFile("", "", []files.File{
files.NewReaderFile("QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk", "QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk", ioutil.NopCloser(strings.NewReader(helloStr)), nil),
})
},
opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
},
{
name: "stdinNamed",
path: "/ipfs/QmQ6cGBmb3ZbdrQW1MRm1RJnYnaxCqfssz7CrTa9NEhQyS",
data: func() files.File {
return files.NewReaderFile("", os.Stdin.Name(), ioutil.NopCloser(strings.NewReader(helloStr)), nil)
},
expect: func(files.File) files.File {
return files.NewSliceFile("", "", []files.File{
files.NewReaderFile("test", "test", ioutil.NopCloser(strings.NewReader(helloStr)), nil),
})
},
opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true), options.Unixfs.StdinName("test")},
},
{
name: "twoLevelDirWrapped",
data: twoLevelDir(),
recursive: true,
expect: wrapped,
path: "/ipfs/QmPwsL3T5sWhDmmAWZHAzyjKtMVDS9a11aHNRqb3xoVnmg",
opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true)},
},
{
name: "twoLevelInlineHash",
data: twoLevelDir(),
recursive: true,
expect: wrapped,
path: "/ipfs/zBunoruKoyCHKkALNSWxDvj4L7yuQnMgQ4hUa9j1Z64tVcDEcu6Zdetyu7eeFCxMPfxb7YJvHeFHoFoHMkBUQf6vfdhmi",
opts: []options.UnixfsAddOption{options.Unixfs.Wrap(true), options.Unixfs.Inline(true), options.Unixfs.RawLeaves(true), options.Unixfs.Hash(mh.SHA3)},
},
// hidden
{
name: "hiddenFiles",
data: func() files.File {
return files.NewSliceFile("t", "t", []files.File{
files.NewReaderFile("t/.bar", "t/.bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/bar", "t/bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/foo", "t/foo", ioutil.NopCloser(strings.NewReader("hello1")), nil),
})
},
recursive: true,
path: "/ipfs/QmehGvpf2hY196MzDFmjL8Wy27S4jbgGDUAhBJyvXAwr3g",
opts: []options.UnixfsAddOption{options.Unixfs.Hidden(true)},
},
{
name: "hiddenFileAlwaysAdded",
data: func() files.File {
return files.NewReaderFile(".foo", ".foo", ioutil.NopCloser(strings.NewReader(helloStr)), nil)
},
recursive: true,
path: hello,
},
{
name: "hiddenFilesNotAdded",
data: func() files.File {
return files.NewSliceFile("t", "t", []files.File{
files.NewReaderFile("t/.bar", "t/.bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/bar", "t/bar", ioutil.NopCloser(strings.NewReader("hello2")), nil),
files.NewReaderFile("t/foo", "t/foo", ioutil.NopCloser(strings.NewReader("hello1")), nil),
})
},
expect: func(files.File) files.File {
return flatDir()
},
recursive: true,
path: "/ipfs/QmRKGpFfR32FVXdvJiHfo4WJ5TDYBsM1P9raAp1p6APWSp",
opts: []options.UnixfsAddOption{options.Unixfs.Hidden(false)},
},
// Events / Progress
{
name: "simpleAddEvent",
data: strFile(helloStr),
path: "/ipfs/zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd",
events: []coreiface.AddEvent{
{Name: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Hash: "zb2rhdhmJjJZs9qkhQCpCQ7VREFkqWw3h1r8utjVvQugwHPFd", Size: strconv.Itoa(len(helloStr))},
},
opts: []options.UnixfsAddOption{options.Unixfs.RawLeaves(true)},
},
{
name: "silentAddEvent",
data: twoLevelDir(),
path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
events: []coreiface.AddEvent{
{Name: "t/abc", Hash: "QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt", Size: "62"},
{Name: "t", Hash: "QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr", Size: "229"},
},
recursive: true,
opts: []options.UnixfsAddOption{options.Unixfs.Silent(true)},
},
{
name: "dirAddEvents",
data: twoLevelDir(),
path: "/ipfs/QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr",
events: []coreiface.AddEvent{
{Name: "t/abc/def", Hash: "QmNyJpQkU1cEkBwMDhDNFstr42q55mqG5GE5Mgwug4xyGk", Size: "13"},
{Name: "t/bar", Hash: "QmS21GuXiRMvJKHos4ZkEmQDmRBqRaF5tQS2CQCu2ne9sY", Size: "14"},
{Name: "t/foo", Hash: "QmfAjGiVpTN56TXi6SBQtstit5BEw3sijKj1Qkxn6EXKzJ", Size: "14"},
{Name: "t/abc", Hash: "QmU7nuGs2djqK99UNsNgEPGh6GV4662p6WtsgccBNGTDxt", Size: "62"},
{Name: "t", Hash: "QmVG2ZYCkV1S4TK8URA3a4RupBF17A8yAr4FqsRDXVJASr", Size: "229"},
},
recursive: true,
},
{
name: "progress1M",
data: func() files.File {
r := bytes.NewReader(bytes.Repeat([]byte{0}, 1000000))
return files.NewReaderFile("", "", ioutil.NopCloser(r), nil)
},
path: "/ipfs/QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD",
events: []coreiface.AddEvent{
{Name: "", Bytes: 262144},
{Name: "", Bytes: 524288},
{Name: "", Bytes: 786432},
{Name: "", Bytes: 1000000},
{Name: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Hash: "QmXXNNbwe4zzpdMg62ZXvnX1oU7MwSrQ3vAEtuwFKCm1oD", Size: "1000256"},
},
recursive: true,
opts: []options.UnixfsAddOption{options.Unixfs.Progress(true)},
},
}
if p.String() != hello {
t.Fatalf("expected path %s, got: %s", hello, p)
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
r, err := api.Unixfs().Cat(ctx, p)
if err != nil {
t.Fatal(err)
}
buf := make([]byte, len(helloStr))
_, err = io.ReadFull(r, buf)
if err != nil {
t.Error(err)
}
// recursive logic
if string(buf) != helloStr {
t.Fatalf("expected [%s], got [%s] [err=%s]", helloStr, string(buf), err)
data := testCase.data()
if testCase.recursive {
data = files.NewSliceFile("", "", []files.File{
data,
})
}
// handle events if relevant to test case
opts := testCase.opts
eventOut := make(chan interface{})
var evtWg sync.WaitGroup
if len(testCase.events) > 0 {
opts = append(opts, options.Unixfs.Events(eventOut))
evtWg.Add(1)
go func() {
defer evtWg.Done()
expected := testCase.events
for evt := range eventOut {
event, ok := evt.(*coreiface.AddEvent)
if !ok {
t.Fatal("unexpected event type")
}
if len(expected) < 1 {
t.Fatal("got more events than expected")
}
if expected[0].Size != event.Size {
t.Errorf("Event.Size didn't match, %s != %s", expected[0].Size, event.Size)
}
if expected[0].Name != event.Name {
t.Errorf("Event.Name didn't match, %s != %s", expected[0].Name, event.Name)
}
if expected[0].Hash != event.Hash {
t.Errorf("Event.Hash didn't match, %s != %s", expected[0].Hash, event.Hash)
}
if expected[0].Bytes != event.Bytes {
t.Errorf("Event.Bytes didn't match, %d != %d", expected[0].Bytes, event.Bytes)
}
expected = expected[1:]
}
if len(expected) > 0 {
t.Fatalf("%d event(s) didn't arrive", len(expected))
}
}()
}
// Add!
p, err := api.Unixfs().Add(ctx, data, opts...)
close(eventOut)
evtWg.Wait()
if testCase.err != "" {
if err == nil {
t.Fatalf("expected an error: %s", testCase.err)
}
if err.Error() != testCase.err {
t.Fatalf("expected an error: '%s' != '%s'", err.Error(), testCase.err)
}
return
}
if err != nil {
t.Fatal(err)
}
if p.String() != testCase.path {
t.Errorf("expected path %s, got: %s", testCase.path, p)
}
// compare file structure with Unixfs().Get
var cmpFile func(orig files.File, got files.File)
cmpFile = func(orig files.File, got files.File) {
if orig.IsDirectory() != got.IsDirectory() {
t.Fatal("file type mismatch")
}
if !orig.IsDirectory() {
defer orig.Close()
defer got.Close()
do, err := ioutil.ReadAll(orig)
if err != nil {
t.Fatal(err)
}
dg, err := ioutil.ReadAll(got)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(do, dg) {
t.Fatal("data not equal")
}
return
}
for {
fo, err := orig.NextFile()
fg, err2 := got.NextFile()
if err != nil {
if err == io.EOF && err2 == io.EOF {
break
}
t.Fatal(err)
}
if err2 != nil {
t.Fatal(err)
}
cmpFile(fo, fg)
}
}
f, err := api.Unixfs().Get(ctx, p)
if err != nil {
t.Fatal(err)
}
orig := testCase.data()
if testCase.expect != nil {
orig = testCase.expect(orig)
}
cmpFile(orig, f)
})
}
}
func TestAddEmptyFile(t *testing.T) {
func TestAddPinned(t *testing.T) {
ctx := context.Background()
_, api, err := makeAPI(ctx)
if err != nil {
t.Error(err)
}
str := strings.NewReader("")
p, err := api.Unixfs().Add(ctx, str)
_, err = api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.Pin(true))
if err != nil {
t.Error(err)
}
if p.String() != emptyFile {
t.Fatalf("expected path %s, got: %s", hello, p)
pins, err := api.Pin().Ls(ctx)
if len(pins) != 1 {
t.Fatalf("expected 1 pin, got %d", len(pins))
}
if pins[0].Path().String() != "/ipld/QmQy2Dw4Wk7rdJKjThjYXzfFJNaRKRHhHP5gHHXroJMYxk" {
t.Fatalf("got unexpected pin: %s", pins[0].Path().String())
}
}
func TestCatBasic(t *testing.T) {
func TestAddHashOnly(t *testing.T) {
ctx := context.Background()
node, api, err := makeAPI(ctx)
if err != nil {
t.Fatal(err)
}
hr := strings.NewReader(helloStr)
p, err := coreunix.Add(node, hr)
if err != nil {
t.Fatal(err)
}
p = "/ipfs/" + p
if p != hello {
t.Fatalf("expected CID %s, got: %s", hello, p)
}
helloPath, err := coreiface.ParsePath(hello)
if err != nil {
t.Fatal(err)
}
r, err := api.Unixfs().Cat(ctx, helloPath)
if err != nil {
t.Fatal(err)
}
buf := make([]byte, len(helloStr))
_, err = io.ReadFull(r, buf)
_, api, err := makeAPI(ctx)
if err != nil {
t.Error(err)
}
if string(buf) != helloStr {
t.Fatalf("expected [%s], got [%s] [err=%s]", helloStr, string(buf), err)
p, err := api.Unixfs().Add(ctx, strFile(helloStr)(), options.Unixfs.HashOnly(true))
if err != nil {
t.Error(err)
}
if p.String() != hello {
t.Errorf("unxepected path: %s", p.String())
}
_, err = api.Block().Get(ctx, p)
if err == nil {
t.Fatal("expected an error")
}
if err.Error() != "blockservice: key not found" {
t.Errorf("unxepected error: %s", err.Error())
}
}

View File

@ -5,7 +5,7 @@ import (
"io/ioutil"
"math"
"gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
"gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"

View File

@ -5,7 +5,7 @@ import (
"io/ioutil"
"math"
"gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
"gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"

View File

@ -14,10 +14,10 @@ import (
"github.com/ipfs/go-ipfs/core"
corecommands "github.com/ipfs/go-ipfs/core/commands"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
cmdsHttp "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds/http"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
)
var (

View File

@ -9,7 +9,7 @@ import (
core "github.com/ipfs/go-ipfs/core"
coreapi "github.com/ipfs/go-ipfs/core/coreapi"
id "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/protocol/identify"
id "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/protocol/identify"
)
type GatewayConfig struct {

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
@ -16,17 +17,18 @@ import (
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
"github.com/ipfs/go-ipfs/dagutils"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
"gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
"gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
resolver "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path/resolver"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
chunker "gx/ipfs/QmULKgr55cSWR8Kiwy3cVRcAiGVnR6EVSaB7hJcWS4138p/go-ipfs-chunker"
routing "gx/ipfs/QmVBnJDKhtFXTRVjXKinqpwGu8t1DyNqPKan2iGX8PR8xG/go-libp2p-routing"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
routing "gx/ipfs/QmVQPj6rHdqz6dDQrjcdP36zDYLaoB7xwqRg39kx2PqqKU/go-libp2p-routing"
chunker "gx/ipfs/QmbrQ27wGQeE8spxjbw9mk5Ef7as4tRFSnWLkEGg4xeg2f/go-ipfs-chunker"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
multibase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
)
@ -266,7 +268,7 @@ func (i *gatewayHandler) getOrHeadHandler(ctx context.Context, w http.ResponseWr
w.Header().Set("Content-Disposition", fmt.Sprintf("inline; filename*=UTF-8''%s", url.PathEscape(urlFilename)))
name = urlFilename
} else {
name = gopath.Base(urlPath)
name = getFilename(urlPath)
}
i.serveFile(w, r, name, modtime, dr)
return
@ -398,7 +400,7 @@ func (i *gatewayHandler) serveFile(w http.ResponseWriter, req *http.Request, nam
}
func (i *gatewayHandler) postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
p, err := i.api.Unixfs().Add(ctx, r.Body)
p, err := i.api.Unixfs().Add(ctx, files.NewReaderFile("", "", ioutil.NopCloser(r.Body), nil))
if err != nil {
internalWebError(w, err)
return
@ -624,3 +626,11 @@ func webErrorWithCode(w http.ResponseWriter, message string, err error, code int
func internalWebError(w http.ResponseWriter, err error) {
webErrorWithCode(w, "internalWebError", err, http.StatusInternalServerError)
}
func getFilename(s string) string {
if (strings.HasPrefix(s, ipfsPathPrefix) || strings.HasPrefix(s, ipnsPathPrefix)) && strings.Count(gopath.Clean(s), "/") <= 2 {
// Don't want to treat ipfs.io in /ipns/ipfs.io as a filename.
return ""
}
return gopath.Base(s)
}

View File

@ -19,12 +19,12 @@ import (
repo "github.com/ipfs/go-ipfs/repo"
ci "gx/ipfs/QmPvyPwuCgJ7pDmrKDxRtsScJgBaM5h4EpRL2qQJsmXf4n/go-libp2p-crypto"
datastore "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
syncds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
id "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/protocol/identify"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
id "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/protocol/identify"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
datastore "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
syncds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
)
// `ipfs object new unixfs-dir`
@ -161,6 +161,14 @@ func TestGatewayGet(t *testing.T) {
ns["/ipns/double.example.com"] = path.FromString("/ipns/working.example.com")
ns["/ipns/triple.example.com"] = path.FromString("/ipns/double.example.com")
ns["/ipns/broken.example.com"] = path.FromString("/ipns/" + k)
// We picked .man because:
// 1. It's a valid TLD.
// 2. Go treats it as the file extension for "man" files (even though
// nobody actually *uses* this extension, AFAIK).
//
// Unfortunately, this may not work on all platforms as file type
// detection is platform dependent.
ns["/ipns/example.man"] = path.FromString("/ipfs/" + k)
t.Log(ts.URL)
for _, test := range []struct {
@ -183,6 +191,8 @@ func TestGatewayGet(t *testing.T) {
{"working.example.com", "/ipfs/" + k, http.StatusNotFound, "ipfs resolve -r /ipns/working.example.com/ipfs/" + k + ": no link by that name\n"},
{"broken.example.com", "/", http.StatusNotFound, "ipfs resolve -r /ipns/broken.example.com/: " + namesys.ErrResolveFailed.Error() + "\n"},
{"broken.example.com", "/ipfs/" + k, http.StatusNotFound, "ipfs resolve -r /ipns/broken.example.com/ipfs/" + k + ": " + namesys.ErrResolveFailed.Error() + "\n"},
// This test case ensures we don't treat the TLD as a file extension.
{"example.man", "/", http.StatusOK, "fnord"},
} {
var c http.Client
r, err := http.NewRequest("GET", ts.URL+test.path, nil)
@ -198,6 +208,10 @@ func TestGatewayGet(t *testing.T) {
continue
}
defer resp.Body.Close()
contentType := resp.Header.Get("Content-Type")
if contentType != "text/plain; charset=utf-8" {
t.Errorf("expected content type to be text/plain, got %s", contentType)
}
if resp.StatusCode != test.status {
t.Errorf("got %d, expected %d from %s", resp.StatusCode, test.status, urlstr)
continue

View File

@ -7,9 +7,9 @@ import (
core "github.com/ipfs/go-ipfs/core"
swarmt "gx/ipfs/QmPQoCVRHaGD25VffyB7DFV5qP65hFSQJdSDy75P1vYBKe/go-libp2p-swarm/testing"
bhost "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/host/basic"
inet "gx/ipfs/QmfDPh144WGBqRxZb1TGDHerbMnZATrHZggAPw7putNnBq/go-libp2p-net"
bhost "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/host/basic"
inet "gx/ipfs/QmWUPYHpNv4YahaBYXovuEJttgfqcNcN9Gg4arhQYcRoqa/go-libp2p-net"
swarmt "gx/ipfs/Qmb55o5PuhvqwjdVLvc4VV3ouLziYc6TfwM9LC6GwBQokn/go-libp2p-swarm/testing"
)
// This test is based on go-libp2p/p2p/net/swarm.TestConnectednessCorrect

View File

@ -12,8 +12,8 @@ import (
humanize "gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mfs "gx/ipfs/QmPbuswDwcPT4WquGqGoeBBDuuBaUmbZJFYiaes6vkgXYJ/go-mfs"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
mfs "gx/ipfs/QmahrY1adY4wvtYEtoGjpZ2GUohTyukrkMkwUR9ytRjTG2/go-mfs"
)
var log = logging.Logger("corerepo")

View File

@ -18,28 +18,21 @@ import (
"fmt"
"github.com/ipfs/go-ipfs/core"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
"github.com/ipfs/go-ipfs/core/coreapi/interface"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
"gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
)
func Pin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) ([]cid.Cid, error) {
func Pin(n *core.IpfsNode, api iface.CoreAPI, ctx context.Context, paths []string, recursive bool) ([]cid.Cid, error) {
out := make([]cid.Cid, len(paths))
r := &resolver.Resolver{
DAG: n.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
for i, fpath := range paths {
p, err := path.ParsePath(fpath)
p, err := iface.ParsePath(fpath)
if err != nil {
return nil, err
}
dagnode, err := core.Resolve(ctx, n.Namesys, r, p)
dagnode, err := api.ResolveNode(ctx, p)
if err != nil {
return nil, fmt.Errorf("pin: %s", err)
}
@ -58,30 +51,25 @@ func Pin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool)
return out, nil
}
func Unpin(n *core.IpfsNode, ctx context.Context, paths []string, recursive bool) ([]cid.Cid, error) {
func Unpin(n *core.IpfsNode, api iface.CoreAPI, ctx context.Context, paths []string, recursive bool) ([]cid.Cid, error) {
unpinned := make([]cid.Cid, len(paths))
r := &resolver.Resolver{
DAG: n.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
for i, p := range paths {
p, err := path.ParsePath(p)
p, err := iface.ParsePath(p)
if err != nil {
return nil, err
}
k, err := core.ResolveToCid(ctx, n.Namesys, r, p)
k, err := api.ResolvePath(ctx, p)
if err != nil {
return nil, err
}
err = n.Pinning.Unpin(ctx, k, recursive)
err = n.Pinning.Unpin(ctx, k.Cid(), recursive)
if err != nil {
return nil, err
}
unpinned[i] = k
unpinned[i] = k.Cid()
}
err := n.Pinning.Flush()

View File

@ -11,21 +11,22 @@ import (
"strconv"
core "github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
"github.com/ipfs/go-ipfs/pin"
unixfs "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
balanced "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/balanced"
ihelper "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/helpers"
trickle "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer/trickle"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
posinfo "gx/ipfs/QmPG32VXR5jmpo9q8R9FNdR4Ae97Ky9CiZE6SctJLUB79H/go-ipfs-posinfo"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
mfs "gx/ipfs/QmPbuswDwcPT4WquGqGoeBBDuuBaUmbZJFYiaes6vkgXYJ/go-mfs"
unixfs "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
balanced "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/balanced"
ihelper "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/helpers"
trickle "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer/trickle"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
chunker "gx/ipfs/QmULKgr55cSWR8Kiwy3cVRcAiGVnR6EVSaB7hJcWS4138p/go-ipfs-chunker"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
mfs "gx/ipfs/QmahrY1adY4wvtYEtoGjpZ2GUohTyukrkMkwUR9ytRjTG2/go-mfs"
chunker "gx/ipfs/QmbrQ27wGQeE8spxjbw9mk5Ef7as4tRFSnWLkEGg4xeg2f/go-ipfs-chunker"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
)
var log = logging.Logger("coreunix")
@ -46,13 +47,6 @@ type Object struct {
Size string
}
type AddedObject struct {
Name string
Hash string `json:",omitempty"`
Bytes int64 `json:",omitempty"`
Size string `json:",omitempty"`
}
// NewAdder Returns a new Adder used for a file add operation.
func NewAdder(ctx context.Context, p pin.Pinner, bs bstore.GCBlockstore, ds ipld.DAGService) (*Adder, error) {
return &Adder{
@ -75,7 +69,7 @@ type Adder struct {
pinning pin.Pinner
blockstore bstore.GCBlockstore
dagService ipld.DAGService
Out chan interface{}
Out chan<- interface{}
Progress bool
Hidden bool
Pin bool
@ -398,8 +392,8 @@ func (adder *Adder) addNode(node ipld.Node, path string) error {
return nil
}
// AddFile adds the given file while respecting the adder.
func (adder *Adder) AddFile(file files.File) error {
// AddAllAndPin adds the given request's files and pin them.
func (adder *Adder) AddAllAndPin(file files.File) (ipld.Node, error) {
if adder.Pin {
adder.unlocker = adder.blockstore.PinLock()
}
@ -409,7 +403,41 @@ func (adder *Adder) AddFile(file files.File) error {
}
}()
return adder.addFile(file)
switch {
case file.IsDirectory():
// Iterate over each top-level file and add individually. Otherwise the
// single files.File f is treated as a directory, affecting hidden file
// semantics.
for {
f, err := file.NextFile()
if err == io.EOF {
// Finished the list of files.
break
} else if err != nil {
return nil, err
}
if err := adder.addFile(f); err != nil {
return nil, err
}
}
break
default:
if err := adder.addFile(file); err != nil {
return nil, err
}
break
}
// copy intermediary nodes from editor to our actual dagservice
nd, err := adder.Finalize()
if err != nil {
return nil, err
}
if !adder.Pin {
return nd, nil
}
return nd, adder.PinRoot()
}
func (adder *Adder) addFile(file files.File) error {
@ -536,7 +564,7 @@ func (adder *Adder) maybePauseForGC() error {
}
// outputDagnode sends dagnode info over the output channel
func outputDagnode(out chan interface{}, name string, dn ipld.Node) error {
func outputDagnode(out chan<- interface{}, name string, dn ipld.Node) error {
if out == nil {
return nil
}
@ -546,7 +574,7 @@ func outputDagnode(out chan interface{}, name string, dn ipld.Node) error {
return err
}
out <- &AddedObject{
out <- &coreiface.AddEvent{
Hash: o.Hash,
Name: name,
Size: o.Size,
@ -581,7 +609,7 @@ func getOutput(dagnode ipld.Node) (*Object, error) {
type progressReader struct {
file files.File
out chan interface{}
out chan<- interface{}
bytes int64
lastProgress int64
}
@ -592,7 +620,7 @@ func (i *progressReader) Read(p []byte) (int, error) {
i.bytes += int64(n)
if i.bytes-i.lastProgress >= progressReaderIncrement || err == io.EOF {
i.lastProgress = i.bytes
i.out <- &AddedObject{
i.out <- &coreiface.AddEvent{
Name: i.file.FileName(),
Bytes: i.bytes,
}

View File

@ -11,6 +11,7 @@ import (
"time"
"github.com/ipfs/go-ipfs/core"
coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface"
"github.com/ipfs/go-ipfs/pin/gc"
"github.com/ipfs/go-ipfs/repo"
@ -18,12 +19,12 @@ import (
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
blocks "gx/ipfs/QmRcHuYzAyswytBuMF78rj3LTChYszomRFXNg4685ZN1WM/go-block-format"
files "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit/files"
datastore "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
syncds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
"gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
blockstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
"gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
datastore "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
syncds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
blockstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
)
const testPeerID = "QmTFauExutTsy4XP6JbMFcw2Wa9645HJt2bTqL6qYDCKfe"
@ -85,7 +86,7 @@ func TestAddGCLive(t *testing.T) {
go func() {
defer close(addDone)
defer close(out)
err := adder.AddFile(slf)
_, err := adder.AddAllAndPin(slf)
if err != nil {
t.Fatal(err)
@ -96,7 +97,7 @@ func TestAddGCLive(t *testing.T) {
addedHashes := make(map[string]struct{})
select {
case o := <-out:
addedHashes[o.(*AddedObject).Hash] = struct{}{}
addedHashes[o.(*coreiface.AddEvent).Hash] = struct{}{}
case <-addDone:
t.Fatal("add shouldnt complete yet")
}
@ -124,7 +125,7 @@ func TestAddGCLive(t *testing.T) {
// receive next object from adder
o := <-out
addedHashes[o.(*AddedObject).Hash] = struct{}{}
addedHashes[o.(*coreiface.AddEvent).Hash] = struct{}{}
<-gcstarted
@ -140,7 +141,7 @@ func TestAddGCLive(t *testing.T) {
var last cid.Cid
for a := range out {
// wait for it to finish
c, err := cid.Decode(a.(*AddedObject).Hash)
c, err := cid.Decode(a.(*coreiface.AddEvent).Hash)
if err != nil {
t.Fatal(err)
}
@ -178,7 +179,8 @@ func testAddWPosInfo(t *testing.T, rawLeaves bool) {
if err != nil {
t.Fatal(err)
}
adder.Out = make(chan interface{})
out := make(chan interface{})
adder.Out = out
adder.Progress = true
adder.RawLeaves = rawLeaves
adder.NoCopy = true
@ -191,12 +193,12 @@ func testAddWPosInfo(t *testing.T, rawLeaves bool) {
go func() {
defer close(adder.Out)
err = adder.AddFile(file)
_, err = adder.AddAllAndPin(file)
if err != nil {
t.Fatal(err)
}
}()
for range adder.Out {
for range out {
}
exp := 0

View File

@ -1,24 +0,0 @@
package coreunix
import (
"context"
core "github.com/ipfs/go-ipfs/core"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
)
func Cat(ctx context.Context, n *core.IpfsNode, pstr string) (uio.DagReader, error) {
r := &resolver.Resolver{
DAG: n.DAG,
ResolveOnce: uio.ResolveUnixfsOnce,
}
dagNode, err := core.Resolve(ctx, n.Namesys, r, path.Path(pstr))
if err != nil {
return nil, err
}
return uio.NewDagReader(ctx, dagNode, n.DAG)
}

View File

@ -3,8 +3,8 @@ package coreunix
import (
core "github.com/ipfs/go-ipfs/core"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
dag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
dag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
)
func AddMetadataTo(n *core.IpfsNode, skey string, m *ft.Metadata) (string, error) {

View File

@ -7,20 +7,20 @@ import (
"testing"
core "github.com/ipfs/go-ipfs/core"
ft "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs"
importer "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/importer"
uio "gx/ipfs/QmU4x3742bvgfxJsByEDpBnifJqjJdV6x528co4hwKCn46/go-unixfs/io"
merkledag "gx/ipfs/QmcBoNcAP6qDjgRBew7yjvCqHq7p5jMstE44jPUBWBxzsV/go-merkledag"
bserv "gx/ipfs/QmcRecCZWM2NZfCQrCe97Ch3Givv8KKEP82tGUDntzdLFe/go-blockservice"
ft "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs"
importer "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/importer"
uio "gx/ipfs/QmQDcPcBH8nfz3JB4K4oEvxhRmBwCrMgvG966XpExEWexf/go-unixfs/io"
merkledag "gx/ipfs/QmXTw4By9FMZAt7qJm4JoJuNBrBgqMMzkS4AjKc4zqTUVd/go-merkledag"
bserv "gx/ipfs/QmY1fUNoXjC8sH86kyaK8BWFGaU6MmH4AJfF1w4sKjmtRZ/go-blockservice"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
u "gx/ipfs/QmPdKqUcHGFdeSpvjVoaTRPPstGif9GBZb5Q56RVw9o69A/go-ipfs-util"
offline "gx/ipfs/QmR5miWuikPxWyUrzMYJVmFUcD44pGdtc98h9Qsbp4YcJw/go-ipfs-exchange-offline"
chunker "gx/ipfs/QmULKgr55cSWR8Kiwy3cVRcAiGVnR6EVSaB7hJcWS4138p/go-ipfs-chunker"
ds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
dssync "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
offline "gx/ipfs/QmT6dHGp3UYd3vUMpy7rzX2CXQv7HLcj42Vtq8qwwjgASb/go-ipfs-exchange-offline"
ds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
dssync "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
chunker "gx/ipfs/QmbrQ27wGQeE8spxjbw9mk5Ef7as4tRFSnWLkEGg4xeg2f/go-ipfs-chunker"
bstore "gx/ipfs/QmcDDgAXDbpDUpadCJKLr49KYR4HuL7T8Z1dZTHt6ixsoR/go-ipfs-blockstore"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
bstore "gx/ipfs/QmdriVJgKx4JADRgh3cYPXqXmsa1A45SvFki1nDWHhQNtC/go-ipfs-blockstore"
)
func getDagserv(t *testing.T) ipld.DAGService {

View File

@ -8,14 +8,14 @@ import (
"github.com/ipfs/go-ipfs/repo"
testutil "gx/ipfs/QmNfQbgBfARAtrYsBguChX6VJ5nbjeoYy1KdC36aaYWqG8/go-testutil"
datastore "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore"
syncds "gx/ipfs/QmUyz7JTJzgegC6tiJrfby3mPhzcdswVtG4x58TQ6pq8jV/go-datastore/sync"
config "gx/ipfs/QmVBUpxsHh53rNcufqxMpLAmz37eGyLJUaexDy1W9YkiNk/go-ipfs-config"
libp2p "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p"
mocknet "gx/ipfs/QmVsVARb86uSe1qYouewFMNd2p2sp2NGWm1JGPReVDWchW/go-libp2p/p2p/net/mock"
host "gx/ipfs/QmQKod7iLxQK6X3aFYvhDDnFdXo3QjxKeL2F7UrPtdKQR2/go-libp2p-host"
config "gx/ipfs/QmSoYrBMibm2T3LupaLuez7LPGnyrJwdRxvTfPUyCp691u/go-ipfs-config"
libp2p "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p"
mocknet "gx/ipfs/QmU9Cf9q5TBCAC3kg74Fqr6K7DQTwa41C44YypYqB2GfR8/go-libp2p/p2p/net/mock"
pstore "gx/ipfs/QmXEyLwySuDMXejWBu8XwdkX2WuGKk8x9jFwz8js7j72UX/go-libp2p-peerstore"
datastore "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore"
syncds "gx/ipfs/QmaRb5yNXKonhbkpNxNawoydk4N6es6b4fPj19sjEKsh5D/go-datastore/sync"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
host "gx/ipfs/QmeA5hsqgLryvkeyqeQdvGDqurLkYi3XEPLZP3pzuBJXh2/go-libp2p-host"
pstore "gx/ipfs/QmfAQMFpgDU2U4BXG64qVr8HSiictfWvkSBz7Y2oDj65st/go-libp2p-peerstore"
)
// NewMockNode constructs an IpfsNode for use in tests.

View File

@ -6,10 +6,9 @@ import (
"strings"
namesys "github.com/ipfs/go-ipfs/namesys"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
resolver "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path/resolver"
cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
resolver "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path/resolver"
logging "gx/ipfs/QmZChCsSt8DctjceaL56Eibc29CVQq4dGKRXC5JRZ6Ppae/go-log"
ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format"
)
@ -74,37 +73,3 @@ func Resolve(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver,
// ok, we have an IPFS path now (or what we'll treat as one)
return r.ResolvePath(ctx, p)
}
// ResolveToCid resolves a path to a cid.
//
// It first checks if the path is already in the form of just a cid (<cid> or
// /ipfs/<cid>) and returns immediately if so. Otherwise, it falls back onto
// Resolve to perform resolution of the dagnode being referenced.
func ResolveToCid(ctx context.Context, nsys namesys.NameSystem, r *resolver.Resolver, p path.Path) (cid.Cid, error) {
// If the path is simply a cid, parse and return it. Parsed paths are already
// normalized (read: prepended with /ipfs/ if needed), so segment[1] should
// always be the key.
if p.IsJustAKey() {
return cid.Decode(p.Segments()[1])
}
// Fall back onto regular dagnode resolution. Retrieve the second-to-last
// segment of the path and resolve its link to the last segment.
head, tail, err := p.PopLastSegment()
if err != nil {
return cid.Cid{}, err
}
dagnode, err := Resolve(ctx, nsys, r, head)
if err != nil {
return cid.Cid{}, err
}
// Extract and return the cid of the link to the target dag node.
link, _, err := dagnode.ResolveLink([]string{tail})
if err != nil {
return cid.Cid{}, err
}
return link.Cid, nil
}

View File

@ -5,7 +5,7 @@ import (
core "github.com/ipfs/go-ipfs/core"
coremock "github.com/ipfs/go-ipfs/core/mock"
path "gx/ipfs/QmcjwUb36Z16NJkvDX6ccXPqsFswo6AsRXynyXcLLCphV2/go-path"
path "gx/ipfs/QmQmMu1vsgsjxyB8tzrA6ZTCTCLDLVaXMb4Q57r2v886Sx/go-path"
)
func TestResolveNoComponents(t *testing.T) {

Some files were not shown because too many files have changed in this diff Show More