urlstore.go 3.44 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

Steven Allen's avatar
Steven Allen committed
11 12 13
	balanced "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/importer/balanced"
	ihelper "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/importer/helpers"
	trickle "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/importer/trickle"
14
	cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid"
15
	cmds "gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds"
Jakub Sztandera's avatar
Jakub Sztandera committed
16
	mh "gx/ipfs/QmPnFwZ2JXKnXgMw8CdBPxn7FWh6LLdjUjxV1fKHuJnkr8/go-multihash"
17
	cmdkit "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit"
18
	chunk "gx/ipfs/QmdSeG9s4EQ9TGruJJS9Us38TQDZtMmFGwzTYUDVqNTURm/go-ipfs-chunker"
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 53 54
	Arguments: []cmdkit.Argument{
		cmdkit.StringArg("url", true, false, "URL to add to IPFS"),
	},
	Type: BlockStat{},

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

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

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

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

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

Jakub Sztandera's avatar
Jakub Sztandera committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
		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{
100 101 102 103 104 105
			Dagserv:    n.DAG,
			RawLeaves:  true,
			Maxlinks:   ihelper.DefaultLinksPerBlock,
			NoCopy:     true,
			CidBuilder: &prefix,
			URL:        url,
Jakub Sztandera's avatar
Jakub Sztandera committed
106 107
		}

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

118
		cmds.EmitOnce(res, BlockStat{
119
			Key:  root.Cid().String(),
Jakub Sztandera's avatar
Jakub Sztandera committed
120 121 122
			Size: int(hres.ContentLength),
		})
	},
123 124 125 126 127
	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
128 129
	},
}