github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/core/core.go (about)

     1  package core
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"fmt"
     7  
     8  	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
     9  	b58 "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-base58"
    10  	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
    11  	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
    12  
    13  	bserv "github.com/jbenet/go-ipfs/blockservice"
    14  	config "github.com/jbenet/go-ipfs/config"
    15  	diag "github.com/jbenet/go-ipfs/diagnostics"
    16  	exchange "github.com/jbenet/go-ipfs/exchange"
    17  	bitswap "github.com/jbenet/go-ipfs/exchange/bitswap"
    18  	merkledag "github.com/jbenet/go-ipfs/merkledag"
    19  	namesys "github.com/jbenet/go-ipfs/namesys"
    20  	inet "github.com/jbenet/go-ipfs/net"
    21  	mux "github.com/jbenet/go-ipfs/net/mux"
    22  	netservice "github.com/jbenet/go-ipfs/net/service"
    23  	path "github.com/jbenet/go-ipfs/path"
    24  	peer "github.com/jbenet/go-ipfs/peer"
    25  	pin "github.com/jbenet/go-ipfs/pin"
    26  	routing "github.com/jbenet/go-ipfs/routing"
    27  	dht "github.com/jbenet/go-ipfs/routing/dht"
    28  	u "github.com/jbenet/go-ipfs/util"
    29  	ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
    30  )
    31  
    32  var log = u.Logger("core")
    33  
    34  // IpfsNode is IPFS Core module. It represents an IPFS instance.
    35  type IpfsNode struct {
    36  
    37  	// the node's configuration
    38  	Config *config.Config
    39  
    40  	// the local node's identity
    41  	Identity peer.Peer
    42  
    43  	// storage for other Peer instances
    44  	Peerstore peer.Peerstore
    45  
    46  	// the local datastore
    47  	Datastore ds.ThreadSafeDatastore
    48  
    49  	// the network message stream
    50  	Network inet.Network
    51  
    52  	// the routing system. recommend ipfs-dht
    53  	Routing routing.IpfsRouting
    54  
    55  	// the block exchange + strategy (bitswap)
    56  	Exchange exchange.Interface
    57  
    58  	// the block service, get/add blocks.
    59  	Blocks *bserv.BlockService
    60  
    61  	// the merkle dag service, get/add objects.
    62  	DAG merkledag.DAGService
    63  
    64  	// the path resolution system
    65  	Resolver *path.Resolver
    66  
    67  	// the name system, resolves paths to hashes
    68  	Namesys namesys.NameSystem
    69  
    70  	// the diagnostics service
    71  	Diagnostics *diag.Diagnostics
    72  
    73  	// the pinning manager
    74  	Pinning pin.Pinner
    75  
    76  	ctxc.ContextCloser
    77  
    78  	onlineMode bool // alternatively, offline
    79  }
    80  
    81  // NewIpfsNode constructs a new IpfsNode based on the given config.
    82  func NewIpfsNode(cfg *config.Config, online bool) (n *IpfsNode, err error) {
    83  	success := false // flip to true after all sub-system inits succeed
    84  	defer func() {
    85  		if !success && n != nil {
    86  			n.Close()
    87  		}
    88  	}()
    89  
    90  	if cfg == nil {
    91  		return nil, fmt.Errorf("configuration required")
    92  	}
    93  
    94  	// derive this from a higher context.
    95  	ctx := context.TODO()
    96  	n = &IpfsNode{
    97  		onlineMode:    online,
    98  		Config:        cfg,
    99  		ContextCloser: ctxc.NewContextCloser(ctx, nil),
   100  	}
   101  
   102  	// setup datastore.
   103  	if n.Datastore, err = makeDatastore(cfg.Datastore); err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	// setup peerstore + local peer identity
   108  	n.Peerstore = peer.NewPeerstore()
   109  	n.Identity, err = initIdentity(n.Config, n.Peerstore, online)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	// setup online services
   115  	if online {
   116  
   117  		dhtService := netservice.NewService(ctx, nil)      // nil handler for now, need to patch it
   118  		exchangeService := netservice.NewService(ctx, nil) // nil handler for now, need to patch it
   119  		diagService := netservice.NewService(ctx, nil)     // nil handler for now, need to patch it
   120  
   121  		muxMap := &mux.ProtocolMap{
   122  			mux.ProtocolID_Routing:    dhtService,
   123  			mux.ProtocolID_Exchange:   exchangeService,
   124  			mux.ProtocolID_Diagnostic: diagService,
   125  			// add protocol services here.
   126  		}
   127  
   128  		// setup the network
   129  		listenAddrs, err := listenAddresses(cfg)
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  
   134  		n.Network, err = inet.NewIpfsNetwork(ctx, listenAddrs, n.Identity, n.Peerstore, muxMap)
   135  		if err != nil {
   136  			return nil, err
   137  		}
   138  		n.AddCloserChild(n.Network)
   139  
   140  		// setup diagnostics service
   141  		n.Diagnostics = diag.NewDiagnostics(n.Identity, n.Network, diagService)
   142  		diagService.SetHandler(n.Diagnostics)
   143  
   144  		// setup routing service
   145  		dhtRouting := dht.NewDHT(ctx, n.Identity, n.Peerstore, n.Network, dhtService, n.Datastore)
   146  		// TODO(brian): perform this inside NewDHT factory method
   147  		dhtService.SetHandler(dhtRouting) // wire the handler to the service.
   148  		n.Routing = dhtRouting
   149  		n.AddCloserChild(dhtRouting)
   150  
   151  		// setup exchange service
   152  		const alwaysSendToPeer = true // use YesManStrategy
   153  		n.Exchange = bitswap.NetMessageSession(ctx, n.Identity, n.Network, exchangeService, n.Routing, n.Datastore, alwaysSendToPeer)
   154  		// ok, this function call is ridiculous o/ consider making it simpler.
   155  
   156  		go initConnections(ctx, n.Config, n.Peerstore, dhtRouting)
   157  	}
   158  
   159  	// TODO(brian): when offline instantiate the BlockService with a bitswap
   160  	// session that simply doesn't return blocks
   161  	n.Blocks, err = bserv.NewBlockService(n.Datastore, n.Exchange)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  
   166  	n.DAG = merkledag.NewDAGService(n.Blocks)
   167  	n.Namesys = namesys.NewNameSystem(n.Routing)
   168  	n.Pinning, err = pin.LoadPinner(n.Datastore, n.DAG)
   169  	if err != nil {
   170  		n.Pinning = pin.NewPinner(n.Datastore, n.DAG)
   171  	}
   172  	n.Resolver = &path.Resolver{DAG: n.DAG}
   173  
   174  	success = true
   175  	return n, nil
   176  }
   177  
   178  func (n *IpfsNode) OnlineMode() bool {
   179  	return n.onlineMode
   180  }
   181  
   182  func initIdentity(cfg *config.Config, peers peer.Peerstore, online bool) (peer.Peer, error) {
   183  	if cfg.Identity.PeerID == "" {
   184  		return nil, errors.New("Identity was not set in config (was ipfs init run?)")
   185  	}
   186  
   187  	if len(cfg.Identity.PeerID) == 0 {
   188  		return nil, errors.New("No peer ID in config! (was ipfs init run?)")
   189  	}
   190  
   191  	// get peer from peerstore (so it is constructed there)
   192  	id := peer.ID(b58.Decode(cfg.Identity.PeerID))
   193  	peer, err := peers.Get(id)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  
   198  	// when not online, don't need to parse private keys (yet)
   199  	if online {
   200  		skb, err := base64.StdEncoding.DecodeString(cfg.Identity.PrivKey)
   201  		if err != nil {
   202  			return nil, err
   203  		}
   204  
   205  		if err := peer.LoadAndVerifyKeyPair(skb); err != nil {
   206  			return nil, err
   207  		}
   208  	}
   209  
   210  	return peer, nil
   211  }
   212  
   213  func initConnections(ctx context.Context, cfg *config.Config, pstore peer.Peerstore, route *dht.IpfsDHT) {
   214  	for _, p := range cfg.Bootstrap {
   215  		if p.PeerID == "" {
   216  			log.Errorf("error: peer does not include PeerID. %v", p)
   217  		}
   218  
   219  		maddr, err := ma.NewMultiaddr(p.Address)
   220  		if err != nil {
   221  			log.Error(err)
   222  			continue
   223  		}
   224  
   225  		// setup peer
   226  		npeer, err := pstore.Get(peer.DecodePrettyID(p.PeerID))
   227  		if err != nil {
   228  			log.Errorf("Bootstrapping error: %v", err)
   229  			continue
   230  		}
   231  		npeer.AddAddress(maddr)
   232  
   233  		if _, err = route.Connect(ctx, npeer); err != nil {
   234  			log.Errorf("Bootstrapping error: %v", err)
   235  		}
   236  	}
   237  }
   238  
   239  func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
   240  	var listen []ma.Multiaddr
   241  
   242  	if len(cfg.Addresses.Swarm) > 0 {
   243  		maddr, err := ma.NewMultiaddr(cfg.Addresses.Swarm)
   244  		if err != nil {
   245  			return nil, fmt.Errorf("Failure to parse config.Addresses.Swarm: %s", cfg.Addresses.Swarm)
   246  		}
   247  
   248  		listen = append(listen, maddr)
   249  	}
   250  
   251  	return listen, nil
   252  }