urlstore.go 3.18 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
	cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
9
	filestore "github.com/ipfs/go-ipfs/filestore"
Jakub Sztandera's avatar
Jakub Sztandera committed
10

11
	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
Jakub Sztandera's avatar
Jakub Sztandera committed
12
	mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
Steven Allen's avatar
Steven Allen committed
13 14 15
	balanced "gx/ipfs/QmRX6WZhMinQrQhyuwaqNHYQtNPhtBwzxKFySzNMaJmW9v/go-unixfs/importer/balanced"
	ihelper "gx/ipfs/QmRX6WZhMinQrQhyuwaqNHYQtNPhtBwzxKFySzNMaJmW9v/go-unixfs/importer/helpers"
	trickle "gx/ipfs/QmRX6WZhMinQrQhyuwaqNHYQtNPhtBwzxKFySzNMaJmW9v/go-unixfs/importer/trickle"
16
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
Steven Allen's avatar
Steven Allen committed
17
	chunk "gx/ipfs/QmTUTG9Jg9ZRA1EzTPGTDvnwfcfKhDMnqANnP9fe4rSjMR/go-ipfs-chunker"
Steven Allen's avatar
Steven Allen committed
18
	cmds "gx/ipfs/QmXTmUCBtDUrzDYVzASogLiNph7EBuYqEgPL7QoHNMzUnz/go-ipfs-cmds"
Jakub Sztandera's avatar
Jakub Sztandera committed
19 20
)

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

var urlAdd = &cmds.Command{
28
	Helptext: cmdkit.HelpText{
29
		Tagline: "Add URL via urlstore.",
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
		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.
`,
	},
47 48 49
	Options: []cmdkit.Option{
		cmdkit.BoolOption(trickleOptionName, "t", "Use trickle-dag format for dag generation."),
	},
Jakub Sztandera's avatar
Jakub Sztandera committed
50 51 52
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("url", true, false, "URL to add to IPFS"),
	},
keks's avatar
keks committed
53
	Type: &BlockStat{},
Jakub Sztandera's avatar
Jakub Sztandera committed
54

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

62
		if !filestore.IsURL(url) {
keks's avatar
keks committed
63
			return fmt.Errorf("unsupported url syntax: %s", url)
64 65
		}

66 67
		cfg, err := n.Repo.Config()
		if err != nil {
keks's avatar
keks committed
68
			return err
69 70 71
		}

		if !cfg.Experimental.UrlstoreEnabled {
keks's avatar
keks committed
72
			return filestore.ErrUrlstoreNotEnabled
73 74
		}

75 76
		useTrickledag, _ := req.Options[trickleOptionName].(bool)

Jakub Sztandera's avatar
Jakub Sztandera committed
77 78
		hreq, err := http.NewRequest("GET", url, nil)
		if err != nil {
keks's avatar
keks committed
79
			return err
Jakub Sztandera's avatar
Jakub Sztandera committed
80 81 82 83
		}

		hres, err := http.DefaultClient.Do(hreq)
		if err != nil {
keks's avatar
keks committed
84
			return err
Jakub Sztandera's avatar
Jakub Sztandera committed
85 86
		}
		if hres.StatusCode != http.StatusOK {
keks's avatar
keks committed
87
			return fmt.Errorf("expected code 200, got: %d", hres.StatusCode)
Jakub Sztandera's avatar
Jakub Sztandera committed
88 89 90 91 92
		}

		chk := chunk.NewSizeSplitter(hres.Body, chunk.DefaultBlockSize)
		prefix := cid.NewPrefixV1(cid.DagProtobuf, mh.SHA2_256)
		dbp := &ihelper.DagBuilderParams{
93 94 95 96 97 98
			Dagserv:    n.DAG,
			RawLeaves:  true,
			Maxlinks:   ihelper.DefaultLinksPerBlock,
			NoCopy:     true,
			CidBuilder: &prefix,
			URL:        url,
Jakub Sztandera's avatar
Jakub Sztandera committed
99 100
		}

101 102 103 104 105
		layout := balanced.Layout
		if useTrickledag {
			layout = trickle.Layout
		}
		root, err := layout(dbp.New(chk))
Jakub Sztandera's avatar
Jakub Sztandera committed
106
		if err != nil {
keks's avatar
keks committed
107
			return err
Jakub Sztandera's avatar
Jakub Sztandera committed
108 109
		}

keks's avatar
keks committed
110
		return cmds.EmitOnce(res, &BlockStat{
111
			Key:  root.Cid().String(),
Jakub Sztandera's avatar
Jakub Sztandera committed
112 113 114
			Size: int(hres.ContentLength),
		})
	},
115 116 117 118 119
	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
120 121
	},
}