daemon.go 5 KB
Newer Older
1
package main
2 3

import (
4
	"fmt"
5

6
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
7
	cmds "github.com/jbenet/go-ipfs/commands"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8
	commands "github.com/jbenet/go-ipfs/core/commands"
9
	corehttp "github.com/jbenet/go-ipfs/core/corehttp"
10
	fsrepo "github.com/jbenet/go-ipfs/repo/fsrepo"
11
	util "github.com/jbenet/go-ipfs/util"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
12
	"github.com/jbenet/go-ipfs/util/debugerror"
13 14 15
)

const (
16
	initOptionKwd = "init"
17 18 19
	mountKwd      = "mount"
	ipfsMountKwd  = "mount-ipfs"
	ipnsMountKwd  = "mount-ipns"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20 21
	// apiAddrKwd    = "address-api"
	// swarmAddrKwd  = "address-swarm"
22 23
)

24
var daemonCmd = &cmds.Command{
25
	Helptext: cmds.HelpText{
Matt Bell's avatar
Matt Bell committed
26 27 28 29 30 31 32 33
		Tagline: "Run a network-connected IPFS node",
		ShortDescription: `
'ipfs daemon' runs a persistent IPFS daemon that can serve commands
over the network. Most applications that use IPFS will do so by
communicating with a daemon over the HTTP API. While the daemon is
running, calls to 'ipfs' commands will be sent over the network to
the daemon.
`,
34 35
	},

36
	Options: []cmds.Option{
37
		cmds.BoolOption(initOptionKwd, "Initialize IPFS with default settings if not already initialized"),
38 39 40
		cmds.BoolOption(mountKwd, "Mounts IPFS to the filesystem"),
		cmds.StringOption(ipfsMountKwd, "Path to the mountpoint for IPFS (if using --mount)"),
		cmds.StringOption(ipnsMountKwd, "Path to the mountpoint for IPNS (if using --mount)"),
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
41 42 43 44

		// TODO: add way to override addresses. tricky part: updating the config if also --init.
		// cmds.StringOption(apiAddrKwd, "Address for the daemon rpc API (overrides config)"),
		// cmds.StringOption(swarmAddrKwd, "Address for the swarm socket (overrides config)"),
45
	},
46 47 48 49
	Subcommands: map[string]*cmds.Command{},
	Run:         daemonFunc,
}

50
func daemonFunc(req cmds.Request, res cmds.Response) {
51

52
	fmt.Println("Initializing daemon...")
53 54
	// first, whether user has provided the initialization flag. we may be
	// running in an uninitialized state.
55
	initialize, _, err := req.Option(initOptionKwd).Bool()
56
	if err != nil {
57 58
		res.SetError(err, cmds.ErrNormal)
		return
59
	}
60
	if initialize {
61 62 63 64 65 66 67 68

		// now, FileExists is our best method of detecting whether IPFS is
		// configured. Consider moving this into a config helper method
		// `IsInitialized` where the quality of the signal can be improved over
		// time, and many call-sites can benefit.
		if !util.FileExists(req.Context().ConfigRoot) {
			err := initWithDefaults(req.Context().ConfigRoot)
			if err != nil {
69 70
				res.SetError(debugerror.Wrap(err), cmds.ErrNormal)
				return
71 72 73 74
			}
		}
	}

75 76 77 78 79 80 81 82
	// To ensure that IPFS has been initialized, fetch the config. Do this
	// _before_ acquiring the daemon lock so the user gets an appropriate error
	// message.
	// NB: It's safe to read the config without the daemon lock, but not safe
	// to write.
	ctx := req.Context()
	cfg, err := ctx.GetConfig()
	if err != nil {
83 84
		res.SetError(err, cmds.ErrNormal)
		return
85 86
	}

87
	// acquire the repo lock _before_ constructing a node. we need to make
88
	// sure we are permitted to access the resources (datastore, etc.)
89 90
	repo := fsrepo.At(req.Context().ConfigRoot)
	if err := repo.Open(); err != nil {
91 92
		res.SetError(debugerror.Errorf("Couldn't obtain lock. Is another daemon already running?"), cmds.ErrNormal)
		return
93
	}
94
	defer repo.Close()
95

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96 97
	// OK!!! Now we're ready to construct the node.
	// make sure we construct an online node.
98 99 100
	ctx.Online = true
	node, err := ctx.GetNode()
	if err != nil {
101 102
		res.SetError(err, cmds.ErrNormal)
		return
103 104
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
105 106
	// verify api address is valid multiaddr
	apiMaddr, err := ma.NewMultiaddr(cfg.Addresses.API)
107
	if err != nil {
108 109
		res.SetError(err, cmds.ErrNormal)
		return
110 111
	}

112 113 114 115 116 117 118 119
	var gatewayMaddr ma.Multiaddr
	if len(cfg.Addresses.Gateway) > 0 {
		// ignore error for gateway address
		// if there is an error (invalid address), then don't run the gateway
		gatewayMaddr, _ = ma.NewMultiaddr(cfg.Addresses.Gateway)
		if gatewayMaddr == nil {
			log.Errorf("Invalid gateway address: %s", cfg.Addresses.Gateway)
		}
120 121
	}

122 123
	// mount if the user provided the --mount flag
	mount, _, err := req.Option(mountKwd).Bool()
124
	if err != nil {
125 126
		res.SetError(err, cmds.ErrNormal)
		return
127
	}
128 129 130
	if mount {
		fsdir, found, err := req.Option(ipfsMountKwd).String()
		if err != nil {
131 132
			res.SetError(err, cmds.ErrNormal)
			return
133 134 135 136 137 138 139
		}
		if !found {
			fsdir = cfg.Mounts.IPFS
		}

		nsdir, found, err := req.Option(ipnsMountKwd).String()
		if err != nil {
140 141
			res.SetError(err, cmds.ErrNormal)
			return
142 143 144 145 146 147 148
		}
		if !found {
			nsdir = cfg.Mounts.IPNS
		}

		err = commands.Mount(node, fsdir, nsdir)
		if err != nil {
149 150
			res.SetError(err, cmds.ErrNormal)
			return
151
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
152 153
		fmt.Printf("IPFS mounted at: %s\n", fsdir)
		fmt.Printf("IPNS mounted at: %s\n", nsdir)
154
	}
155

156
	if gatewayMaddr != nil {
157
		go func() {
158
			err := corehttp.ListenAndServe(node, gatewayMaddr.String(), corehttp.GatewayOption)
159 160 161 162
			if err != nil {
				log.Error(err)
			}
		}()
163 164
	}

165 166 167 168
	var opts = []corehttp.ServeOption{
		corehttp.CommandsOption(*req.Context()),
		corehttp.WebUIOption,
		corehttp.GatewayOption,
169
	}
170
	if err := corehttp.ListenAndServe(node, apiMaddr.String(), opts...); err != nil {
171 172 173
		res.SetError(err, cmds.ErrNormal)
		return
	}
174
}