cidbase.go 2.86 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
package cmdenv

import (
	"errors"

	path "gx/ipfs/QmNYPETsdAu2uQ1k9q9S1jYEGURaLHV6cbYRSVFVRftpF8/go-path"
	cmds "gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
	cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
	cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
	mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
)

var OptionCidBase = cmdkit.StringOption("cid-base", "Multibase encoding used for version 1 CIDs in output.")
var OptionOutputCidV1 = cmdkit.BoolOption("output-cidv1", "Upgrade CID version 0 to version 1 in output.")

// GetCidEncoder processes the `cid-base` and `output-cidv1` options and
// returns a encoder to use based on those parameters.
func GetCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
	return getCidBase(req, true)
}

// GetLowLevelCidEncoder is like GetCidEncoder but meant to be used by
// lower level commands.  It differs from GetCidEncoder in that CIDv0
// are not, by default, auto-upgraded to CIDv1.
func GetLowLevelCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
	return getCidBase(req, false)
}

func getCidBase(req *cmds.Request, autoUpgrade bool) (cidenc.Encoder, error) {
	base, _ := req.Options["cid-base"].(string)
	upgrade, upgradeDefined := req.Options["output-cidv1"].(bool)

	e := cidenc.Default()

	if base != "" {
		var err error
		e.Base, err = mbase.EncoderByName(base)
		if err != nil {
			return e, err
		}
		if autoUpgrade {
			e.Upgrade = true
		}
	}

	if upgradeDefined {
		e.Upgrade = upgrade
	}

	return e, nil
}

// CidBaseDefined returns true if the `cid-base` option is specified
// on the command line
func CidBaseDefined(req *cmds.Request) bool {
	base, _ := req.Options["cid-base"].(string)
	return base != ""
}

// CidEncoderFromPath creates a new encoder that is influenced from
// the encoded Cid in a Path.  For CidV0 the multibase from the base
// encoder is used and automatic upgrades are disabled.  For CidV1 the
// multibase from the CID is used and upgrades are eneabled.  On error
// the base encoder is returned.  If you don't care about the error
// condition, it is safe to ignore the error returned.
func CidEncoderFromPath(enc cidenc.Encoder, p string) (cidenc.Encoder, error) {
	v, err := extractCidString(p)
	if err != nil {
		return enc, err
	}
	if cidVer(v) == 0 {
		return cidenc.Encoder{Base: enc.Base, Upgrade: false}, nil
	}
	e, err := mbase.NewEncoder(mbase.Encoding(v[0]))
	if err != nil {
		return enc, err
	}
	return cidenc.Encoder{Base: e, Upgrade: true}, nil
}

func extractCidString(str string) (string, error) {
	p, err := path.ParsePath(str)
	if err != nil {
		return "", err
	}
	segs := p.Segments()
	if segs[0] == "ipfs" || segs[0] == "ipld" {
		return segs[1], nil
	}
	return "", errors.New("no CID found")
}

func cidVer(v string) int {
	if len(v) == 46 && v[:2] == "Qm" {
		return 0
	}
	return 1
}