cidbase.go 3.22 KB
Newer Older
1 2 3
package cmdenv

import (
4
	"fmt"
5
	"strings"
6

Jakub Sztandera's avatar
Jakub Sztandera committed
7
	mbase "github.com/multiformats/go-multibase"
tavit ohanian's avatar
tavit ohanian committed
8 9 10
	cid "gitlab.dms3.io/dms3/go-cid"
	cidenc "gitlab.dms3.io/dms3/go-cidutil/cidenc"
	cmds "gitlab.dms3.io/dms3/go-dms3-cmds"
11 12
)

Steven Allen's avatar
Steven Allen committed
13 14
var OptionCidBase = cmds.StringOption("cid-base", "Multibase encoding used for version 1 CIDs in output.")
var OptionUpgradeCidV0InOutput = cmds.BoolOption("upgrade-cidv0-in-output", "Upgrade version 0 to version 1 CIDs in output.")
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

// 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) {
30
	base, _ := req.Options[OptionCidBase.Name()].(string)
31
	upgrade, upgradeDefined := req.Options[OptionUpgradeCidV0InOutput.Name()].(bool)
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

	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
63 64 65 66 67 68 69 70 71
// multibase from the CID is used and upgrades are enabled.
//
// This logic is intentionally fuzzy and will match anything of the form
// `CidLike`, `CidLike/...`, or `/namespace/CidLike/...`.
//
// For example:
//
// * Qm...
// * Qm.../...
tavit ohanian's avatar
tavit ohanian committed
72 73
// * /dms3/Qm...
// * /dms3ns/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
74 75 76 77 78 79 80 81 82 83 84 85 86
// * /bzz/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
func CidEncoderFromPath(p string) (cidenc.Encoder, error) {
	components := strings.SplitN(p, "/", 4)

	var maybeCid string
	if components[0] != "" {
		// No leading slash, first component is likely CID-like.
		maybeCid = components[0]
	} else if len(components) < 3 {
		// Not enough components to include a CID.
		return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
	} else {
		maybeCid = components[2]
87
	}
88
	c, err := cid.Decode(maybeCid)
89
	if err != nil {
90 91
		// Ok, not a CID-like thing. Keep the current encoder.
		return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
92
	}
93 94 95
	if c.Version() == 0 {
		// Version 0, use the base58 non-upgrading encoder.
		return cidenc.Default(), nil
96 97
	}

98 99 100 101 102
	// Version 1+, extract multibase encoding.
	encoding, _, err := mbase.Decode(maybeCid)
	if err != nil {
		// This should be impossible, we've already decoded the cid.
		panic(fmt.Sprintf("BUG: failed to get multibase decoder for CID %s", maybeCid))
103
	}
104 105

	return cidenc.Encoder{Base: mbase.MustNewEncoder(encoding), Upgrade: true}, nil
106
}