core.go 16.4 KB
Newer Older
1 2 3 4
/*
Package core implements the IpfsNode object and related methods.

Packages underneath core/ provide a (relatively) stable, low-level API
5 6 7 8
to carry out most IPFS-related tasks.  For more details on the other
interfaces and how core/... fits into the bigger IPFS picture, see:

  $ godoc github.com/ipfs/go-ipfs
9
*/
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11
package core

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
13
	"errors"
Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
14
	"fmt"
15
	"io"
Jeromy's avatar
Jeromy committed
16
	"net"
17
	"time"
18

19 20 21
	b58 "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
	ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
22 23
	goprocess "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
	goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
Jeromy's avatar
Jeromy committed
24
	mamask "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/multiaddr-filter"
25 26
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	diag "github.com/ipfs/go-ipfs/diagnostics"
Jeromy's avatar
Jeromy committed
27
	metrics "github.com/ipfs/go-ipfs/metrics"
28
	ic "github.com/ipfs/go-ipfs/p2p/crypto"
29
	discovery "github.com/ipfs/go-ipfs/p2p/discovery"
30 31 32 33 34 35
	p2phost "github.com/ipfs/go-ipfs/p2p/host"
	p2pbhost "github.com/ipfs/go-ipfs/p2p/host/basic"
	rhost "github.com/ipfs/go-ipfs/p2p/host/routed"
	swarm "github.com/ipfs/go-ipfs/p2p/net/swarm"
	addrutil "github.com/ipfs/go-ipfs/p2p/net/swarm/addr"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
Jeromy's avatar
Jeromy committed
36
	eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog"
37

38 39 40 41
	routing "github.com/ipfs/go-ipfs/routing"
	dht "github.com/ipfs/go-ipfs/routing/dht"
	kb "github.com/ipfs/go-ipfs/routing/kbucket"
	offroute "github.com/ipfs/go-ipfs/routing/offline"
42

43 44 45 46 47 48 49
	bstore "github.com/ipfs/go-ipfs/blocks/blockstore"
	bserv "github.com/ipfs/go-ipfs/blockservice"
	exchange "github.com/ipfs/go-ipfs/exchange"
	bitswap "github.com/ipfs/go-ipfs/exchange/bitswap"
	bsnet "github.com/ipfs/go-ipfs/exchange/bitswap/network"
	offline "github.com/ipfs/go-ipfs/exchange/offline"
	rp "github.com/ipfs/go-ipfs/exchange/reprovide"
50

51 52 53 54 55 56 57 58
	mount "github.com/ipfs/go-ipfs/fuse/mount"
	ipnsfs "github.com/ipfs/go-ipfs/ipnsfs"
	merkledag "github.com/ipfs/go-ipfs/merkledag"
	namesys "github.com/ipfs/go-ipfs/namesys"
	path "github.com/ipfs/go-ipfs/path"
	pin "github.com/ipfs/go-ipfs/pin"
	repo "github.com/ipfs/go-ipfs/repo"
	config "github.com/ipfs/go-ipfs/repo/config"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
59 60
)

Jeromy's avatar
Jeromy committed
61
const IpnsValidatorTag = "ipns"
62
const kSizeBlockstoreWriteCache = 100
63
const kReprovideFrequency = time.Hour * 12
Jeromy's avatar
Jeromy committed
64

Brian Tiger Chow's avatar
Brian Tiger Chow committed
65
var log = eventlog.Logger("core")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
66

67 68 69 70 71 72 73 74 75
type mode int

const (
	// zero value is not a valid mode, must be explicitly set
	invalidMode mode = iota
	offlineMode
	onlineMode
)

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
76
// IpfsNode is IPFS Core module. It represents an IPFS instance.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77 78
type IpfsNode struct {

79
	// Self
80
	Identity peer.ID // the local node's identity
81

82
	Repo repo.Repo
83 84

	// Local node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85 86 87
	Pinning    pin.Pinner // the pinning manager
	Mounts     Mounts     // current mount state, if any.
	PrivateKey ic.PrivKey // the local node's private Key
88 89

	// Services
90 91 92 93 94
	Peerstore  peer.Peerstore       // storage for other Peer instances
	Blockstore bstore.Blockstore    // the block store (lower level)
	Blocks     *bserv.BlockService  // the block service, get/add blocks.
	DAG        merkledag.DAGService // the merkle dag service, get/add objects.
	Resolver   *path.Resolver       // the path resolution system
Jeromy's avatar
Jeromy committed
95
	Reporter   metrics.Reporter
96
	Discovery  discovery.Service
97 98

	// Online
99 100 101 102 103 104 105
	PeerHost     p2phost.Host        // the network host (server+client)
	Bootstrapper io.Closer           // the periodic bootstrapper
	Routing      routing.IpfsRouting // the routing system. recommend ipfs-dht
	Exchange     exchange.Interface  // the block exchange + strategy (bitswap)
	Namesys      namesys.NameSystem  // the name system, resolves paths to hashes
	Diagnostics  *diag.Diagnostics   // the diagnostics service
	Reprovider   *rp.Reprovider      // the value reprovider system
106

107 108
	IpnsFs *ipnsfs.Filesystem

109 110
	proc goprocess.Process
	ctx  context.Context
111

112
	mode mode
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
113 114
}

115 116 117 118 119 120 121 122
// Mounts defines what the node's mount state is. This should
// perhaps be moved to the daemon or mount. It's here because
// it needs to be accessible across daemon requests.
type Mounts struct {
	Ipfs mount.Mount
	Ipns mount.Mount
}

123
type ConfigOption func(ctx context.Context) (*IpfsNode, error)
124

125 126 127 128 129 130
func NewIPFSNode(ctx context.Context, option ConfigOption) (*IpfsNode, error) {
	node, err := option(ctx)
	if err != nil {
		return nil, err
	}

131
	node.proc = goprocessctx.WithContextAndTeardown(ctx, node.teardown)
132 133
	node.ctx = ctx

134 135 136
	success := false // flip to true after all sub-system inits succeed
	defer func() {
		if !success {
137
			node.proc.Close()
138 139 140
		}
	}()

141 142 143 144
	// Need to make sure it's perfectly clear 1) which variables are expected
	// to be initialized at this point, and 2) which variables will be
	// initialized after this point.

145 146
	node.Blocks, err = bserv.New(node.Blockstore, node.Exchange)
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
147
		return nil, err
148
	}
149 150 151
	if node.Peerstore == nil {
		node.Peerstore = peer.NewPeerstore()
	}
152
	node.DAG = merkledag.NewDAGService(node.Blocks)
153
	node.Pinning, err = pin.LoadPinner(node.Repo.Datastore(), node.DAG)
154
	if err != nil {
155
		node.Pinning = pin.NewPinner(node.Repo.Datastore(), node.DAG)
156 157
	}
	node.Resolver = &path.Resolver{DAG: node.DAG}
158 159 160 161

	// Setup the mutable ipns filesystem structure
	if node.OnlineMode() {
		fs, err := ipnsfs.NewFilesystem(ctx, node.DAG, node.Namesys, node.Pinning, node.PrivateKey)
162
		if err != nil && err != kb.ErrLookupFailure {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
163
			return nil, err
164 165 166 167
		}
		node.IpnsFs = fs
	}

168
	success = true
Brian Tiger Chow's avatar
Brian Tiger Chow committed
169
	return node, nil
170 171
}

172 173
func Offline(r repo.Repo) ConfigOption {
	return Standard(r, false)
174 175
}

Jeromy's avatar
Jeromy committed
176 177
func OnlineWithOptions(r repo.Repo, router RoutingOption, ho HostOption) ConfigOption {
	return standardWithRouting(r, true, router, ho)
178 179
}

180 181
func Online(r repo.Repo) ConfigOption {
	return Standard(r, true)
182 183 184
}

// DEPRECATED: use Online, Offline functions
185
func Standard(r repo.Repo, online bool) ConfigOption {
Jeromy's avatar
Jeromy committed
186
	return standardWithRouting(r, online, DHTOption, DefaultHostOption)
187 188 189
}

// TODO refactor so maybeRouter isn't special-cased in this way
Jeromy's avatar
Jeromy committed
190
func standardWithRouting(r repo.Repo, online bool, routingOption RoutingOption, hostOption HostOption) ConfigOption {
191
	return func(ctx context.Context) (n *IpfsNode, err error) {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
192 193 194 195 196 197 198 199 200 201 202 203
		// FIXME perform node construction in the main constructor so it isn't
		// necessary to perform this teardown in this scope.
		success := false
		defer func() {
			if !success && n != nil {
				n.teardown()
			}
		}()

		// TODO move as much of node initialization as possible into
		// NewIPFSNode. The larger these config options are, the harder it is
		// to test all node construction code paths.
204

205
		if r == nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
206
			return nil, fmt.Errorf("repo required")
207 208
		}
		n = &IpfsNode{
209 210 211 212 213 214
			mode: func() mode {
				if online {
					return onlineMode
				}
				return offlineMode
			}(),
215
			Repo: r,
216
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
217

218 219
		// setup Peerstore
		n.Peerstore = peer.NewPeerstore()
220

221 222 223 224
		// setup local peer ID (private key is loaded in online setup)
		if err := n.loadID(); err != nil {
			return nil, err
		}
Juan Batiz-Benet's avatar
go fmt  
Juan Batiz-Benet committed
225

226
		n.Blockstore, err = bstore.WriteCached(bstore.NewBlockstore(n.Repo.Datastore()), kSizeBlockstoreWriteCache)
227
		if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
228
			return nil, err
229
		}
230

231
		if online {
Jeromy's avatar
Jeromy committed
232 233
			do := setupDiscoveryOption(n.Repo.Config().Discovery)
			if err := n.startOnlineServices(ctx, routingOption, hostOption, do); err != nil {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
234
				return nil, err
235 236 237 238
			}
		} else {
			n.Exchange = offline.Exchange(n.Blockstore)
		}
239

Brian Tiger Chow's avatar
Brian Tiger Chow committed
240
		success = true
241
		return n, nil
Jeromy's avatar
Jeromy committed
242
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
243
}
244

Jeromy's avatar
Jeromy committed
245
func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption, do DiscoveryOption) error {
246 247

	if n.PeerHost != nil { // already online.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
248
		return errors.New("node already online")
249 250 251
	}

	// load private key
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
252
	if err := n.LoadPrivateKey(); err != nil {
253 254 255
		return err
	}

Jeromy's avatar
Jeromy committed
256 257 258
	// Set reporter
	n.Reporter = metrics.NewBandwidthCounter()

Jeromy's avatar
Jeromy committed
259 260 261
	// get undialable addrs from config
	cfg := n.Repo.Config()
	var addrfilter []*net.IPNet
262
	for _, s := range cfg.Swarm.AddrFilters {
Jeromy's avatar
Jeromy committed
263 264 265 266 267 268 269 270
		f, err := mamask.NewMask(s)
		if err != nil {
			return fmt.Errorf("incorrectly formatter address filter in config: %s", s)
		}
		addrfilter = append(addrfilter, f)
	}

	peerhost, err := hostOption(ctx, n.Identity, n.Peerstore, n.Reporter, addrfilter)
271
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
272
		return err
273 274
	}

275
	if err := n.startOnlineServicesWithHost(ctx, peerhost, routingOption); err != nil {
276
		return err
277 278 279 280
	}

	// Ok, now we're ready to listen.
	if err := startListening(ctx, n.PeerHost, n.Repo.Config()); err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
281
		return err
282
	}
283

284
	n.Reprovider = rp.NewReprovider(n.Routing, n.Blockstore)
285
	go n.Reprovider.ProvideEvery(ctx, kReprovideFrequency)
286

287
	// setup local discovery
Jeromy's avatar
Jeromy committed
288 289 290
	if do != nil {
		service, err := do(n.PeerHost)
		if err != nil {
Jeromy's avatar
Jeromy committed
291 292 293 294
			log.Error("mdns error: ", err)
		} else {
			service.RegisterNotifee(n)
			n.Discovery = service
Jeromy's avatar
Jeromy committed
295
		}
296 297
	}

298
	return n.Bootstrap(DefaultBootstrapConfig)
299 300
}

Jeromy's avatar
Jeromy committed
301 302 303 304 305 306 307 308 309 310 311 312
func setupDiscoveryOption(d config.Discovery) DiscoveryOption {
	if d.MDNS.Enabled {
		return func(h p2phost.Host) (discovery.Service, error) {
			if d.MDNS.Interval == 0 {
				d.MDNS.Interval = 5
			}
			return discovery.NewMdnsService(h, time.Duration(d.MDNS.Interval)*time.Second)
		}
	}
	return nil
}

313 314
func (n *IpfsNode) HandlePeerFound(p peer.PeerInfo) {
	log.Warning("trying peer info: ", p)
315
	ctx, _ := context.WithTimeout(context.TODO(), time.Second*10)
316 317 318 319 320 321
	err := n.PeerHost.Connect(ctx, p)
	if err != nil {
		log.Warning("Failed to connect to peer found by discovery: ", err)
	}
}

322 323
// startOnlineServicesWithHost  is the set of services which need to be
// initialized with the host and _before_ we start listening.
324
func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, host p2phost.Host, routingOption RoutingOption) error {
325
	// setup diagnostics service
326
	n.Diagnostics = diag.NewDiagnostics(n.Identity, host)
327 328

	// setup routing service
329
	r, err := routingOption(ctx, host, n.Repo.Datastore())
Jeromy's avatar
Jeromy committed
330
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
331
		return err
332
	}
Jeromy's avatar
Jeromy committed
333
	n.Routing = r
334

335 336 337
	// Wrap standard peer host with routing system to allow unknown peer lookups
	n.PeerHost = rhost.Wrap(host, n.Routing)

338 339
	// setup exchange service
	const alwaysSendToPeer = true // use YesManStrategy
340
	bitswapNetwork := bsnet.NewFromIpfsHost(n.PeerHost, n.Routing)
341 342 343 344
	n.Exchange = bitswap.New(ctx, n.Identity, bitswapNetwork, n.Blockstore, alwaysSendToPeer)

	// setup name system
	n.Namesys = namesys.NewNameSystem(n.Routing)
345

346 347 348
	return nil
}

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
// Process returns the Process object
func (n *IpfsNode) Process() goprocess.Process {
	return n.proc
}

// Close calls Close() on the Process object
func (n *IpfsNode) Close() error {
	return n.proc.Close()
}

// Context returns the IpfsNode context
func (n *IpfsNode) Context() context.Context {
	return n.ctx
}

364 365
// teardown closes owned children. If any errors occur, this function returns
// the first error.
Brian Tiger Chow's avatar
Brian Tiger Chow committed
366
func (n *IpfsNode) teardown() error {
367
	log.Debug("core is shutting down...")
368 369
	// owned objects are closed in this teardown to ensure that they're closed
	// regardless of which constructor was used to add them to the node.
Jeromy's avatar
Jeromy committed
370 371 372 373
	closers := []io.Closer{
		n.Exchange,
		n.Repo,
	}
374

Jeromy's avatar
Jeromy committed
375 376
	// Filesystem needs to be closed before network, dht, and blockservice
	// so it can use them as its shutting down
377
	if n.IpnsFs != nil {
Jeromy's avatar
Jeromy committed
378 379 380
		closers = append(closers, n.IpnsFs)
	}

Jeromy's avatar
Jeromy committed
381 382 383 384
	if n.Blocks != nil {
		closers = append(closers, n.Blocks)
	}

Jeromy's avatar
Jeromy committed
385 386
	if n.Bootstrapper != nil {
		closers = append(closers, n.Bootstrapper)
387 388
	}

389
	if dht, ok := n.Routing.(*dht.IpfsDHT); ok {
390
		closers = append(closers, dht.Process())
Jeromy's avatar
Jeromy committed
391 392 393 394
	}

	if n.PeerHost != nil {
		closers = append(closers, n.PeerHost)
395
	}
396

397
	var errs []error
398
	for _, closer := range closers {
399 400
		if err := closer.Close(); err != nil {
			errs = append(errs, err)
401 402 403 404
		}
	}
	if len(errs) > 0 {
		return errs[0]
Brian Tiger Chow's avatar
Brian Tiger Chow committed
405 406
	}
	return nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
407 408
}

Brian Tiger Chow's avatar
Brian Tiger Chow committed
409
func (n *IpfsNode) OnlineMode() bool {
410 411 412 413 414 415
	switch n.mode {
	case onlineMode:
		return true
	default:
		return false
	}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
416 417
}

418
func (n *IpfsNode) Bootstrap(cfg BootstrapConfig) error {
419 420

	// TODO what should return value be when in offlineMode?
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
421 422 423 424
	if n.Routing == nil {
		return nil
	}

425 426 427 428 429 430 431 432
	if n.Bootstrapper != nil {
		n.Bootstrapper.Close() // stop previous bootstrap process.
	}

	// if the caller did not specify a bootstrap peer function, get the
	// freshest bootstrap peers from config. this responds to live changes.
	if cfg.BootstrapPeers == nil {
		cfg.BootstrapPeers = func() []peer.PeerInfo {
433
			ps, err := n.loadBootstrapPeers()
434
			if err != nil {
435
				log.Warningf("failed to parse bootstrap peers from config: %s", n.Repo.Config().Bootstrap)
436 437 438 439 440 441 442 443 444
				return nil
			}
			return ps
		}
	}

	var err error
	n.Bootstrapper, err = Bootstrap(n, cfg)
	return err
445 446
}

447 448
func (n *IpfsNode) loadID() error {
	if n.Identity != "" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
449
		return errors.New("identity already loaded")
450 451
	}

452
	cid := n.Repo.Config().Identity.PeerID
453
	if cid == "" {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
454
		return errors.New("Identity was not set in config (was ipfs init run?)")
455 456
	}
	if len(cid) == 0 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
457
		return errors.New("No peer ID in config! (was ipfs init run?)")
458 459
	}

460 461 462
	n.Identity = peer.ID(b58.Decode(cid))
	return nil
}
463

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
464
func (n *IpfsNode) LoadPrivateKey() error {
465
	if n.Identity == "" || n.Peerstore == nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
466
		return errors.New("loaded private key out of order.")
467 468
	}

469
	if n.PrivateKey != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
470
		return errors.New("private key already loaded")
471 472
	}

473
	sk, err := loadPrivateKey(&n.Repo.Config().Identity, n.Identity)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
474
	if err != nil {
475
		return err
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
476
	}
477

478 479
	n.PrivateKey = sk
	n.Peerstore.AddPrivKey(n.Identity, n.PrivateKey)
Jeromy's avatar
Jeromy committed
480 481 482 483
	n.Peerstore.AddPubKey(n.Identity, sk.GetPublic())
	return nil
}

484 485 486 487 488 489 490 491
func (n *IpfsNode) loadBootstrapPeers() ([]peer.PeerInfo, error) {
	parsed, err := n.Repo.Config().BootstrapPeers()
	if err != nil {
		return nil, err
	}
	return toPeerInfos(parsed), nil
}

Jeromy's avatar
Jeromy committed
492 493 494
// SetupOfflineRouting loads the local nodes private key and
// uses it to instantiate a routing system in offline mode.
// This is primarily used for offline ipns modifications.
Jeromy's avatar
Jeromy committed
495
func (n *IpfsNode) SetupOfflineRouting() error {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
496
	err := n.LoadPrivateKey()
Jeromy's avatar
Jeromy committed
497 498 499 500 501
	if err != nil {
		return err
	}

	n.Routing = offroute.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey)
502 503 504

	n.Namesys = namesys.NewNameSystem(n.Routing)

505
	return nil
506 507 508 509
}

func loadPrivateKey(cfg *config.Identity, id peer.ID) (ic.PrivKey, error) {
	sk, err := cfg.DecodePrivateKey("passphrase todo!")
510 511 512
	if err != nil {
		return nil, err
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
513

514 515 516 517
	id2, err := peer.IDFromPrivateKey(sk)
	if err != nil {
		return nil, err
	}
518

519 520
	if id2 != id {
		return nil, fmt.Errorf("private key in config does not match id: %s != %s", id, id2)
521 522
	}

523
	return sk, nil
524
}
525

526
func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
527 528 529
	var listen []ma.Multiaddr
	for _, addr := range cfg.Addresses.Swarm {
		maddr, err := ma.NewMultiaddr(addr)
530
		if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
531
			return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm: %s", cfg.Addresses.Swarm)
532
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
533
		listen = append(listen, maddr)
534 535 536 537
	}

	return listen, nil
}
538

Jeromy's avatar
Jeromy committed
539
type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error)
Jeromy's avatar
Jeromy committed
540 541 542

var DefaultHostOption HostOption = constructPeerHost

543
// isolates the complex initialization steps
Jeromy's avatar
Jeromy committed
544
func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore, bwr metrics.Reporter, fs []*net.IPNet) (p2phost.Host, error) {
545 546

	// no addresses to begin with. we'll start later.
Jeromy's avatar
Jeromy committed
547
	network, err := swarm.NewNetwork(ctx, nil, id, ps, bwr)
548
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
549
		return nil, err
550
	}
551

552 553 554 555
	for _, f := range fs {
		network.Swarm().Filters.AddDialFilter(f)
	}

Jeromy's avatar
Jeromy committed
556 557
	host := p2pbhost.New(network, p2pbhost.NATPortMap, bwr)

558 559 560 561 562 563 564
	return host, nil
}

// startListening on the network addresses
func startListening(ctx context.Context, host p2phost.Host, cfg *config.Config) error {
	listenAddrs, err := listenAddresses(cfg)
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
565
		return err
566 567
	}

568
	// make sure we error out if our config does not have addresses we can use
569
	log.Debugf("Config.Addresses.Swarm:%s", listenAddrs)
570
	filteredAddrs := addrutil.FilterUsableAddrs(listenAddrs)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
571
	log.Debugf("Config.Addresses.Swarm:%s (filtered)", filteredAddrs)
572
	if len(filteredAddrs) < 1 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
573
		return fmt.Errorf("addresses in config not usable: %s", listenAddrs)
574 575
	}

576 577 578
	// Actually start listening:
	if err := host.Network().Listen(filteredAddrs...); err != nil {
		return err
579 580
	}

581
	// list out our addresses
582
	addrs, err := host.Network().InterfaceListenAddresses()
583
	if err != nil {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
584
		return err
585
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
586
	log.Infof("Swarm listening at: %s", addrs)
587
	return nil
588
}
589

590 591
func constructDHTRouting(ctx context.Context, host p2phost.Host, dstore ds.ThreadSafeDatastore) (routing.IpfsRouting, error) {
	dhtRouting := dht.NewDHT(ctx, host, dstore)
592
	dhtRouting.Validator[IpnsValidatorTag] = namesys.IpnsRecordValidator
593 594
	return dhtRouting, nil
}
Jeromy's avatar
Jeromy committed
595

596
type RoutingOption func(context.Context, p2phost.Host, ds.ThreadSafeDatastore) (routing.IpfsRouting, error)
Jeromy's avatar
Jeromy committed
597

Jeromy's avatar
Jeromy committed
598 599
type DiscoveryOption func(p2phost.Host) (discovery.Service, error)

600
var DHTOption RoutingOption = constructDHTRouting