commands: Refactored Command#Run function signature to (req Request, res Response)

This commit is contained in:
Matt Bell 2015-01-20 17:58:50 -08:00
parent 856d2896a7
commit 7b4de230eb
27 changed files with 426 additions and 236 deletions

View File

@ -47,13 +47,14 @@ the daemon.
Run: daemonFunc,
}
func daemonFunc(req cmds.Request) (interface{}, error) {
func daemonFunc(req cmds.Request, res cmds.Response) {
// first, whether user has provided the initialization flag. we may be
// running in an uninitialized state.
initialize, _, err := req.Option(initOptionKwd).Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if initialize {
@ -64,7 +65,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
if !util.FileExists(req.Context().ConfigRoot) {
err := initWithDefaults(req.Context().ConfigRoot)
if err != nil {
return nil, debugerror.Wrap(err)
res.SetError(debugerror.Wrap(err), cmds.ErrNormal)
return
}
}
}
@ -77,14 +79,16 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
ctx := req.Context()
cfg, err := ctx.GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// acquire the repo lock _before_ constructing a node. we need to make
// sure we are permitted to access the resources (datastore, etc.)
repo := fsrepo.At(req.Context().ConfigRoot)
if err := repo.Open(); err != nil {
return nil, debugerror.Errorf("Couldn't obtain lock. Is another daemon already running?")
res.SetError(debugerror.Errorf("Couldn't obtain lock. Is another daemon already running?"), cmds.ErrNormal)
return
}
defer repo.Close()
@ -93,13 +97,15 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
ctx.Online = true
node, err := ctx.GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// verify api address is valid multiaddr
apiMaddr, err := ma.NewMultiaddr(cfg.Addresses.API)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
var gatewayMaddr ma.Multiaddr
@ -115,12 +121,14 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
// mount if the user provided the --mount flag
mount, _, err := req.Option(mountKwd).Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if mount {
fsdir, found, err := req.Option(ipfsMountKwd).String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
fsdir = cfg.Mounts.IPFS
@ -128,7 +136,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
nsdir, found, err := req.Option(ipnsMountKwd).String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
nsdir = cfg.Mounts.IPNS
@ -136,7 +145,8 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
err = commands.Mount(node, fsdir, nsdir)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
fmt.Printf("IPFS mounted at: %s\n", fsdir)
fmt.Printf("IPNS mounted at: %s\n", nsdir)
@ -156,5 +166,9 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
corehttp.WebUIOption,
corehttp.GatewayOption,
}
return nil, corehttp.ListenAndServe(node, apiMaddr, opts...)
err = corehttp.ListenAndServe(node, apiMaddr, opts...)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
}

View File

@ -39,22 +39,29 @@ var initCmd = &cmds.Command{
// name of the file?
// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !bitsOptFound {
nBitsForKeypair = nBitsForKeypairDefault
}
return doInit(req.Context().ConfigRoot, force, nBitsForKeypair)
output, err := doInit(req.Context().ConfigRoot, force, nBitsForKeypair)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
}

View File

@ -36,11 +36,12 @@ IPFS very quickly. To start, run:
Run: tourRunFunc,
}
func tourRunFunc(req cmds.Request) (interface{}, error) {
func tourRunFunc(req cmds.Request, res cmds.Response) {
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
id := tour.TopicID(cfg.Tour.Last)
@ -64,11 +65,10 @@ func tourRunFunc(req cmds.Request) (interface{}, error) {
fmt.Fprintln(&w, "")
fprintTourList(&w, tour.TopicID(cfg.Tour.Last))
return nil, nil
return
}
fprintTourShow(&w, t)
return nil, nil
}
var cmdIpfsTourNext = &cmds.Command{
@ -76,21 +76,24 @@ var cmdIpfsTourNext = &cmds.Command{
Tagline: "Show the next IPFS Tour topic",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
var w bytes.Buffer
path := req.Context().ConfigRoot
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
id := tour.NextTopic(tour.TopicID(cfg.Tour.Last))
topic, err := tourGet(id)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if err := fprintTourShow(&w, topic); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// topic changed, not last. write it out.
@ -98,12 +101,12 @@ var cmdIpfsTourNext = &cmds.Command{
cfg.Tour.Last = string(id)
err := writeConfig(path, cfg)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
}
w.WriteTo(os.Stdout)
return nil, nil
},
}
@ -112,19 +115,20 @@ var cmdIpfsTourRestart = &cmds.Command{
Tagline: "Restart the IPFS Tour",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
path := req.Context().ConfigRoot
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
cfg.Tour.Last = ""
err = writeConfig(path, cfg)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return nil, nil
},
}
@ -133,16 +137,16 @@ var cmdIpfsTourList = &cmds.Command{
Tagline: "Show a list of IPFS Tour topics",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
var w bytes.Buffer
fprintTourList(&w, tour.TopicID(cfg.Tour.Last))
w.WriteTo(os.Stdout)
return nil, nil
},
}

View File

@ -14,7 +14,7 @@ var log = u.Logger("command")
// Function is the type of function that Commands use.
// It reads from the Request, and writes results to the Response.
type Function func(Request) (interface{}, error)
type Function func(Request, Response)
// Marshaler is a function that takes in a Response, and returns an io.Reader
// (or an error on failure)
@ -95,21 +95,12 @@ func (c *Command) Call(req Request) Response {
return res
}
output, err := cmd.Run(req)
if err != nil {
// if returned error is a commands.Error, use its error code
// otherwise, just default the code to ErrNormal
switch e := err.(type) {
case *Error:
res.SetError(e, e.Code)
case Error:
res.SetError(e, e.Code)
default:
res.SetError(err, ErrNormal)
}
cmd.Run(req, res)
if res.Error() != nil {
return res
}
output := res.Output()
isChan := false
actualType := reflect.TypeOf(output)
if actualType != nil {
@ -140,7 +131,6 @@ func (c *Command) Call(req Request) Response {
}
}
res.SetOutput(output)
return res
}

View File

@ -2,8 +2,8 @@ package commands
import "testing"
func noop(req Request) (interface{}, error) {
return nil, nil
func noop(req Request, res Response) {
return
}
func TestOptionValidation(t *testing.T) {

View File

@ -44,13 +44,15 @@ remains to be implemented.
cmds.OptionRecursivePath, // a builtin option that allows recursive paths (-r, --recursive)
cmds.BoolOption("quiet", "q", "Write minimal output"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
outChan := make(chan interface{})
res.SetOutput((<-chan interface{})(outChan))
go func() {
defer close(outChan)
@ -67,8 +69,6 @@ remains to be implemented.
}
}
}()
return outChan, nil
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -2,6 +2,7 @@ package commands
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
@ -57,16 +58,17 @@ on raw ipfs blocks. It outputs the following to stdout:
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
b, err := getBlockForKey(req, req.Arguments()[0])
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return &BlockStat{
res.SetOutput(&BlockStat{
Key: b.Key().Pretty(),
Size: len(b.Data),
}, nil
})
},
Type: BlockStat{},
Marshalers: cmds.MarshalerMap{
@ -89,13 +91,14 @@ It outputs to stdout, and <key> is a base58 encoded multihash.
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
b, err := getBlockForKey(req, req.Arguments()[0])
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return bytes.NewReader(b.Data), nil
res.SetOutput(bytes.NewReader(b.Data))
},
}
@ -111,25 +114,29 @@ It reads from stdin, and <key> is a base58 encoded multihash.
Arguments: []cmds.Argument{
cmds.FileArg("data", true, false, "The data to be stored as an IPFS block").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
file, err := req.Files().NextFile()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
data, err := ioutil.ReadAll(file)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
err = file.Close()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
b := blocks.NewBlock(data)
@ -137,13 +144,14 @@ It reads from stdin, and <key> is a base58 encoded multihash.
k, err := n.Blocks.AddBlock(b)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return &BlockStat{
res.SetOutput(&BlockStat{
Key: k.String(),
Size: len(data),
}, nil
})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
@ -160,7 +168,7 @@ func getBlockForKey(req cmds.Request, key string) (*blocks.Block, error) {
}
if !u.IsValidHash(key) {
return nil, cmds.Error{"Not a valid hash", cmds.ErrClient}
return nil, errors.New("Not a valid hash")
}
h, err := mh.FromB58String(key)
@ -173,6 +181,7 @@ func getBlockForKey(req cmds.Request, key string) (*blocks.Block, error) {
if err != nil {
return nil, err
}
log.Debugf("ipfs block: got block with key: %q", b.Key())
return b, nil
}

View File

@ -76,29 +76,33 @@ in the bootstrap list).
cmds.BoolOption("default", "add default bootstrap nodes"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
inputPeers, err := config.ParseBootstrapPeers(req.Arguments())
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
r := fsrepo.At(req.Context().ConfigRoot)
if err := r.Open(); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
defer r.Close()
cfg := r.Config()
deflt, _, err := req.Option("default").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if deflt {
// parse separately for meaningful, correct error.
defltPeers, err := DefaultBootstrapPeers()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
inputPeers = append(inputPeers, defltPeers...)
@ -106,14 +110,16 @@ in the bootstrap list).
added, err := bootstrapAdd(r, cfg, inputPeers)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if len(inputPeers) == 0 {
return nil, cmds.ClientError("no bootstrap peers to add")
res.SetError(errors.New("no bootstrap peers to add"), cmds.ErrClient)
return
}
return &BootstrapOutput{added}, nil
res.SetOutput(&BootstrapOutput{added})
},
Type: BootstrapOutput{},
Marshalers: cmds.MarshalerMap{
@ -125,7 +131,11 @@ in the bootstrap list).
var buf bytes.Buffer
err := bootstrapWritePeers(&buf, "added ", v.Peers)
return &buf, err
if err != nil {
return nil, err
}
return &buf, nil
},
},
}
@ -143,22 +153,25 @@ var bootstrapRemoveCmd = &cmds.Command{
Options: []cmds.Option{
cmds.BoolOption("all", "Remove all bootstrap peers."),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
input, err := config.ParseBootstrapPeers(req.Arguments())
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
r := fsrepo.At(req.Context().ConfigRoot)
if err := r.Open(); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
defer r.Close()
cfg := r.Config()
all, _, err := req.Option("all").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
var removed []config.BootstrapPeer
@ -168,10 +181,11 @@ var bootstrapRemoveCmd = &cmds.Command{
removed, err = bootstrapRemove(r, cfg, input)
}
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return &BootstrapOutput{removed}, nil
res.SetOutput(&BootstrapOutput{removed})
},
Type: BootstrapOutput{},
Marshalers: cmds.MarshalerMap{
@ -194,14 +208,15 @@ var bootstrapListCmd = &cmds.Command{
ShortDescription: "Peers are output in the format '<multiaddr>/<peerID>'.",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
peers := cfg.Bootstrap
return &BootstrapOutput{peers}, nil
res.SetOutput(&BootstrapOutput{peers})
},
Type: BootstrapOutput{},
Marshalers: cmds.MarshalerMap{

View File

@ -20,21 +20,23 @@ it contains.
Arguments: []cmds.Argument{
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to be outputted").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
node, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
readers := make([]io.Reader, 0, len(req.Arguments()))
readers, err = cat(node, req.Arguments())
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
reader := io.MultiReader(readers...)
return reader, nil
res.SetOutput(reader)
},
}

View File

@ -22,9 +22,9 @@ func CommandsCmd(root *cmds.Command) *cmds.Command {
ShortDescription: `Lists all available commands (and subcommands) and exits.`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
root := cmd2outputCmd("ipfs", root)
return &root, nil
res.SetOutput(&root)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -57,23 +57,34 @@ Set the value of the 'datastore.path' key:
cmds.StringArg("key", true, false, "The key of the config entry (e.g. \"Addresses.API\")"),
cmds.StringArg("value", false, false, "The value to set the config entry to"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
args := req.Arguments()
key := args[0]
r := fsrepo.At(req.Context().ConfigRoot)
if err := r.Open(); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
defer r.Close()
var value string
if len(args) == 2 {
value = args[1]
return setConfig(r, key, value)
output, err := setConfig(r, key, value)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
} else {
return getConfig(r, key)
output, err := getConfig(r, key)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
}
},
Marshalers: cmds.MarshalerMap{
@ -117,13 +128,19 @@ included in the output of this command.
`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
filename, err := config.Filename(req.Context().ConfigRoot)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return showConfig(filename)
output, err := showConfig(filename)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
}
@ -136,19 +153,23 @@ variable set to your preferred text editor.
`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
filename, err := config.Filename(req.Context().ConfigRoot)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return nil, editConfig(filename)
err = editConfig(filename)
if err != nil {
res.SetError(err, cmds.ErrNormal)
}
},
}
var configReplaceCmd = &cmds.Command{
Helptext: cmds.HelpText{
Tagline: "Replaces the config with <file>",
Tagline: "Replaces the config with `file>",
ShortDescription: `
Make sure to back up the config file first if neccessary, this operation
can't be undone.
@ -158,20 +179,26 @@ can't be undone.
Arguments: []cmds.Argument{
cmds.FileArg("file", true, false, "The file to use as the new config"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
r := fsrepo.At(req.Context().ConfigRoot)
if err := r.Open(); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
defer r.Close()
file, err := req.Files().NextFile()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
defer file.Close()
return nil, replaceConfig(r, file)
err = replaceConfig(r, file)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
},
}

View File

@ -2,6 +2,7 @@ package commands
import (
"bytes"
"errors"
"io"
"strings"
"text/template"
@ -63,50 +64,65 @@ connected peers and latencies between them.
cmds.StringOption("vis", "output vis. one of: "+strings.Join(visFmts, ", ")),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !n.OnlineMode() {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
vis, _, err := req.Option("vis").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
timeoutS, _, err := req.Option("timeout").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
timeout := DefaultDiagnosticTimeout
if timeoutS != "" {
t, err := time.ParseDuration(timeoutS)
if err != nil {
return nil, cmds.ClientError("error parsing timeout")
res.SetError(errors.New("error parsing timeout"), cmds.ErrNormal)
return
}
timeout = t
}
info, err := n.Diagnostics.GetDiagnostic(timeout)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
switch vis {
case visD3:
return bytes.NewReader(diag.GetGraphJson(info)), nil
res.SetOutput(bytes.NewReader(diag.GetGraphJson(info)))
case visDot:
var buf bytes.Buffer
w := diag.DotWriter{W: &buf}
err := w.WriteGraph(info)
return io.Reader(&buf), err
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(io.Reader(&buf))
}
return stdDiagOutputMarshal(standardDiagOutput(info))
output, err := stdDiagOutputMarshal(standardDiagOutput(info))
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
}

View File

@ -45,37 +45,54 @@ if no peer is specified, prints out local peers info.
Arguments: []cmds.Argument{
cmds.StringArg("peerid", false, false, "peer.ID of node to look up").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
node, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if len(req.Arguments()) == 0 {
return printPeer(node.Peerstore, node.Identity)
output, err := printPeer(node.Peerstore, node.Identity)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
return
}
pid := req.Arguments()[0]
id := peer.ID(b58.Decode(pid))
if len(id) == 0 {
return nil, cmds.ClientError("Invalid peer id")
res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient)
return
}
ctx, _ := context.WithTimeout(context.TODO(), time.Second*5)
// TODO handle offline mode with polymorphism instead of conditionals
if !node.OnlineMode() {
return nil, errors.New(offlineIdErrorMessage)
res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
return
}
p, err := node.Routing.FindPeer(ctx, id)
if err == kb.ErrLookupFailure {
return nil, errors.New(offlineIdErrorMessage)
res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient)
return
}
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return printPeer(node.Peerstore, p.ID)
output, err := printPeer(node.Peerstore, p.ID)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -47,7 +47,7 @@ output of a running daemon.
cmds.StringArg("subsystem", true, false, fmt.Sprintf("the subsystem logging identifier. Use '%s' for all subsystems.", logAllKeyword)),
cmds.StringArg("level", true, false, "one of: debug, info, notice, warning, error, critical"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
args := req.Arguments()
subsystem, level := args[0], args[1]
@ -57,12 +57,13 @@ output of a running daemon.
}
if err := u.SetLogLevel(subsystem, level); err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
s := fmt.Sprintf("Changed log level of '%s' to '%s'", subsystem, level)
log.Info(s)
return &MessageOutput{s}, nil
res.SetOutput(&MessageOutput{s})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: MessageTextMarshaler,
@ -78,7 +79,7 @@ var logTailCmd = &cmds.Command{
`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
path := fmt.Sprintf("%s/logs/events.log", req.Context().ConfigRoot)
outChan := make(chan interface{})
@ -108,7 +109,7 @@ var logTailCmd = &cmds.Command{
}
}()
return (<-chan interface{})(outChan), nil
res.SetOutput((<-chan interface{})(outChan))
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -37,10 +37,11 @@ it contains, with the following format:
Arguments: []cmds.Argument{
cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
node, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
paths := req.Arguments()
@ -49,7 +50,8 @@ it contains, with the following format:
for _, path := range paths {
dagnode, err := node.Resolver.ResolvePath(path)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
dagnodes = append(dagnodes, dagnode)
}
@ -69,7 +71,7 @@ it contains, with the following format:
}
}
return &LsOutput{output}, nil
res.SetOutput(&LsOutput{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -90,25 +90,29 @@ baz
// TODO longform
cmds.StringOption("n", "The path where IPNS should be mounted"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
cfg, err := req.Context().GetConfig()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
node, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// error if we aren't running node in online mode
if !node.OnlineMode() {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
fsdir, found, err := req.Option("f").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
fsdir = cfg.Mounts.IPFS // use default value
@ -117,7 +121,8 @@ baz
// get default mount points
nsdir, found, err := req.Option("n").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
nsdir = cfg.Mounts.IPNS // NB: be sure to not redeclare!
@ -125,13 +130,14 @@ baz
err = Mount(node, fsdir, nsdir)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
var output config.Mounts
output.IPFS = fsdir
output.IPNS = nsdir
return &output, nil
res.SetOutput(&output)
},
Type: config.Mounts{},
Marshalers: cmds.MarshalerMap{

View File

@ -13,8 +13,8 @@ var MountCmd = &cmds.Command{
ShortDescription: "Not yet implemented on Windows. :(",
},
Run: func(req cmds.Request) (interface{}, error) {
return errors.New("Mount isn't compatible with Windows yet"), nil
Run: func(req cmds.Request, res cmds.Response) {
res.SetError(errors.New("Mount isn't compatible with Windows yet"), cmds.ErrNormal)
},
}

View File

@ -71,14 +71,20 @@ output is the raw data of the object.
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
key := req.Arguments()[0]
return objectData(n, key)
output, err := objectData(n, key)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
}
@ -95,14 +101,20 @@ multihash.
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "Key of the object to retrieve, in base58-encoded multihash format").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
key := req.Arguments()[0]
return objectLinks(n, key)
output, err := objectLinks(n, key)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
@ -137,17 +149,19 @@ This command outputs data in the following encodings:
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "Key of the object to retrieve (in base58-encoded multihash format)").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
key := req.Arguments()[0]
object, err := objectGet(n, key)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
node := &Node{
@ -163,7 +177,7 @@ This command outputs data in the following encodings:
}
}
return node, nil
res.SetOutput(node)
},
Type: Node{},
Marshalers: cmds.MarshalerMap{
@ -201,25 +215,28 @@ var objectStatCmd = &cmds.Command{
Arguments: []cmds.Argument{
cmds.StringArg("key", true, false, "Key of the object to retrieve (in base58-encoded multihash format)").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
key := req.Arguments()[0]
object, err := objectGet(n, key)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
ns, err := object.Stat()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return ns, nil
res.SetOutput(ns)
},
Type: dag.NodeStat{},
Marshalers: cmds.MarshalerMap{
@ -263,15 +280,17 @@ Data should be in the format specified by <encoding>.
cmds.FileArg("data", true, false, "Data to be stored as a DAG object"),
cmds.StringArg("encoding", true, false, "Encoding type of <data>, either \"protobuf\" or \"json\""),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
input, err := req.Files().NextFile()
if err != nil && err != io.EOF {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
encoding := req.Arguments()[0]
@ -282,10 +301,11 @@ Data should be in the format specified by <encoding>.
if err == ErrUnknownObjectEnc {
errType = cmds.ErrClient
}
return nil, cmds.Error{err.Error(), errType}
res.SetError(err, errType)
return
}
return output, nil
res.SetOutput(output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -42,16 +42,18 @@ on disk.
cmds.BoolOption("recursive", "r", "Recursively pin the object linked to by the specified object(s)"),
},
Type: PinOutput{},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// set recursive flag
recursive, found, err := req.Option("recursive").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
recursive = false
@ -59,10 +61,11 @@ on disk.
added, err := corerepo.Pin(n, req.Arguments(), recursive)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return &PinOutput{added}, nil
res.SetOutput(&PinOutput{added})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
@ -104,16 +107,18 @@ collected if needed.
cmds.BoolOption("recursive", "r", "Recursively unpin the object linked to by the specified object(s)"),
},
Type: PinOutput{},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// set recursive flag
recursive, found, err := req.Option("recursive").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
recursive = false // default
@ -121,10 +126,11 @@ collected if needed.
removed, err := corerepo.Unpin(n, req.Arguments(), recursive)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return &PinOutput{removed}, nil
res.SetOutput(&PinOutput{removed})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {
@ -165,15 +171,17 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
Options: []cmds.Option{
cmds.StringOption("type", "t", "The type of pinned keys to list. Can be \"direct\", \"indirect\", \"recursive\", or \"all\". Defaults to \"direct\""),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
typeStr, found, err := req.Option("type").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if !found {
typeStr = "direct"
@ -182,7 +190,8 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
switch typeStr {
case "all", "direct", "indirect", "recursive":
default:
return nil, cmds.ClientError("Invalid type '" + typeStr + "', must be one of {direct, indirect, recursive, all}")
err = fmt.Errorf("Invalid type '%s', must be one of {direct, indirect, recursive, all}", typeStr)
res.SetError(err, cmds.ErrClient)
}
keys := make([]u.Key, 0)
@ -196,7 +205,7 @@ Use --type=<type> to specify the type of pinned keys to list. Valid values are:
keys = append(keys, n.Pinning.RecursiveKeys()...)
}
return &KeyList{Keys: keys}, nil
res.SetOutput(&KeyList{Keys: keys})
},
Type: KeyList{},
Marshalers: cmds.MarshalerMap{

View File

@ -74,21 +74,24 @@ trip latency information.
}, nil
},
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
ctx := req.Context().Context
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// Must be online!
if !n.OnlineMode() {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
addr, peerID, err := ParsePeerParam(req.Arguments()[0])
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if addr != nil {
@ -99,14 +102,15 @@ trip latency information.
numPings := 10
val, found, err := req.Option("count").Int()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if found {
numPings = val
}
outChan := pingPeer(ctx, n, peerID, numPings)
return outChan, nil
res.SetOutput(outChan)
},
Type: PingResult{},
}

View File

@ -46,21 +46,23 @@ Publish a <ref> to another public key:
cmds.StringArg("name", false, false, "The IPNS name to publish to. Defaults to your node's peerID"),
cmds.StringArg("ipfs-path", true, false, "IPFS path of the obejct to be published at <name>").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
log.Debug("Begin Publish")
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
args := req.Arguments()
if n.PeerHost == nil {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
}
if n.Identity == "" {
return nil, errors.New("Identity not loaded!")
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
return
}
// name := ""
@ -70,14 +72,19 @@ Publish a <ref> to another public key:
case 2:
// name = args[0]
ref = args[1]
return nil, errors.New("keychains not yet implemented")
res.SetError(errors.New("keychains not yet implemented"), cmds.ErrNormal)
case 1:
// name = n.Identity.ID.String()
ref = args[0]
}
// TODO n.Keychain.Get(name).PrivKey
return publish(n, n.PrivateKey, ref)
output, err := publish(n, n.PrivateKey, ref)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -53,36 +53,42 @@ Note: list all refs recursively with -r.
cmds.BoolOption("unique", "u", "Omit duplicate refs from output"),
cmds.BoolOption("recursive", "r", "Recursively list links of child nodes"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
ctx := req.Context().Context
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
unique, _, err := req.Option("unique").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
recursive, _, err := req.Option("recursive").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
edges, _, err := req.Option("edges").Bool()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
format, _, err := req.Option("format").String()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
objs, err := objectsForPaths(n, req.Arguments())
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
piper, pipew := io.Pipe()
@ -110,7 +116,7 @@ Note: list all refs recursively with -r.
}
}()
return eptr, nil
res.SetOutput(eptr)
},
}
@ -122,17 +128,19 @@ Displays the hashes of all local objects.
`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
ctx := req.Context().Context
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// todo: make async
allKeys, err := n.Blockstore.AllKeysChan(ctx, 0, 0)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
piper, pipew := io.Pipe()
@ -151,7 +159,7 @@ Displays the hashes of all local objects.
}
}()
return eptr, nil
res.SetOutput(eptr)
},
}

View File

@ -36,26 +36,28 @@ order to reclaim hard disk space.
Options: []cmds.Option{
cmds.BoolOption("quiet", "q", "Write minimal output"),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
gcOutChan, err := corerepo.GarbageCollectBlockstore(n, req.Context().Context)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
outChan := make(chan interface{})
res.SetOutput((<-chan interface{})(outChan))
go func() {
defer close(outChan)
for k := range gcOutChan {
outChan <- k
}
}()
return outChan, nil
},
Type: corerepo.KeyRemoved{},
Marshalers: cmds.MarshalerMap{

View File

@ -40,22 +40,25 @@ Resolve te value of another name:
Arguments: []cmds.Argument{
cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID.").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
var name string
if n.PeerHost == nil {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
if len(req.Arguments()) == 0 {
if n.Identity == "" {
return nil, errors.New("Identity not loaded!")
res.SetError(errors.New("Identity not loaded!"), cmds.ErrNormal)
return
}
name = n.Identity.Pretty()
@ -65,12 +68,13 @@ Resolve te value of another name:
output, err := n.Namesys.Resolve(name)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
// TODO: better errors (in the case of not finding the name, we get "failed to find any peer in table")
return output, nil
res.SetOutput(output)
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {

View File

@ -45,16 +45,18 @@ var swarmPeersCmd = &cmds.Command{
ipfs swarm peers lists the set of peers this node is connected to.
`,
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
log.Debug("ipfs swarm peers")
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
if n.PeerHost == nil {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
conns := n.PeerHost.Network().Conns()
@ -66,7 +68,7 @@ ipfs swarm peers lists the set of peers this node is connected to.
}
sort.Sort(sort.StringSlice(addrs))
return &stringList{addrs}, nil
res.SetOutput(&stringList{addrs})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,
@ -87,24 +89,27 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8Szb
Arguments: []cmds.Argument{
cmds.StringArg("address", true, true, "address of peer to connect to").EnableStdin(),
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
ctx := context.TODO()
log.Debug("ipfs swarm connect")
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
addrs := req.Arguments()
if n.PeerHost == nil {
return nil, errNotOnline
res.SetError(errNotOnline, cmds.ErrClient)
return
}
peers, err := peersWithAddresses(n.Peerstore, addrs)
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
output := make([]string, len(peers))
@ -119,7 +124,7 @@ ipfs swarm connect /ip4/104.131.131.82/tcp/4001/QmaCpDMGvV2BGHeYERUEnRQAwe3N8Szb
}
}
return &stringList{output}, nil
res.SetOutput(&stringList{output})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: stringListMarshaler,

View File

@ -22,12 +22,19 @@ var UpdateCmd = &cmds.Command{
ShortDescription: "ipfs update is a utility command used to check for updates and apply them.",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return updateApply(n)
output, err := updateApply(n)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
Type: UpdateOutput{},
Subcommands: map[string]*cmds.Command{
@ -55,12 +62,19 @@ var UpdateCheckCmd = &cmds.Command{
ShortDescription: "'ipfs update check' checks if any updates are available for IPFS.\nNothing will be downloaded or installed.",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return updateCheck(n)
output, err := updateCheck(n)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
Type: UpdateOutput{},
Marshalers: cmds.MarshalerMap{
@ -84,12 +98,19 @@ var UpdateLogCmd = &cmds.Command{
ShortDescription: "This command is not yet implemented.",
},
Run: func(req cmds.Request) (interface{}, error) {
Run: func(req cmds.Request, res cmds.Response) {
n, err := req.Context().GetNode()
if err != nil {
return nil, err
res.SetError(err, cmds.ErrNormal)
return
}
return updateLog(n)
output, err := updateLog(n)
if err != nil {
res.SetError(err, cmds.ErrNormal)
return
}
res.SetOutput(output)
},
}

View File

@ -22,10 +22,10 @@ var VersionCmd = &cmds.Command{
Options: []cmds.Option{
cmds.BoolOption("number", "n", "Only show the version number"),
},
Run: func(req cmds.Request) (interface{}, error) {
return &VersionOutput{
Run: func(req cmds.Request, res cmds.Response) {
res.SetOutput(&VersionOutput{
Version: config.CurrentVersionNumber,
}, nil
})
},
Marshalers: cmds.MarshalerMap{
cmds.Text: func(res cmds.Response) (io.Reader, error) {