init.go 4.54 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3

import (
4
	"bytes"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
5
	"errors"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
6
	"fmt"
7
	"io"
Matt Bell's avatar
Matt Bell committed
8

9 10 11 12 13 14 15 16 17 18
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	assets "github.com/ipfs/go-ipfs/assets"
	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	coreunix "github.com/ipfs/go-ipfs/core/coreunix"
	namesys "github.com/ipfs/go-ipfs/namesys"
	config "github.com/ipfs/go-ipfs/repo/config"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
	uio "github.com/ipfs/go-ipfs/unixfs/io"
	u "github.com/ipfs/go-ipfs/util"
Matt Bell's avatar
Matt Bell committed
19 20
)

21
const nBitsForKeypairDefault = 2048
22

Matt Bell's avatar
Matt Bell committed
23
var initCmd = &cmds.Command{
24 25 26 27
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},
28

Matt Bell's avatar
Matt Bell committed
29
	Options: []cmds.Option{
30
		cmds.IntOption("bits", "b", "Number of bits to use in the generated RSA private key (defaults to 4096)"),
31
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
32 33 34 35 36

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
Matt Bell's avatar
Matt Bell committed
37
	},
38 39 40 41 42 43 44 45 46 47 48
	PreRun: func(req cmds.Request) error {
		daemonLocked := fsrepo.LockedByOtherProcess(req.Context().ConfigRoot)

		log.Info("checking if daemon is running...")
		if daemonLocked {
			e := "ipfs daemon is running. please stop it to run this command"
			return cmds.ClientError(e)
		}

		return nil
	},
49
	Run: func(req cmds.Request, res cmds.Response) {
50

51
		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
52
		if err != nil {
53 54
			res.SetError(err, cmds.ErrNormal)
			return
55 56
		}

57
		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
58
		if err != nil {
59 60
			res.SetError(err, cmds.ErrNormal)
			return
61
		}
Henry's avatar
Henry committed
62

63
		if !bitsOptFound {
64
			nBitsForKeypair = nBitsForKeypairDefault
65 66
		}

67 68 69 70 71 72 73 74 75
		rpipe, wpipe := io.Pipe()
		go func() {
			defer wpipe.Close()
			if err := doInit(wpipe, req.Context().ConfigRoot, force, nBitsForKeypair); err != nil {
				res.SetError(err, cmds.ErrNormal)
				return
			}
		}()
		res.SetOutput(rpipe)
76 77
	},
}
Matt Bell's avatar
Matt Bell committed
78

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
var errRepoExists = errors.New(`ipfs configuration file already exists!
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80 81 82 83
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

84 85
func initWithDefaults(out io.Writer, repoRoot string) error {
	err := doInit(out, repoRoot, false, nBitsForKeypairDefault)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86
	return err
87 88
}

89
func doInit(out io.Writer, repoRoot string, force bool, nBitsForKeypair int) error {
Henry's avatar
Henry committed
90
	if _, err := fmt.Fprintf(out, "initializing ipfs node at %s\n", repoRoot); err != nil {
91 92
		return err
	}
93

94
	if fsrepo.IsInitialized(repoRoot) && !force {
95
		return errRepoExists
96
	}
Henry's avatar
Henry committed
97

98
	conf, err := config.Init(out, nBitsForKeypair)
99
	if err != nil {
100
		return err
101
	}
Henry's avatar
Henry committed
102

103
	if fsrepo.IsInitialized(repoRoot) {
104
		if err := fsrepo.Remove(repoRoot); err != nil {
105
			return err
106
		}
107
	}
Henry's avatar
Henry committed
108

109
	if err := fsrepo.Init(repoRoot, conf); err != nil {
110
		return err
111
	}
112

113 114
	if err := addDefaultAssets(out, repoRoot); err != nil {
		return err
Jeromy's avatar
Jeromy committed
115
	}
116 117

	return initializeIpnsKeyspace(repoRoot)
118 119
}

120
func addDefaultAssets(out io.Writer, repoRoot string) error {
121
	ctx, cancel := context.WithCancel(context.Background())
122
	defer cancel()
Henry's avatar
Henry committed
123

124 125
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
126 127
		return err
	}
Henry's avatar
Henry committed
128

129
	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
130
	if err != nil {
131
		return err
132 133 134
	}
	defer nd.Close()

135 136 137 138 139 140 141 142 143
	dirb := uio.NewDirectory(nd.DAG)

	// add every file in the assets pkg
	for fname, file := range assets.Init_dir {
		buf := bytes.NewBufferString(file)
		s, err := coreunix.Add(nd, buf)
		if err != nil {
			return err
		}
Henry's avatar
Henry committed
144

145 146 147 148 149 150 151 152
		k := u.B58KeyDecode(s)
		if err := dirb.AddChild(fname, k); err != nil {
			return err
		}
	}

	dir := dirb.GetNode()
	dkey, err := nd.DAG.Add(dir)
153
	if err != nil {
154 155
		return err
	}
Henry's avatar
Henry committed
156

Jeromy's avatar
Jeromy committed
157
	if err := nd.Pinning.Pin(ctx, dir, true); err != nil {
158
		return err
159
	}
Henry's avatar
Henry committed
160

161 162 163 164
	if err := nd.Pinning.Flush(); err != nil {
		return err
	}

Henry's avatar
Henry committed
165 166 167 168 169 170
	if _, err = fmt.Fprintf(out, "to get started, enter:\n"); err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
	return err
Matt Bell's avatar
Matt Bell committed
171
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
172

Jeromy's avatar
Jeromy committed
173 174 175 176
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

177 178
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
Jeromy's avatar
Jeromy committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192
		return err
	}

	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
	if err != nil {
		return err
	}
	defer nd.Close()

	err = nd.SetupOfflineRouting()
	if err != nil {
		return err
	}

193
	return namesys.InitializeKeyspace(ctx, nd.DAG, nd.Namesys, nd.Pinning, nd.PrivateKey)
Jeromy's avatar
Jeromy committed
194
}