Documentation ¶
Overview ¶
Package commands implements the ipfs command interface
Using github.com/ipfs/go-ipfs/commands to define the command line and HTTP APIs. This is the interface available to folks using IPFS from outside of the Go language.
Index ¶
- Constants
- Variables
- func CommandsCmd(root *cmds.Command) *cmds.Command
- func ExternalBinary() *cmds.Command
- func KeyListTextMarshaler(res cmds.Response) (io.Reader, error)
- func MessageTextMarshaler(res cmds.Response) (io.Reader, error)
- func ParsePeerParam(text string) (ma.Multiaddr, peer.ID, error)
- type AddPinOutput
- type BadNode
- type BlockStat
- type BootstrapOutput
- type Command
- type ConfigField
- type GcResult
- type IdOutput
- type IpnsEntry
- type KeyList
- type KeyOutput
- type KeyOutputList
- type KeyRenameOutput
- type LsLink
- type LsObject
- type LsOutput
- type MessageOutput
- type Option
- type P2PListenerInfoOutput
- type P2PLsOutput
- type P2PStreamInfoOutput
- type P2PStreamsOutput
- type PinOutput
- type PinStatus
- type PinVerifyRes
- type PingResult
- type RefKeyList
- type RefKeyObject
- type RefWrapper
- type RefWriter
- type RepoVersion
- type ResolvedPath
- type VerifyProgress
- type VersionOutput
Constants ¶
const (
ApiOption = "api"
)
Variables ¶
var ActiveReqsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List commands run on this IPFS node.", ShortDescription: ` Lists running and recently run commands. `, }, Run: func(req cmds.Request, res cmds.Response) { res.SetOutput(req.InvocContext().ReqLog.Report()) }, Options: []cmds.Option{ cmds.BoolOption("verbose", "v", "Print extra information.").Default(false), }, Subcommands: map[string]*cmds.Command{ "clear": clearInactiveCmd, "set-time": setRequestClearCmd, }, Marshalers: map[cmds.EncodingType]cmds.Marshaler{ cmds.Text: func(res cmds.Response) (io.Reader, error) { out, ok := res.Output().(*[]*cmds.ReqLogEntry) if !ok { log.Errorf("%#v", res.Output()) return nil, cmds.ErrIncorrectType } buf := new(bytes.Buffer) verbose, _, _ := res.Request().Option("v").Bool() w := tabwriter.NewWriter(buf, 4, 4, 2, ' ', 0) if verbose { fmt.Fprint(w, "ID\t") } fmt.Fprint(w, "Command\t") if verbose { fmt.Fprint(w, "Arguments\tOptions\t") } fmt.Fprintln(w, "Active\tStartTime\tRunTime") for _, req := range *out { if verbose { fmt.Fprintf(w, "%d\t", req.ID) } fmt.Fprintf(w, "%s\t", req.Command) if verbose { fmt.Fprintf(w, "%v\t[", req.Args) var keys []string for k, _ := range req.Options { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Fprintf(w, "%s=%v,", k, req.Options[k]) } fmt.Fprintf(w, "]\t") } var live time.Duration if req.Active { live = time.Since(req.StartTime) } else { live = req.EndTime.Sub(req.StartTime) } t := req.StartTime.Format(time.Stamp) fmt.Fprintf(w, "%t\t%s\t%s\n", req.Active, t, live) } w.Flush() return buf, nil }, }, Type: []*cmds.ReqLogEntry{}, }
var AddCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Add a file or directory to ipfs.", ShortDescription: ` Adds contents of <path> to ipfs. Use -r to add directories (recursively). `, LongDescription: ` Adds contents of <path> to ipfs. Use -r to add directories. Note that directories are added recursively, to form the ipfs MerkleDAG. The wrap option, '-w', wraps the file (or files, if using the recursive option) in a directory. This directory contains only the files which have been added, and means that the file retains its filename. For example: > ipfs add example.jpg added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg > ipfs add example.jpg -w added QmbFMke1KXqnYyBBWxB74N4c5SBnJMVAiMNRcGu6x1AwQH example.jpg added QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx You can now refer to the added file in a gateway, like so: /ipfs/QmaG4FuMqEBnQNn3C8XJ5bpW8kLs7zq2ZXgHptJHbKDDVx/example.jpg `, }, Arguments: []cmds.Argument{ cmds.FileArg("path", true, true, "The path to a file to be added to ipfs.").EnableRecursive().EnableStdin(), }, Options: []cmds.Option{ cmds.OptionRecursivePath, cmds.BoolOption(quietOptionName, "q", "Write minimal output."), cmds.BoolOption(quieterOptionName, "Q", "Write only final hash."), cmds.BoolOption(silentOptionName, "Write no output."), cmds.BoolOption(progressOptionName, "p", "Stream progress data."), cmds.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."), cmds.BoolOption(onlyHashOptionName, "n", "Only chunk and hash - do not write to disk."), cmds.BoolOption(wrapOptionName, "w", "Wrap files with a directory object."), cmds.BoolOption(hiddenOptionName, "H", "Include files that are hidden. Only takes effect on recursive add."), cmds.StringOption(chunkerOptionName, "s", "Chunking algorithm to use."), cmds.BoolOption(pinOptionName, "Pin this object when adding.").Default(true), cmds.BoolOption(rawLeavesOptionName, "Use raw blocks for leaf nodes. (experimental)"), cmds.BoolOption(noCopyOptionName, "Add the file using filestore. (experimental)"), cmds.BoolOption(fstoreCacheOptionName, "Check the filestore for pre-existing blocks. (experimental)"), cmds.IntOption(cidVersionOptionName, "Cid version. Non-zero value will change default of 'raw-leaves' to true. (experimental)").Default(0), cmds.StringOption(hashOptionName, "Hash function to use. Will set Cid version to 1 if used. (experimental)").Default("sha2-256"), }, PreRun: func(req cmds.Request) error { quiet, _, _ := req.Option(quietOptionName).Bool() quieter, _, _ := req.Option(quieterOptionName).Bool() quiet = quiet || quieter silent, _, _ := req.Option(silentOptionName).Bool() if quiet || silent { return nil } _, found, _ := req.Option(progressOptionName).Bool() if !found { req.SetOption(progressOptionName, true) } sizeFile, ok := req.Files().(files.SizeFile) if !ok { log.Warning("cannot determine size of input file") return nil } sizeCh := make(chan int64, 1) req.Values()["size"] = sizeCh go func() { size, err := sizeFile.Size() if err != nil { log.Warningf("error getting files size: %s", err) return } log.Debugf("Total size of file being added: %v\n", size) sizeCh <- size }() return nil }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } cfg, err := n.Repo.Config() if err != nil { res.SetError(err, cmds.ErrNormal) return } progress, _, _ := req.Option(progressOptionName).Bool() trickle, _, _ := req.Option(trickleOptionName).Bool() wrap, _, _ := req.Option(wrapOptionName).Bool() hash, _, _ := req.Option(onlyHashOptionName).Bool() hidden, _, _ := req.Option(hiddenOptionName).Bool() silent, _, _ := req.Option(silentOptionName).Bool() chunker, _, _ := req.Option(chunkerOptionName).String() dopin, _, _ := req.Option(pinOptionName).Bool() rawblks, rbset, _ := req.Option(rawLeavesOptionName).Bool() nocopy, _, _ := req.Option(noCopyOptionName).Bool() fscache, _, _ := req.Option(fstoreCacheOptionName).Bool() cidVer, _, _ := req.Option(cidVersionOptionName).Int() hashFunStr, hfset, _ := req.Option(hashOptionName).String() if nocopy && !cfg.Experimental.FilestoreEnabled { res.SetError(errors.New("filestore is not enabled, see https://git.io/vy4XN"), cmds.ErrClient) return } if nocopy && !rbset { rawblks = true } if nocopy && !rawblks { res.SetError(fmt.Errorf("nocopy option requires '--raw-leaves' to be enabled as well"), cmds.ErrNormal) return } if hfset && cidVer == 0 { cidVer = 1 } if cidVer >= 1 && !rbset { rawblks = true } prefix, err := dag.PrefixForCidVersion(cidVer) if err != nil { res.SetError(err, cmds.ErrNormal) return } hashFunCode, ok := mh.Names[strings.ToLower(hashFunStr)] if !ok { res.SetError(fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr)), cmds.ErrNormal) return } prefix.MhType = hashFunCode prefix.MhLength = -1 if hash { nilnode, err := core.NewNode(n.Context(), &core.BuildCfg{ NilRepo: true, }) if err != nil { res.SetError(err, cmds.ErrNormal) return } n = nilnode } addblockstore := n.Blockstore if !(fscache || nocopy) { addblockstore = bstore.NewGCBlockstore(n.BaseBlocks, n.GCLocker) } exch := n.Exchange local, _, _ := req.Option("local").Bool() if local { exch = offline.Exchange(addblockstore) } bserv := blockservice.New(addblockstore, exch) dserv := dag.NewDAGService(bserv) fileAdder, err := coreunix.NewAdder(req.Context(), n.Pinning, n.Blockstore, dserv) if err != nil { res.SetError(err, cmds.ErrNormal) return } outChan := make(chan interface{}, adderOutChanSize) res.SetOutput((<-chan interface{})(outChan)) 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.Prefix = &prefix if hash { md := dagtest.Mock() mr, err := mfs.NewRoot(req.Context(), md, ft.EmptyDirNode(), nil) if err != nil { res.SetError(err, cmds.ErrNormal) return } fileAdder.SetMfsRoot(mr) } addAllAndPin := func(f files.File) error { for { file, err := f.NextFile() if err == io.EOF { break } else if err != nil { return err } if err := fileAdder.AddFile(file); err != nil { return err } } _, err := fileAdder.Finalize() if err != nil { return err } if hash { return nil } return fileAdder.PinRoot() } go func() { defer close(outChan) if err := addAllAndPin(req.Files()); err != nil { res.SetError(err, cmds.ErrNormal) return } }() }, PostRun: func(req cmds.Request, res cmds.Response) { if res.Error() != nil { return } outChan, ok := res.Output().(<-chan interface{}) if !ok { res.SetError(u.ErrCast(), cmds.ErrNormal) return } res.SetOutput(nil) quiet, _, _ := req.Option(quietOptionName).Bool() quieter, _, _ := req.Option(quieterOptionName).Bool() quiet = quiet || quieter progress, _, _ := req.Option(progressOptionName).Bool() var bar *pb.ProgressBar if progress { bar = pb.New64(0).SetUnits(pb.U_BYTES) bar.ManualUpdate = true bar.ShowTimeLeft = false bar.ShowPercent = false bar.Output = res.Stderr() bar.Start() } var sizeChan chan int64 s, found := req.Values()["size"] if found { sizeChan = s.(chan int64) } lastFile := "" lastHash := "" var totalProgress, prevFiles, lastBytes int64 LOOP: for { select { case out, ok := <-outChan: if !ok { if quieter { fmt.Fprintln(res.Stdout(), lastHash) } break LOOP } output := out.(*coreunix.AddedObject) if len(output.Hash) > 0 { lastHash = output.Hash if quieter { continue } if progress { fmt.Fprintf(res.Stderr(), "\033[2K\r") } if quiet { fmt.Fprintf(res.Stdout(), "%s\n", output.Hash) } else { fmt.Fprintf(res.Stdout(), "added %s %s\n", output.Hash, output.Name) } } else { log.Debugf("add progress: %v %v\n", output.Name, output.Bytes) if !progress { continue } if len(lastFile) == 0 { lastFile = output.Name } if output.Name != lastFile || output.Bytes < lastBytes { prevFiles += lastBytes lastFile = output.Name } lastBytes = output.Bytes delta := prevFiles + lastBytes - totalProgress totalProgress = bar.Add64(delta) } if progress { bar.Update() } case size := <-sizeChan: if progress { bar.Total = size bar.ShowPercent = true bar.ShowBar = true bar.ShowTimeLeft = true } case <-req.Context().Done(): res.SetError(req.Context().Err(), cmds.ErrNormal) return } } }, Type: coreunix.AddedObject{}, }
var BitswapCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Interact with the bitswap agent.", ShortDescription: ``, }, Subcommands: map[string]*cmds.Command{ "wantlist": showWantlistCmd, "stat": bitswapStatCmd, "unwant": unwantCmd, "ledger": ledgerCmd, "reprovide": reprovideCmd, }, }
var BlockCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Interact with raw IPFS blocks.", ShortDescription: ` 'ipfs block' is a plumbing command used to manipulate raw IPFS blocks. Reads from stdin or writes to stdout, and <key> is a base58 encoded multihash. `, }, Subcommands: map[string]*cmds.Command{ "stat": blockStatCmd, "get": blockGetCmd, "put": blockPutCmd, "rm": blockRmCmd, }, }
var BootstrapCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show or edit the list of bootstrap peers.", ShortDescription: ` Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'. ` + bootstrapSecurityWarning, }, Run: bootstrapListCmd.Run, Marshalers: bootstrapListCmd.Marshalers, Type: bootstrapListCmd.Type, Subcommands: map[string]*cmds.Command{ "list": bootstrapListCmd, "add": bootstrapAddCmd, "rm": bootstrapRemoveCmd, }, }
var CatCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show IPFS object data.", ShortDescription: "Displays the data contained by an IPFS or IPNS object(s) at the given path.", }, 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, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !node.OnlineMode() { if err := node.SetupOfflineRouting(); err != nil { res.SetError(err, cmds.ErrNormal) return } } readers, length, err := cat(req.Context(), node, req.Arguments()) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetLength(length) reader := io.MultiReader(readers...) res.SetOutput(reader) }, PostRun: func(req cmds.Request, res cmds.Response) { if res.Length() < progressBarMinSize { return } bar, reader := progressBarForReader(res.Stderr(), res.Output().(io.Reader), int64(res.Length())) bar.Start() res.SetOutput(reader) }, }
var CommandsDaemonCmd = CommandsCmd(Root)
commandsDaemonCmd is the "ipfs commands" command for daemon
var CommandsDaemonROCmd = CommandsCmd(RootRO)
var ConfigCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Get and set ipfs config values.", ShortDescription: ` 'ipfs config' controls configuration variables. It works like 'git config'. The configuration values are stored in a config file inside your ipfs repository.`, LongDescription: ` 'ipfs config' controls configuration variables. It works much like 'git config'. The configuration values are stored in a config file inside your IPFS repository. Examples: Get the value of the 'Datastore.Path' key: $ ipfs config Datastore.Path Set the value of the 'Datastore.Path' key: $ ipfs config Datastore.Path ~/.ipfs/datastore `, }, Arguments: []cmds.Argument{ 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."), }, Options: []cmds.Option{ cmds.BoolOption("bool", "Set a boolean value.").Default(false), cmds.BoolOption("json", "Parse stringified JSON.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { args := req.Arguments() key := args[0] switch strings.ToLower(key) { case "identity", "identity.privkey": res.SetError(fmt.Errorf("cannot show or change private key through API"), cmds.ErrNormal) return default: } r, err := fsrepo.Open(req.InvocContext().ConfigRoot) if err != nil { res.SetError(err, cmds.ErrNormal) return } defer r.Close() var output *ConfigField if len(args) == 2 { value := args[1] if parseJson, _, _ := req.Option("json").Bool(); parseJson { var jsonVal interface{} if err := json.Unmarshal([]byte(value), &jsonVal); err != nil { err = fmt.Errorf("failed to unmarshal json. %s", err) res.SetError(err, cmds.ErrNormal) return } output, err = setConfig(r, key, jsonVal) } else if isbool, _, _ := req.Option("bool").Bool(); isbool { output, err = setConfig(r, key, value == "true") } else { output, err = setConfig(r, key, value) } } else { output, err = getConfig(r, 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) { if len(res.Request().Arguments()) == 2 { return nil, nil } v := res.Output() if v == nil { k := res.Request().Arguments()[0] return nil, fmt.Errorf("config does not contain key: %s", k) } vf, ok := v.(*ConfigField) if !ok { return nil, u.ErrCast() } buf, err := config.HumanOutput(vf.Value) if err != nil { return nil, err } buf = append(buf, byte('\n')) return bytes.NewReader(buf), nil }, }, Type: ConfigField{}, Subcommands: map[string]*cmds.Command{ "show": configShowCmd, "edit": configEditCmd, "replace": configReplaceCmd, }, }
var DNSCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Resolve DNS links.", ShortDescription: ` Multihashes are hard to remember, but domain names are usually easy to remember. To create memorable aliases for multihashes, DNS TXT records can point to other DNS links, IPFS objects, IPNS keys, etc. This command resolves those links to the referenced object. `, LongDescription: ` Multihashes are hard to remember, but domain names are usually easy to remember. To create memorable aliases for multihashes, DNS TXT records can point to other DNS links, IPFS objects, IPNS keys, etc. This command resolves those links to the referenced object. For example, with this DNS TXT record: > dig +short TXT _dnslink.ipfs.io dnslink=/ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy The resolver will give: > ipfs dns ipfs.io /ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy The resolver can recursively resolve: > dig +short TXT recursive.ipfs.io dnslink=/ipns/ipfs.io > ipfs dns -r recursive.ipfs.io /ipfs/QmRzTuh2Lpuz7Gr39stNr6mTFdqAghsZec1JoUnfySUzcy `, }, Arguments: []cmds.Argument{ cmds.StringArg("domain-name", true, false, "The domain-name name to resolve.").EnableStdin(), }, Options: []cmds.Option{ cmds.BoolOption("recursive", "r", "Resolve until the result is not a DNS link.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { recursive, _, _ := req.Option("recursive").Bool() name := req.Arguments()[0] resolver := namesys.NewDNSResolver() depth := 1 if recursive { depth = namesys.DefaultDepthLimit } output, err := resolver.ResolveN(req.Context(), name, depth) if err == namesys.ErrResolveFailed { res.SetError(err, cmds.ErrNotFound) return } if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(&ResolvedPath{output}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { output, ok := res.Output().(*ResolvedPath) if !ok { return nil, util.ErrCast() } return strings.NewReader(output.Path.String() + "\n"), nil }, }, Type: ResolvedPath{}, }
var DhtCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Issue commands directly through the DHT.", ShortDescription: ``, }, Subcommands: map[string]*cmds.Command{ "query": queryDhtCmd, "findprovs": findProvidersDhtCmd, "findpeer": findPeerDhtCmd, "get": getValueDhtCmd, "put": putValueDhtCmd, "provide": provideRefDhtCmd, }, }
var DiagCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Generate diagnostic reports.", }, Subcommands: map[string]*cmds.Command{ "sys": sysDiagCmd, "cmds": ActiveReqsCmd, }, }
var ErrDepthLimitExceeded = fmt.Errorf("depth limit exceeded")
Error indicating the max depth has been exceded.
var ErrInvalidCompressionLevel = errors.New("Compression level must be between 1 and 9")
var ErrNotDHT = errors.New("routing service is not a DHT")
var FileStoreCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Interact with filestore objects.", }, Subcommands: map[string]*cmds.Command{ "ls": lsFileStore, "verify": verifyFileStore, "dups": dupsFileStore, }, }
var GetCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Download IPFS objects.", ShortDescription: ` Stores to disk the data contained an IPFS or IPNS object(s) at the given path. By default, the output will be stored at './<ipfs-path>', but an alternate path can be specified with '--output=<path>' or '-o=<path>'. To output a TAR archive instead of unpacked files, use '--archive' or '-a'. To compress the output with GZIP compression, use '--compress' or '-C'. You may also specify the level of compression by specifying '-l=<1-9>'. `, }, Arguments: []cmds.Argument{ cmds.StringArg("ipfs-path", true, false, "The path to the IPFS object(s) to be outputted.").EnableStdin(), }, Options: []cmds.Option{ cmds.StringOption("output", "o", "The path where the output should be stored."), cmds.BoolOption("archive", "a", "Output a TAR archive.").Default(false), cmds.BoolOption("compress", "C", "Compress the output with GZIP compression.").Default(false), cmds.IntOption("compression-level", "l", "The level of compression (1-9).").Default(-1), }, PreRun: func(req cmds.Request) error { _, err := getCompressOptions(req) return err }, Run: func(req cmds.Request, res cmds.Response) { if len(req.Arguments()) == 0 { res.SetError(errors.New("not enough arugments provided"), cmds.ErrClient) return } cmplvl, err := getCompressOptions(req) if err != nil { res.SetError(err, cmds.ErrClient) return } node, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } p := path.Path(req.Arguments()[0]) ctx := req.Context() dn, err := core.Resolve(ctx, node.Namesys, node.Resolver, p) if err != nil { res.SetError(err, cmds.ErrNormal) return } switch dn := dn.(type) { case *dag.ProtoNode: size, err := dn.Size() if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetLength(size) case *dag.RawNode: res.SetLength(uint64(len(dn.RawData()))) default: res.SetError(fmt.Errorf("'ipfs get' only supports unixfs nodes"), cmds.ErrNormal) return } archive, _, _ := req.Option("archive").Bool() reader, err := uarchive.DagArchive(ctx, dn, p.String(), node.DAG, archive, cmplvl) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(reader) }, PostRun: func(req cmds.Request, res cmds.Response) { if res.Output() == nil { return } outReader := res.Output().(io.Reader) res.SetOutput(nil) outPath, _, _ := req.Option("output").String() if len(outPath) == 0 { _, outPath = gopath.Split(req.Arguments()[0]) outPath = gopath.Clean(outPath) } cmplvl, err := getCompressOptions(req) if err != nil { res.SetError(err, cmds.ErrClient) return } archive, _, _ := req.Option("archive").Bool() gw := getWriter{ Out: os.Stdout, Err: os.Stderr, Archive: archive, Compression: cmplvl, Size: int64(res.Length()), } if err := gw.Write(outReader, outPath); err != nil { res.SetError(err, cmds.ErrNormal) return } }, }
var IDCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show ipfs node id info.", ShortDescription: ` Prints out information about the specified peer. If no peer is specified, prints out information for local peers. 'ipfs id' supports the format option for output with the following keys: <id> : The peers id. <aver>: Agent version. <pver>: Protocol version. <pubkey>: Public key. <addrs>: Addresses (newline delimited). EXAMPLE: ipfs id Qmece2RkXhsKe5CRooNisBTh4SK119KrXXGmoK6V3kb8aH -f="<addrs>\n" `, }, Arguments: []cmds.Argument{ cmds.StringArg("peerid", false, false, "Peer.ID of node to look up."), }, Options: []cmds.Option{ cmds.StringOption("format", "f", "Optional output format."), }, Run: func(req cmds.Request, res cmds.Response) { node, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } var id peer.ID if len(req.Arguments()) > 0 { id = peer.ID(b58.Decode(req.Arguments()[0])) if len(id) == 0 { res.SetError(cmds.ClientError("Invalid peer id"), cmds.ErrClient) return } } else { id = node.Identity } if id == node.Identity { output, err := printSelf(node) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(output) return } if !node.OnlineMode() { res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) return } p, err := node.Routing.FindPeer(req.Context(), id) if err == kb.ErrLookupFailure { res.SetError(errors.New(offlineIdErrorMessage), cmds.ErrClient) return } if err != nil { res.SetError(err, cmds.ErrNormal) return } 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) { val, ok := res.Output().(*IdOutput) if !ok { return nil, u.ErrCast() } format, found, err := res.Request().Option("format").String() if err != nil { return nil, err } if found { output := format output = strings.Replace(output, "<id>", val.ID, -1) output = strings.Replace(output, "<aver>", val.AgentVersion, -1) output = strings.Replace(output, "<pver>", val.ProtocolVersion, -1) output = strings.Replace(output, "<pubkey>", val.PublicKey, -1) output = strings.Replace(output, "<addrs>", strings.Join(val.Addresses, "\n"), -1) output = strings.Replace(output, "\\n", "\n", -1) output = strings.Replace(output, "\\t", "\t", -1) return strings.NewReader(output), nil } else { marshaled, err := json.MarshalIndent(val, "", "\t") if err != nil { return nil, err } marshaled = append(marshaled, byte('\n')) return bytes.NewReader(marshaled), nil } }, }, Type: IdOutput{}, }
var IpnsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Resolve IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. `, LongDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. You can use the 'ipfs key' commands to list and generate more names and their respective keys. Examples: Resolve the value of your name: > ipfs name resolve /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Resolve the value of another name: > ipfs name resolve QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ /ipfs/QmSiTko9JZyabH56y2fussEt1A5oDqsFXB3CkvAqraFryz Resolve the value of a dnslink: > ipfs name resolve ipfs.io /ipfs/QmaBvfZooxWkrv7D3r8LS9moNjzD2o525XMZze69hhoxf5 `, }, Arguments: []cmds.Argument{ cmds.StringArg("name", false, false, "The IPNS name to resolve. Defaults to your node's peerID."), }, Options: []cmds.Option{ cmds.BoolOption("recursive", "r", "Resolve until the result is not an IPNS name.").Default(false), cmds.BoolOption("nocache", "n", "Do not use cached entries.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { res.SetError(err, cmds.ErrNormal) return } } nocache, _, _ := req.Option("nocache").Bool() local, _, _ := req.Option("local").Bool() // default to nodes namesys resolver var resolver namesys.Resolver = n.Namesys if local && nocache { res.SetError(errors.New("cannot specify both local and nocache"), cmds.ErrNormal) return } if local { offroute := offline.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey) resolver = namesys.NewRoutingResolver(offroute, 0) } if nocache { resolver = namesys.NewNameSystem(n.Routing, n.Repo.Datastore(), 0) } var name string if len(req.Arguments()) == 0 { if n.Identity == "" { res.SetError(errors.New("identity not loaded"), cmds.ErrNormal) return } name = n.Identity.Pretty() } else { name = req.Arguments()[0] } recursive, _, _ := req.Option("recursive").Bool() depth := 1 if recursive { depth = namesys.DefaultDepthLimit } if !strings.HasPrefix(name, "/ipns/") { name = "/ipns/" + name } output, err := resolver.ResolveN(req.Context(), name, depth) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(&ResolvedPath{output}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { output, ok := res.Output().(*ResolvedPath) if !ok { return nil, u.ErrCast() } return strings.NewReader(output.Path.String() + "\n"), nil }, }, Type: ResolvedPath{}, }
var KeyCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Create and list IPNS name keypairs", ShortDescription: ` 'ipfs key gen' generates a new keypair for usage with IPNS and 'ipfs name publish'. > ipfs key gen --type=rsa --size=2048 mykey > ipfs name publish --key=mykey QmSomeHash 'ipfs key list' lists the available keys. > ipfs key list self mykey `, }, Subcommands: map[string]*cmds.Command{ "gen": keyGenCmd, "list": keyListCmd, "rename": keyRenameCmd, "rm": keyRmCmd, }, }
var LogCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Interact with the daemon log output.", ShortDescription: ` 'ipfs log' contains utility commands to affect or read the logging output of a running daemon. `, }, Subcommands: map[string]*cmds.Command{ "level": logLevelCmd, "ls": logLsCmd, "tail": logTailCmd, }, }
var LsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List directory contents for Unix filesystem objects.", ShortDescription: ` Displays the contents of an IPFS or IPNS object(s) at the given path, with the following format: <link base58 hash> <link size in bytes> <link name> The JSON output contains type information. `, }, Arguments: []cmds.Argument{ cmds.StringArg("ipfs-path", true, true, "The path to the IPFS object(s) to list links from.").EnableStdin(), }, Options: []cmds.Option{ cmds.BoolOption("headers", "v", "Print table headers (Hash, Size, Name).").Default(false), cmds.BoolOption("resolve-type", "Resolve linked objects to find out their types.").Default(true), }, Run: func(req cmds.Request, res cmds.Response) { nd, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if _, _, err := req.Option("headers").Bool(); err != nil { res.SetError(err, cmds.ErrNormal) return } resolve, _, err := req.Option("resolve-type").Bool() if err != nil { res.SetError(err, cmds.ErrNormal) return } dserv := nd.DAG if !resolve { offlineexch := offline.Exchange(nd.Blockstore) bserv := blockservice.New(nd.Blockstore, offlineexch) dserv = merkledag.NewDAGService(bserv) } paths := req.Arguments() var dagnodes []node.Node for _, fpath := range paths { p, err := path.ParsePath(fpath) if err != nil { res.SetError(err, cmds.ErrNormal) return } r := &path.Resolver{ DAG: nd.DAG, ResolveOnce: uio.ResolveUnixfsOnce, } dagnode, err := core.Resolve(req.Context(), nd.Namesys, r, p) if err != nil { res.SetError(err, cmds.ErrNormal) return } dagnodes = append(dagnodes, dagnode) } output := make([]LsObject, len(req.Arguments())) for i, dagnode := range dagnodes { dir, err := uio.NewDirectoryFromNode(nd.DAG, dagnode) if err != nil && err != uio.ErrNotADir { res.SetError(err, cmds.ErrNormal) return } var links []*node.Link if dir == nil { links = dagnode.Links() } else { links, err = dir.Links(req.Context()) if err != nil { res.SetError(err, cmds.ErrNormal) return } } output[i] = LsObject{ Hash: paths[i], Links: make([]LsLink, len(links)), } for j, link := range links { t := unixfspb.Data_DataType(-1) linkNode, err := link.GetNode(req.Context(), dserv) if err == merkledag.ErrNotFound && !resolve { linkNode = nil } else if err != nil { res.SetError(err, cmds.ErrNormal) return } if pn, ok := linkNode.(*merkledag.ProtoNode); ok { d, err := unixfs.FromBytes(pn.Data()) if err != nil { res.SetError(err, cmds.ErrNormal) return } t = d.GetType() } output[i].Links[j] = LsLink{ Name: link.Name, Hash: link.Cid.String(), Size: link.Size, Type: t, } } } res.SetOutput(&LsOutput{output}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { headers, _, _ := res.Request().Option("headers").Bool() output := res.Output().(*LsOutput) buf := new(bytes.Buffer) w := tabwriter.NewWriter(buf, 1, 2, 1, ' ', 0) for _, object := range output.Objects { if len(output.Objects) > 1 { fmt.Fprintf(w, "%s:\n", object.Hash) } if headers { fmt.Fprintln(w, "Hash\tSize\tName") } for _, link := range object.Links { if link.Type == unixfspb.Data_Directory { link.Name += "/" } fmt.Fprintf(w, "%s\t%v\t%s\n", link.Hash, link.Size, link.Name) } if len(output.Objects) > 1 { fmt.Fprintln(w) } } w.Flush() return buf, nil }, }, Type: LsOutput{}, }
var MountCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Mounts IPFS to the filesystem (read-only).", ShortDescription: ` Mount IPFS at a read-only mountpoint on the OS (default: /ipfs and /ipns). All IPFS objects will be accessible under that directory. Note that the root will not be listable, as it is virtual. Access known paths directly. You may have to create /ipfs and /ipns before using 'ipfs mount': > sudo mkdir /ipfs /ipns > sudo chown ` + "`" + `whoami` + "`" + ` /ipfs /ipns > ipfs daemon & > ipfs mount `, LongDescription: ` Mount IPFS at a read-only mountpoint on the OS. The default, /ipfs and /ipns, are set in the configutation file, but can be overriden by the options. All IPFS objects will be accessible under this directory. Note that the root will not be listable, as it is virtual. Access known paths directly. You may have to create /ipfs and /ipns before using 'ipfs mount': > sudo mkdir /ipfs /ipns > sudo chown ` + "`" + `whoami` + "`" + ` /ipfs /ipns > ipfs daemon & > ipfs mount Example: # setup > mkdir foo > echo "baz" > foo/bar > ipfs add -r foo added QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR foo/bar added QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC foo > ipfs ls QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR 12 bar > ipfs cat QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR baz # mount > ipfs daemon & > ipfs mount IPFS mounted at: /ipfs IPNS mounted at: /ipns > cd /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC > ls bar > cat bar baz > cat /ipfs/QmSh5e7S6fdcu75LAbXNZAFY2nGyZUJXyLCJDvn2zRkWyC/bar baz > cat /ipfs/QmWLdkp93sNxGRjnFHPaYg8tCQ35NBY3XPn6KiETd3Z4WR baz `, }, Options: []cmds.Option{ cmds.StringOption("ipfs-path", "f", "The path where IPFS should be mounted."), cmds.StringOption("ipns-path", "n", "The path where IPNS should be mounted."), }, Run: func(req cmds.Request, res cmds.Response) { cfg, err := req.InvocContext().GetConfig() if err != nil { res.SetError(err, cmds.ErrNormal) return } node, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if node.LocalMode() { res.SetError(errNotOnline, cmds.ErrClient) return } fsdir, found, err := req.Option("f").String() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !found { fsdir = cfg.Mounts.IPFS } nsdir, found, err := req.Option("n").String() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !found { nsdir = cfg.Mounts.IPNS } err = nodeMount.Mount(node, fsdir, nsdir) if err != nil { res.SetError(err, cmds.ErrNormal) return } var output config.Mounts output.IPFS = fsdir output.IPNS = nsdir res.SetOutput(&output) }, Type: config.Mounts{}, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { v := res.Output().(*config.Mounts) s := fmt.Sprintf("IPFS mounted at: %s\n", v.IPFS) s += fmt.Sprintf("IPNS mounted at: %s\n", v.IPNS) return strings.NewReader(s), nil }, }, }
var NameCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Publish and resolve IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. `, LongDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. You can use the 'ipfs key' commands to list and generate more names and their respective keys. Examples: Publish an <ipfs-path> with your default name: > ipfs name publish /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Publish an <ipfs-path> with another name, added by an 'ipfs key' command: > ipfs key gen --type=rsa --size=2048 mykey > ipfs name publish --key=mykey /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Resolve the value of your name: > ipfs name resolve /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Resolve the value of another name: > ipfs name resolve QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ /ipfs/QmSiTko9JZyabH56y2fussEt1A5oDqsFXB3CkvAqraFryz Resolve the value of a dnslink: > ipfs name resolve ipfs.io /ipfs/QmaBvfZooxWkrv7D3r8LS9moNjzD2o525XMZze69hhoxf5 `, }, Subcommands: map[string]*cmds.Command{ "publish": PublishCmd, "resolve": IpnsCmd, }, }
var P2PCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Libp2p stream mounting.", ShortDescription: ` Create and use tunnels to remote peers over libp2p Note: this command is experimental and subject to change as usecases and APIs are refined`, }, Subcommands: map[string]*cmds.Command{ "listener": p2pListenerCmd, "stream": p2pStreamCmd, }, }
P2PCmd is the 'ipfs p2p' command
var PinCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Pin (and unpin) objects to local storage.", }, Subcommands: map[string]*cmds.Command{ "add": addPinCmd, "rm": rmPinCmd, "ls": listPinCmd, "verify": verifyPinCmd, "update": updatePinCmd, }, }
var PingCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Send echo request packets to IPFS hosts.", ShortDescription: ` 'ipfs ping' is a tool to test sending data to other nodes. It finds nodes via the routing system, sends pings, waits for pongs, and prints out round- trip latency information. `, }, Arguments: []cmds.Argument{ cmds.StringArg("peer ID", true, true, "ID of peer to be pinged.").EnableStdin(), }, Options: []cmds.Option{ cmds.IntOption("count", "n", "Number of ping messages to send.").Default(10), }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { outChan, ok := res.Output().(<-chan interface{}) if !ok { fmt.Println(reflect.TypeOf(res.Output())) return nil, u.ErrCast() } marshal := func(v interface{}) (io.Reader, error) { obj, ok := v.(*PingResult) if !ok { return nil, u.ErrCast() } buf := new(bytes.Buffer) if len(obj.Text) > 0 { buf = bytes.NewBufferString(obj.Text + "\n") } else if obj.Success { fmt.Fprintf(buf, "Pong received: time=%.2f ms\n", obj.Time.Seconds()*1000) } else { fmt.Fprintf(buf, "Pong failed\n") } return buf, nil } return &cmds.ChannelMarshaler{ Channel: outChan, Marshaler: marshal, Res: res, }, nil }, }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { res.SetError(errNotOnline, cmds.ErrClient) return } addr, peerID, err := ParsePeerParam(req.Arguments()[0]) if err != nil { res.SetError(err, cmds.ErrNormal) return } if addr != nil { n.Peerstore.AddAddr(peerID, addr, pstore.TempAddrTTL) } numPings, _, err := req.Option("count").Int() if err != nil { res.SetError(err, cmds.ErrNormal) return } outChan := pingPeer(ctx, n, peerID, numPings) res.SetOutput(outChan) }, Type: PingResult{}, }
var PublishCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Publish IPNS names.", ShortDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. `, LongDescription: ` IPNS is a PKI namespace, where names are the hashes of public keys, and the private key enables publishing new (signed) values. In both publish and resolve, the default name used is the node's own PeerID, which is the hash of its public key. You can use the 'ipfs key' commands to list and generate more names and their respective keys. Examples: Publish an <ipfs-path> with your default name: > ipfs name publish /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Publish an <ipfs-path> with another name, added by an 'ipfs key' command: > ipfs key gen --type=rsa --size=2048 mykey > ipfs name publish --key=mykey /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Alternatively, publish an <ipfs-path> using a valid PeerID(as listed by 'ipfs key list -l'): > ipfs name publish --key=QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Published to QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n: /ipfs/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy `, }, Arguments: []cmds.Argument{ cmds.StringArg("ipfs-path", true, false, "ipfs path of the object to be published.").EnableStdin(), }, Options: []cmds.Option{ cmds.BoolOption("resolve", "Resolve given path before publishing.").Default(true), cmds.StringOption("lifetime", "t", `Time duration that the record will be valid for. <<default>> This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`).Default("24h"), cmds.StringOption("ttl", "Time duration this record should be cached for (caution: experimental)."), cmds.StringOption("key", "k", "Name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'. Default: <<default>>.").Default("self"), }, Run: func(req cmds.Request, res cmds.Response) { log.Debug("begin publish") n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { res.SetError(err, cmds.ErrNormal) return } } if n.Mounts.Ipns != nil && n.Mounts.Ipns.IsActive() { res.SetError(errors.New("cannot manually publish while IPNS is mounted"), cmds.ErrNormal) return } pstr := req.Arguments()[0] if n.Identity == "" { res.SetError(errors.New("identity not loaded"), cmds.ErrNormal) return } popts := new(publishOpts) popts.verifyExists, _, _ = req.Option("resolve").Bool() validtime, _, _ := req.Option("lifetime").String() d, err := time.ParseDuration(validtime) if err != nil { res.SetError(fmt.Errorf("error parsing lifetime option: %s", err), cmds.ErrNormal) return } popts.pubValidTime = d ctx := req.Context() if ttl, found, _ := req.Option("ttl").String(); found { d, err := time.ParseDuration(ttl) if err != nil { res.SetError(err, cmds.ErrNormal) return } ctx = context.WithValue(ctx, "ipns-publish-ttl", d) } kname, _, _ := req.Option("key").String() k, err := keylookup(n, kname) if err != nil { res.SetError(err, cmds.ErrNormal) return } pth, err := path.ParsePath(pstr) if err != nil { res.SetError(err, cmds.ErrNormal) return } output, err := publish(ctx, n, k, pth, popts) if err != nil { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(output) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { v := res.Output().(*IpnsEntry) s := fmt.Sprintf("Published to %s: %s\n", v.Name, v.Value) return strings.NewReader(s), nil }, }, Type: IpnsEntry{}, }
var PubsubCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "An experimental publish-subscribe system on ipfs.", ShortDescription: ` ipfs pubsub allows you to publish messages to a given topic, and also to subscribe to new messages on a given topic. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, Subcommands: map[string]*cmds.Command{ "pub": PubsubPubCmd, "sub": PubsubSubCmd, "ls": PubsubLsCmd, "peers": PubsubPeersCmd, }, }
var PubsubLsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List subscribed topics by name.", ShortDescription: ` ipfs pubsub ls lists out the names of topics you are currently subscribed to. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { res.SetError(errNotOnline, cmds.ErrClient) return } if n.Floodsub == nil { res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) return } res.SetOutput(&stringList{n.Floodsub.GetTopics()}) }, Type: stringList{}, Marshalers: cmds.MarshalerMap{ cmds.Text: stringListMarshaler, }, }
var PubsubPeersCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List peers we are currently pubsubbing with.", ShortDescription: ` ipfs pubsub peers with no arguments lists out the pubsub peers you are currently connected to. If given a topic, it will list connected peers who are subscribed to the named topic. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, Arguments: []cmds.Argument{ cmds.StringArg("topic", false, false, "topic to list connected peers of"), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { res.SetError(errNotOnline, cmds.ErrClient) return } if n.Floodsub == nil { res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) return } var topic string if len(req.Arguments()) == 1 { topic = req.Arguments()[0] } var out []string for _, p := range n.Floodsub.ListPeers(topic) { out = append(out, p.Pretty()) } res.SetOutput(&stringList{out}) }, Type: stringList{}, Marshalers: cmds.MarshalerMap{ cmds.Text: stringListMarshaler, }, }
var PubsubPubCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Publish a message to a given pubsub topic.", ShortDescription: ` ipfs pubsub pub publishes a message to a specified topic. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, }, Arguments: []cmds.Argument{ cmds.StringArg("topic", true, false, "Topic to publish to."), cmds.StringArg("data", true, true, "Payload of message to publish.").EnableStdin(), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { res.SetError(errNotOnline, cmds.ErrClient) return } if n.Floodsub == nil { res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) return } topic := req.Arguments()[0] for _, data := range req.Arguments()[1:] { if err := n.Floodsub.Publish(topic, []byte(data)); err != nil { res.SetError(err, cmds.ErrNormal) return } } }, }
var PubsubSubCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Subscribe to messages on a given topic.", ShortDescription: ` ipfs pubsub sub subscribes to messages on a given topic. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. `, LongDescription: ` ipfs pubsub sub subscribes to messages on a given topic. This is an experimental feature. It is not intended in its current state to be used in a production environment. To use, the daemon must be run with '--enable-pubsub-experiment'. This command outputs data in the following encodings: * "json" (Specified by the "--encoding" or "--enc" flag) `, }, Arguments: []cmds.Argument{ cmds.StringArg("topic", true, false, "String name of topic to subscribe to."), }, Options: []cmds.Option{ cmds.BoolOption("discover", "try to discover other peers subscribed to the same topic"), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { res.SetError(errNotOnline, cmds.ErrClient) return } if n.Floodsub == nil { res.SetError(fmt.Errorf("experimental pubsub feature not enabled. Run daemon with --enable-pubsub-experiment to use."), cmds.ErrNormal) return } topic := req.Arguments()[0] sub, err := n.Floodsub.Subscribe(topic) if err != nil { res.SetError(err, cmds.ErrNormal) return } out := make(chan interface{}) res.SetOutput((<-chan interface{})(out)) go func() { defer sub.Cancel() defer close(out) out <- floodsub.Message{} for { msg, err := sub.Next(req.Context()) if err == io.EOF || err == context.Canceled { return } else if err != nil { res.SetError(err, cmds.ErrNormal) return } out <- msg } }() discover, _, _ := req.Option("discover").Bool() if discover { go func() { blk := blocks.NewBlock([]byte("floodsub:" + topic)) cid, err := n.Blocks.AddBlock(blk) if err != nil { log.Error("pubsub discovery: ", err) return } connectToPubSubPeers(req.Context(), n, cid) }() } }, Marshalers: cmds.MarshalerMap{ cmds.Text: getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { return bytes.NewReader(m.Data), nil }), "ndpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { m.Data = append(m.Data, '\n') return bytes.NewReader(m.Data), nil }), "lenpayload": getPsMsgMarshaler(func(m *floodsub.Message) (io.Reader, error) { buf := make([]byte, 8) n := binary.PutUvarint(buf, uint64(len(m.Data))) return io.MultiReader(bytes.NewReader(buf[:n]), bytes.NewReader(m.Data)), nil }), }, Type: floodsub.Message{}, }
var RefsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List links (references) from an object.", ShortDescription: ` Lists the hashes of all the links an IPFS or IPNS object(s) contains, with the following format: <link base58 hash> NOTE: List all references recursively by using the flag '-r'. `, }, Subcommands: map[string]*cmds.Command{ "local": RefsLocalCmd, }, Arguments: []cmds.Argument{ cmds.StringArg("ipfs-path", true, true, "Path to the object(s) to list refs from.").EnableStdin(), }, Options: []cmds.Option{ cmds.StringOption("format", "Emit edges with given format. Available tokens: <src> <dst> <linkname>.").Default("<dst>"), cmds.BoolOption("edges", "e", "Emit edge format: `<from> -> <to>`.").Default(false), cmds.BoolOption("unique", "u", "Omit duplicate refs from output.").Default(false), cmds.BoolOption("recursive", "r", "Recursively list links of child nodes.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } unique, _, err := req.Option("unique").Bool() if err != nil { res.SetError(err, cmds.ErrNormal) return } recursive, _, err := req.Option("recursive").Bool() if err != nil { res.SetError(err, cmds.ErrNormal) return } format, _, err := req.Option("format").String() if err != nil { res.SetError(err, cmds.ErrNormal) return } edges, _, err := req.Option("edges").Bool() if err != nil { res.SetError(err, cmds.ErrNormal) return } if edges { if format != "<dst>" { res.SetError(errors.New("using format arguement with edges is not allowed"), cmds.ErrClient) return } format = "<src> -> <dst>" } objs, err := objectsForPaths(ctx, n, req.Arguments()) if err != nil { res.SetError(err, cmds.ErrNormal) return } out := make(chan interface{}) res.SetOutput((<-chan interface{})(out)) go func() { defer close(out) rw := RefWriter{ out: out, DAG: n.DAG, Ctx: ctx, Unique: unique, PrintFmt: format, Recursive: recursive, } for _, o := range objs { if _, err := rw.WriteRefs(o); err != nil { out <- &RefWrapper{Err: err.Error()} return } } }() }, Marshalers: refsMarshallerMap, Type: RefWrapper{}, }
var RefsLocalCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "List all local references.", ShortDescription: ` Displays the hashes of all local objects. `, }, Run: func(req cmds.Request, res cmds.Response) { ctx := req.Context() n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } allKeys, err := n.Blockstore.AllKeysChan(ctx) if err != nil { res.SetError(err, cmds.ErrNormal) return } out := make(chan interface{}) res.SetOutput((<-chan interface{})(out)) go func() { defer close(out) for k := range allKeys { out <- &RefWrapper{Ref: k.String()} } }() }, Marshalers: refsMarshallerMap, Type: RefWrapper{}, }
var RefsROCmd = &cmds.Command{}
var RepoCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Manipulate the IPFS repo.", ShortDescription: ` 'ipfs repo' is a plumbing command used to manipulate the repo. `, }, Subcommands: map[string]*cmds.Command{ "gc": repoGcCmd, "stat": repoStatCmd, "fsck": RepoFsckCmd, "version": repoVersionCmd, "verify": repoVerifyCmd, }, }
var RepoFsckCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Remove repo lockfiles.", ShortDescription: ` 'ipfs repo fsck' is a plumbing command that will remove repo and level db lockfiles, as well as the api file. This command can only run when no ipfs daemons are running. `, }, Run: func(req cmds.Request, res cmds.Response) { configRoot := req.InvocContext().ConfigRoot dsPath, err := config.DataStorePath(configRoot) if err != nil { res.SetError(err, cmds.ErrNormal) return } dsLockFile := filepath.Join(dsPath, "LOCK") repoLockFile := filepath.Join(configRoot, lockfile.LockFile) apiFile := filepath.Join(configRoot, "api") log.Infof("Removing repo lockfile: %s", repoLockFile) log.Infof("Removing datastore lockfile: %s", dsLockFile) log.Infof("Removing api file: %s", apiFile) err = os.Remove(repoLockFile) if err != nil && !os.IsNotExist(err) { res.SetError(err, cmds.ErrNormal) return } err = os.Remove(dsLockFile) if err != nil && !os.IsNotExist(err) { res.SetError(err, cmds.ErrNormal) return } err = os.Remove(apiFile) if err != nil && !os.IsNotExist(err) { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(&MessageOutput{"Lockfiles have been removed.\n"}) }, Type: MessageOutput{}, Marshalers: cmds.MarshalerMap{ cmds.Text: MessageTextMarshaler, }, }
var ResolveCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Resolve the value of names to IPFS.", ShortDescription: ` There are a number of mutable name protocols that can link among themselves and into IPNS. This command accepts any of these identifiers and resolves them to the referenced item. `, LongDescription: ` There are a number of mutable name protocols that can link among themselves and into IPNS. For example IPNS references can (currently) point at an IPFS object, and DNS links can point at other DNS links, IPNS entries, or IPFS objects. This command accepts any of these identifiers and resolves them to the referenced item. EXAMPLES Resolve the value of your identity: $ ipfs resolve /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj Resolve the value of another name: $ ipfs resolve /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy Resolve the value of another name recursively: $ ipfs resolve -r /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj Resolve the value of an IPFS DAG path: $ ipfs resolve /ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1 `, }, Arguments: []cmds.Argument{ cmds.StringArg("name", true, false, "The name to resolve.").EnableStdin(), }, Options: []cmds.Option{ cmds.BoolOption("recursive", "r", "Resolve until the result is an IPFS name.").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { n, err := req.InvocContext().GetNode() if err != nil { res.SetError(err, cmds.ErrNormal) return } if !n.OnlineMode() { err := n.SetupOfflineRouting() if err != nil { res.SetError(err, cmds.ErrNormal) return } } name := req.Arguments()[0] recursive, _, _ := req.Option("recursive").Bool() if strings.HasPrefix(name, "/ipns/") && !recursive { p, err := n.Namesys.ResolveN(req.Context(), name, 1) if err != nil && err != ns.ErrResolveRecursion { res.SetError(err, cmds.ErrNormal) return } res.SetOutput(&ResolvedPath{p}) return } p, err := path.ParsePath(name) if err != nil { res.SetError(err, cmds.ErrNormal) return } node, err := core.Resolve(req.Context(), n.Namesys, n.Resolver, p) if err != nil { res.SetError(err, cmds.ErrNormal) return } c := node.Cid() res.SetOutput(&ResolvedPath{path.FromCid(c)}) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { output, ok := res.Output().(*ResolvedPath) if !ok { return nil, u.ErrCast() } return strings.NewReader(output.Path.String() + "\n"), nil }, }, Type: ResolvedPath{}, }
var Root = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Global p2p merkle-dag filesystem.", Synopsis: "ipfs [--config=<config> | -c] [--debug=<debug> | -D] [--help=<help>] [-h=<h>] [--local=<local> | -L] [--api=<api>] <command> ...", Subcommands: ` BASIC COMMANDS init Initialize ipfs local configuration add <path> Add a file to IPFS cat <ref> Show IPFS object data get <ref> Download IPFS objects ls <ref> List links from an object refs <ref> List hashes of links from an object DATA STRUCTURE COMMANDS block Interact with raw blocks in the datastore object Interact with raw dag nodes files Interact with objects as if they were a unix filesystem dag Interact with IPLD documents (experimental) ADVANCED COMMANDS daemon Start a long-running daemon process mount Mount an IPFS read-only mountpoint resolve Resolve any type of name name Publish and resolve IPNS names key Create and list IPNS name keypairs dns Resolve DNS links pin Pin objects to local storage repo Manipulate the IPFS repository stats Various operational stats p2p Libp2p stream mounting filestore Manage the filestore (experimental) NETWORK COMMANDS id Show info about IPFS peers bootstrap Add or remove bootstrap peers swarm Manage connections to the p2p network dht Query the DHT for values or peers ping Measure the latency of a connection diag Print diagnostics TOOL COMMANDS config Manage configuration version Show ipfs version information update Download and apply go-ipfs updates commands List all available commands Use 'ipfs <command> --help' to learn more about each command. ipfs uses a repository in the local file system. By default, the repo is located at ~/.ipfs. To change the repo location, set the $IPFS_PATH environment variable: export IPFS_PATH=/path/to/ipfsrepo EXIT STATUS The CLI will exit with one of the following values: 0 Successful execution. 1 Failed executions. `, }, Options: []cmds.Option{ cmds.StringOption("config", "c", "Path to the configuration file to use."), cmds.BoolOption("debug", "D", "Operate in debug mode.").Default(false), cmds.BoolOption("help", "Show the full command help text.").Default(false), cmds.BoolOption("h", "Show a short version of the command help text.").Default(false), cmds.BoolOption("local", "L", "Run the command locally, instead of using the daemon.").Default(false), cmds.StringOption(ApiOption, "Use a specific API instance (defaults to /ip4/127.0.0.1/tcp/5001)"), }, }
var RootRO = &cmds.Command{}
RootRO is the readonly version of Root
var StatsCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Query IPFS statistics.", ShortDescription: `'ipfs stats' is a set of commands to help look at statistics for your IPFS node. `, LongDescription: `'ipfs stats' is a set of commands to help look at statistics for your IPFS node.`, }, Subcommands: map[string]*cmds.Command{ "bw": statBwCmd, "repo": repoStatCmd, "bitswap": bitswapStatCmd, }, }
var SwarmCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Interact with the swarm.", ShortDescription: ` 'ipfs swarm' is a tool to manipulate the network swarm. The swarm is the component that opens, listens for, and maintains connections to other ipfs peers in the internet. `, }, Subcommands: map[string]*cmds.Command{ "addrs": swarmAddrsCmd, "connect": swarmConnectCmd, "disconnect": swarmDisconnectCmd, "filters": swarmFiltersCmd, "peers": swarmPeersCmd, }, }
var TarCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Utility functions for tar files in ipfs.", }, Subcommands: map[string]*cmds.Command{ "add": tarAddCmd, "cat": tarCatCmd, }, }
var VersionCmd = &cmds.Command{ Helptext: cmds.HelpText{ Tagline: "Show ipfs version information.", ShortDescription: "Returns the current version of ipfs and exits.", }, Options: []cmds.Option{ cmds.BoolOption("number", "n", "Only show the version number.").Default(false), cmds.BoolOption("commit", "Show the commit hash.").Default(false), cmds.BoolOption("repo", "Show repo version.").Default(false), cmds.BoolOption("all", "Show all version information").Default(false), }, Run: func(req cmds.Request, res cmds.Response) { res.SetOutput(&VersionOutput{ Version: config.CurrentVersionNumber, Commit: config.CurrentCommit, Repo: fmt.Sprint(fsrepo.RepoVersion), System: runtime.GOARCH + "/" + runtime.GOOS, Golang: runtime.Version(), }) }, Marshalers: cmds.MarshalerMap{ cmds.Text: func(res cmds.Response) (io.Reader, error) { v := res.Output().(*VersionOutput) repo, _, err := res.Request().Option("repo").Bool() if err != nil { return nil, err } if repo { return strings.NewReader(v.Repo + "\n"), nil } commit, _, err := res.Request().Option("commit").Bool() commitTxt := "" if err != nil { return nil, err } if commit { commitTxt = "-" + v.Commit } number, _, err := res.Request().Option("number").Bool() if err != nil { return nil, err } if number { return strings.NewReader(fmt.Sprintln(v.Version + commitTxt)), nil } all, _, err := res.Request().Option("all").Bool() if err != nil { return nil, err } if all { out := fmt.Sprintf("go-ipfs version: %s-%s\n"+ "Repo version: %s\nSystem version: %s\nGolang version: %s\n", v.Version, v.Commit, v.Repo, v.System, v.Golang) return strings.NewReader(out), nil } return strings.NewReader(fmt.Sprintf("ipfs version %s%s\n", v.Version, commitTxt)), nil }, }, Type: VersionOutput{}, }
Functions ¶
func CommandsCmd ¶
CommandsCmd takes in a root command, and returns a command that lists the subcommands in that root
func ExternalBinary ¶ added in v0.3.10
func KeyListTextMarshaler ¶
KeyListTextMarshaler outputs a KeyList as plaintext, one key per line
Types ¶
type AddPinOutput ¶ added in v0.4.7
type BootstrapOutput ¶
type BootstrapOutput struct {
Peers []string
}
type ConfigField ¶
type ConfigField struct { Key string Value interface{} }
type KeyOutputList ¶ added in v0.4.5
type KeyOutputList struct {
Keys []KeyOutput
}
type KeyRenameOutput ¶ added in v0.4.10
KeyRenameOutput define the output type of keyRenameCmd
type LsLink ¶ added in v0.3.2
type LsLink struct {
Name, Hash string
Size uint64
Type unixfspb.Data_DataType
}
type MessageOutput ¶
type MessageOutput struct {
Message string
}
type P2PListenerInfoOutput ¶ added in v0.4.10
P2PListenerInfoOutput is output type of ls command
type P2PLsOutput ¶ added in v0.4.10
type P2PLsOutput struct {
Listeners []P2PListenerInfoOutput
}
P2PLsOutput is output type of ls command
type P2PStreamInfoOutput ¶ added in v0.4.10
type P2PStreamInfoOutput struct { HandlerID string Protocol string LocalPeer string LocalAddress string RemotePeer string RemoteAddress string }
P2PStreamInfoOutput is output type of streams command
type P2PStreamsOutput ¶ added in v0.4.10
type P2PStreamsOutput struct {
Streams []P2PStreamInfoOutput
}
P2PStreamsOutput is output type of streams command
type PinVerifyRes ¶ added in v0.4.10
PinVerifyRes is the result returned for each pin checked in "pin verify"
func (PinVerifyRes) Format ¶ added in v0.4.10
func (r PinVerifyRes) Format(out io.Writer)
Format formats PinVerifyRes
type RefKeyList ¶ added in v0.3.2
type RefKeyList struct {
Keys map[string]RefKeyObject
}
type RefKeyObject ¶ added in v0.3.4
type RefKeyObject struct {
Type string
}
type RefWrapper ¶ added in v0.3.5
type RefWriter ¶
type RefWriter struct { DAG dag.DAGService Ctx context.Context Unique bool Recursive bool PrintFmt string // contains filtered or unexported fields }
type RepoVersion ¶ added in v0.4.3
type RepoVersion struct {
Version string
}
type ResolvedPath ¶ added in v0.3.3
type VerifyProgress ¶ added in v0.4.3
Source Files ¶
- active.go
- add.go
- bitswap.go
- block.go
- bootstrap.go
- cat.go
- commands.go
- config.go
- dht.go
- diag.go
- dns.go
- external.go
- filestore.go
- get.go
- id.go
- ipns.go
- keystore.go
- log.go
- ls.go
- mount_unix.go
- name.go
- p2p.go
- pin.go
- ping.go
- publish.go
- pubsub.go
- refs.go
- repo.go
- resolve.go
- root.go
- shutdown.go
- stat.go
- swarm.go
- sysdiag.go
- tar.go
- version.go