urlstore.go 3.38 KB
Newer Older
Jakub Sztandera's avatar
Jakub Sztandera committed
1 2 3 4 5 6 7
package commands

import (
	"fmt"
	"io"
	"net/http"

8
	filestore "github.com/ipfs/go-ipfs/filestore"
9 10 11
	balanced "gx/ipfs/QmQjEpRiwVvtowhq69dAtB4jhioPVFXiCcWZm9Sfgn7eqc/go-unixfs/importer/balanced"
	ihelper "gx/ipfs/QmQjEpRiwVvtowhq69dAtB4jhioPVFXiCcWZm9Sfgn7eqc/go-unixfs/importer/helpers"
	trickle "gx/ipfs/QmQjEpRiwVvtowhq69dAtB4jhioPVFXiCcWZm9Sfgn7eqc/go-unixfs/importer/trickle"
Jakub Sztandera's avatar
Jakub Sztandera committed
12

13
	cmds "gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds"
Jakub Sztandera's avatar
Jakub Sztandera committed
14
	mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
15 16 17
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
	chunk "gx/ipfs/QmXzBbJo2sLf3uwjNTeoWYiJV7CjAhkiA4twtLvwJSSNdK/go-ipfs-chunker"
	cid "gx/ipfs/QmZFbDTY9jfSBms2MchvYM9oYRbAF19K7Pby47yDBfpPrb/go-cid"
Jakub Sztandera's avatar
Jakub Sztandera committed
18 19
)

20
var urlStoreCmd = &cmds.Command{
Jakub Sztandera's avatar
Jakub Sztandera committed
21 22 23 24 25 26
	Subcommands: map[string]*cmds.Command{
		"add": urlAdd,
	},
}

var urlAdd = &cmds.Command{
27
	Helptext: cmdkit.HelpText{
28
		Tagline: "Add URL via urlstore.",
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
		LongDescription: `
Add URLs to ipfs without storing the data locally.

The URL provided must be stable and ideally on a web server under your
control.

The file is added using raw-leaves but otherwise using the default
settings for 'ipfs add'.

The file is not pinned, so this command should be followed by an 'ipfs
pin add'.

This command is considered temporary until a better solution can be
found.  It may disappear or the semantics can change at any
time.
`,
	},
46 47 48
	Options: []cmdkit.Option{
		cmdkit.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
	},
Jakub Sztandera's avatar
Jakub Sztandera committed
49 50 51 52 53
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("url", true, false, "URL to add to IPFS"),
	},
	Type: BlockStat{},

54 55 56
	Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) {
		url := req.Arguments[0]
		n, err := GetNode(env)
Jakub Sztandera's avatar
Jakub Sztandera committed
57 58 59 60 61
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

62 63 64 65 66
		if !filestore.IsURL(url) {
			res.SetError(fmt.Errorf("unsupported url syntax: %s", url), cmdkit.ErrNormal)
			return
		}

67 68 69 70 71 72 73
		cfg, err := n.Repo.Config()
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		if !cfg.Experimental.UrlstoreEnabled {
74
			res.SetError(filestore.ErrUrlstoreNotEnabled, cmdkit.ErrNormal)
75 76 77
			return
		}

78 79
		useTrickledag, _ := req.Options[trickleOptionName].(bool)

Jakub Sztandera's avatar
Jakub Sztandera committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
		hreq, err := http.NewRequest("GET", url, nil)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

		hres, err := http.DefaultClient.Do(hreq)
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}
		if hres.StatusCode != http.StatusOK {
			res.SetError(fmt.Errorf("expected code 200, got: %d", hres.StatusCode), cmdkit.ErrNormal)
			return
		}

		chk := chunk.NewSizeSplitter(hres.Body, chunk.DefaultBlockSize)
		prefix := cid.NewPrefixV1(cid.DagProtobuf, mh.SHA2_256)
		dbp := &ihelper.DagBuilderParams{
99 100 101 102 103 104
			Dagserv:    n.DAG,
			RawLeaves:  true,
			Maxlinks:   ihelper.DefaultLinksPerBlock,
			NoCopy:     true,
			CidBuilder: &prefix,
			URL:        url,
Jakub Sztandera's avatar
Jakub Sztandera committed
105 106
		}

107 108 109 110 111
		layout := balanced.Layout
		if useTrickledag {
			layout = trickle.Layout
		}
		root, err := layout(dbp.New(chk))
Jakub Sztandera's avatar
Jakub Sztandera committed
112 113 114 115 116
		if err != nil {
			res.SetError(err, cmdkit.ErrNormal)
			return
		}

117
		cmds.EmitOnce(res, BlockStat{
118
			Key:  root.Cid().String(),
Jakub Sztandera's avatar
Jakub Sztandera committed
119 120 121
			Size: int(hres.ContentLength),
		})
	},
122 123 124 125 126
	Encoders: cmds.EncoderMap{
		cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, bs *BlockStat) error {
			_, err := fmt.Fprintln(w, bs.Key)
			return err
		}),
Jakub Sztandera's avatar
Jakub Sztandera committed
127 128
	},
}