github.com/bcskill/bcschain/v3@v3.4.9-beta2/p2p/simulations/network.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package simulations
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"sync"
    25  	"time"
    26  
    27  	"github.com/bcskill/bcschain/v3/event"
    28  	"github.com/bcskill/bcschain/v3/log"
    29  	"github.com/bcskill/bcschain/v3/p2p"
    30  	"github.com/bcskill/bcschain/v3/p2p/discover"
    31  	"github.com/bcskill/bcschain/v3/p2p/simulations/adapters"
    32  )
    33  
    34  var dialBanTimeout = 200 * time.Millisecond
    35  
    36  // NetworkConfig defines configuration options for starting a Network
    37  type NetworkConfig struct {
    38  	ID             string `json:"id"`
    39  	DefaultService string `json:"default_service,omitempty"`
    40  }
    41  
    42  // Network models a p2p simulation network which consists of a collection of
    43  // simulated nodes and the connections which exist between them.
    44  //
    45  // The Network has a single NodeAdapter which is responsible for actually
    46  // starting nodes and connecting them together.
    47  //
    48  // The Network emits events when nodes are started and stopped, when they are
    49  // connected and disconnected, and also when messages are sent between nodes.
    50  type Network struct {
    51  	NetworkConfig
    52  
    53  	Nodes   []*Node `json:"nodes"`
    54  	nodeMap map[discover.NodeID]int
    55  
    56  	Conns   []*Conn `json:"conns"`
    57  	connMap map[string]int
    58  
    59  	nodeAdapter adapters.NodeAdapter
    60  	events      EventFeed
    61  	lock        sync.RWMutex
    62  	quitc       chan struct{}
    63  }
    64  
    65  // NewNetwork returns a Network which uses the given NodeAdapter and NetworkConfig
    66  func NewNetwork(nodeAdapter adapters.NodeAdapter, conf *NetworkConfig) *Network {
    67  	return &Network{
    68  		NetworkConfig: *conf,
    69  		nodeAdapter:   nodeAdapter,
    70  		nodeMap:       make(map[discover.NodeID]int),
    71  		connMap:       make(map[string]int),
    72  		quitc:         make(chan struct{}),
    73  	}
    74  }
    75  
    76  // Events returns the output event feed of the Network.
    77  func (net *Network) Events() *EventFeed {
    78  	return &net.events
    79  }
    80  
    81  // NewNode adds a new node to the network with a random ID
    82  func (self *Network) NewNode() (*Node, error) {
    83  	conf := adapters.RandomNodeConfig()
    84  	conf.Services = []string{self.DefaultService}
    85  	return self.NewNodeWithConfig(conf)
    86  }
    87  
    88  // NewNodeWithConfig adds a new node to the network with the given config,
    89  // returning an error if a node with the same ID or name already exists
    90  func (self *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error) {
    91  	self.lock.Lock()
    92  	defer self.lock.Unlock()
    93  
    94  	// create a random ID and PrivateKey if not set
    95  	if conf.ID == (discover.NodeID{}) {
    96  		c := adapters.RandomNodeConfig()
    97  		conf.ID = c.ID
    98  		conf.PrivateKey = c.PrivateKey
    99  	}
   100  	id := conf.ID
   101  	if conf.Reachable == nil {
   102  		conf.Reachable = func(otherID discover.NodeID) bool {
   103  			_, err := self.InitConn(conf.ID, otherID)
   104  			return err == nil
   105  		}
   106  	}
   107  
   108  	// assign a name to the node if not set
   109  	if conf.Name == "" {
   110  		conf.Name = fmt.Sprintf("node%02d", len(self.Nodes)+1)
   111  	}
   112  
   113  	// check the node doesn't already exist
   114  	if node := self.getNode(id); node != nil {
   115  		return nil, fmt.Errorf("node with ID %q already exists", id)
   116  	}
   117  	if node := self.getNodeByName(conf.Name); node != nil {
   118  		return nil, fmt.Errorf("node with name %q already exists", conf.Name)
   119  	}
   120  
   121  	// if no services are configured, use the default service
   122  	if len(conf.Services) == 0 {
   123  		conf.Services = []string{self.DefaultService}
   124  	}
   125  
   126  	// use the NodeAdapter to create the node
   127  	adapterNode, err := self.nodeAdapter.NewNode(conf)
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	node := &Node{
   132  		Node:   adapterNode,
   133  		Config: conf,
   134  	}
   135  	log.Trace(fmt.Sprintf("node %v created", id))
   136  	self.nodeMap[id] = len(self.Nodes)
   137  	self.Nodes = append(self.Nodes, node)
   138  
   139  	// emit a "control" event
   140  	self.events.Send(ControlEvent(node))
   141  
   142  	return node, nil
   143  }
   144  
   145  // Config returns the network configuration
   146  func (self *Network) Config() *NetworkConfig {
   147  	return &self.NetworkConfig
   148  }
   149  
   150  // StartAll starts all nodes in the network
   151  func (self *Network) StartAll() error {
   152  	for _, node := range self.Nodes {
   153  		if node.Up {
   154  			continue
   155  		}
   156  		if err := self.Start(node.ID()); err != nil {
   157  			return err
   158  		}
   159  	}
   160  	return nil
   161  }
   162  
   163  // StopAll stops all nodes in the network
   164  func (self *Network) StopAll() error {
   165  	for _, node := range self.Nodes {
   166  		if !node.Up {
   167  			continue
   168  		}
   169  		if err := self.Stop(node.ID()); err != nil {
   170  			return err
   171  		}
   172  	}
   173  	return nil
   174  }
   175  
   176  // Start starts the node with the given ID
   177  func (self *Network) Start(id discover.NodeID) error {
   178  	return self.startWithSnapshots(id, nil)
   179  }
   180  
   181  // startWithSnapshots starts the node with the given ID using the give
   182  // snapshots
   183  func (self *Network) startWithSnapshots(id discover.NodeID, snapshots map[string][]byte) error {
   184  	node := self.GetNode(id)
   185  	if node == nil {
   186  		return fmt.Errorf("node %v does not exist", id)
   187  	}
   188  	if node.Up {
   189  		return fmt.Errorf("node %v already up", id)
   190  	}
   191  	log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name()))
   192  	if err := node.Start(snapshots); err != nil {
   193  		log.Warn(fmt.Sprintf("start up failed: %v", err))
   194  		return err
   195  	}
   196  	node.Up = true
   197  	log.Info(fmt.Sprintf("started node %v: %v", id, node.Up))
   198  
   199  	self.events.Send(NewEvent(node))
   200  
   201  	// subscribe to peer events
   202  	client, err := node.Client()
   203  	if err != nil {
   204  		return fmt.Errorf("error getting rpc client  for node %v: %s", id, err)
   205  	}
   206  	events := make(chan *p2p.PeerEvent)
   207  	sub, err := client.Subscribe(context.Background(), "admin", events, "peerEvents")
   208  	if err != nil {
   209  		return fmt.Errorf("error getting peer events for node %v: %s", id, err)
   210  	}
   211  	go self.watchPeerEvents(id, events, sub)
   212  	return nil
   213  }
   214  
   215  // watchPeerEvents reads peer events from the given channel and emits
   216  // corresponding network events
   217  func (self *Network) watchPeerEvents(id discover.NodeID, events chan *p2p.PeerEvent, sub event.Subscription) {
   218  	defer func() {
   219  		sub.Unsubscribe()
   220  
   221  		// assume the node is now down
   222  		self.lock.Lock()
   223  		node := self.getNode(id)
   224  		node.Up = false
   225  		self.lock.Unlock()
   226  		self.events.Send(NewEvent(node))
   227  	}()
   228  	for {
   229  		select {
   230  		case event, ok := <-events:
   231  			if !ok {
   232  				return
   233  			}
   234  			peer := event.Peer
   235  			switch event.Type {
   236  
   237  			case p2p.PeerEventTypeAdd:
   238  				self.DidConnect(id, peer)
   239  
   240  			case p2p.PeerEventTypeDrop:
   241  				self.DidDisconnect(id, peer)
   242  
   243  			case p2p.PeerEventTypeMsgSend:
   244  				self.DidSend(id, peer, event.Protocol, *event.MsgCode)
   245  
   246  			case p2p.PeerEventTypeMsgRecv:
   247  				self.DidReceive(peer, id, event.Protocol, *event.MsgCode)
   248  
   249  			}
   250  
   251  		case err := <-sub.Err():
   252  			if err != nil {
   253  				log.Error(fmt.Sprintf("error getting peer events for node %v", id), "err", err)
   254  			}
   255  			return
   256  		}
   257  	}
   258  }
   259  
   260  // Stop stops the node with the given ID
   261  func (self *Network) Stop(id discover.NodeID) error {
   262  	node := self.GetNode(id)
   263  	if node == nil {
   264  		return fmt.Errorf("node %v does not exist", id)
   265  	}
   266  	if !node.Up {
   267  		return fmt.Errorf("node %v already down", id)
   268  	}
   269  	if err := node.Stop(); err != nil {
   270  		return err
   271  	}
   272  	node.Up = false
   273  	log.Info(fmt.Sprintf("stop node %v: %v", id, node.Up))
   274  
   275  	self.events.Send(ControlEvent(node))
   276  	return nil
   277  }
   278  
   279  // Connect connects two nodes together by calling the "admin_addPeer" RPC
   280  // method on the "one" node so that it connects to the "other" node
   281  func (self *Network) Connect(oneID, otherID discover.NodeID) error {
   282  	log.Debug(fmt.Sprintf("connecting %s to %s", oneID, otherID))
   283  	conn, err := self.InitConn(oneID, otherID)
   284  	if err != nil {
   285  		return err
   286  	}
   287  	client, err := conn.one.Client()
   288  	if err != nil {
   289  		return err
   290  	}
   291  	self.events.Send(ControlEvent(conn))
   292  	return client.Call(nil, "admin_addPeer", string(conn.other.Addr()))
   293  }
   294  
   295  // Disconnect disconnects two nodes by calling the "admin_removePeer" RPC
   296  // method on the "one" node so that it disconnects from the "other" node
   297  func (self *Network) Disconnect(oneID, otherID discover.NodeID) error {
   298  	conn := self.GetConn(oneID, otherID)
   299  	if conn == nil {
   300  		return fmt.Errorf("connection between %v and %v does not exist", oneID, otherID)
   301  	}
   302  	if !conn.Up() {
   303  		return fmt.Errorf("%v and %v already disconnected", oneID, otherID)
   304  	}
   305  	client, err := conn.one.Client()
   306  	if err != nil {
   307  		return err
   308  	}
   309  	self.events.Send(ControlEvent(conn))
   310  	return client.Call(nil, "admin_removePeer", string(conn.other.Addr()))
   311  }
   312  
   313  // DidConnect tracks the fact that the "one" node connected to the "other" node
   314  func (self *Network) DidConnect(one, other discover.NodeID) error {
   315  	conn, err := self.GetOrCreateConn(one, other)
   316  	if err != nil {
   317  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   318  	}
   319  	if conn.Up() {
   320  		return fmt.Errorf("%v and %v already connected", one, other)
   321  	}
   322  	conn.SetUp(true)
   323  	self.events.Send(NewEvent(conn))
   324  	return nil
   325  }
   326  
   327  // DidDisconnect tracks the fact that the "one" node disconnected from the
   328  // "other" node
   329  func (self *Network) DidDisconnect(one, other discover.NodeID) error {
   330  	conn := self.GetConn(one, other)
   331  	if conn == nil {
   332  		return fmt.Errorf("connection between %v and %v does not exist", one, other)
   333  	}
   334  	if !conn.Up() {
   335  		return fmt.Errorf("%v and %v already disconnected", one, other)
   336  	}
   337  
   338  	conn.mu.Lock()
   339  	conn.up = false
   340  	conn.initiated = time.Now().Add(-dialBanTimeout)
   341  	conn.mu.Unlock()
   342  	self.events.Send(NewEvent(conn))
   343  	return nil
   344  }
   345  
   346  // DidSend tracks the fact that "sender" sent a message to "receiver"
   347  func (self *Network) DidSend(sender, receiver discover.NodeID, proto string, code uint64) error {
   348  	msg := &Msg{
   349  		One:      sender,
   350  		Other:    receiver,
   351  		Protocol: proto,
   352  		Code:     code,
   353  		Received: false,
   354  	}
   355  	self.events.Send(NewEvent(msg))
   356  	return nil
   357  }
   358  
   359  // DidReceive tracks the fact that "receiver" received a message from "sender"
   360  func (self *Network) DidReceive(sender, receiver discover.NodeID, proto string, code uint64) error {
   361  	msg := &Msg{
   362  		One:      sender,
   363  		Other:    receiver,
   364  		Protocol: proto,
   365  		Code:     code,
   366  		Received: true,
   367  	}
   368  	self.events.Send(NewEvent(msg))
   369  	return nil
   370  }
   371  
   372  // GetNode gets the node with the given ID, returning nil if the node does not
   373  // exist
   374  func (self *Network) GetNode(id discover.NodeID) *Node {
   375  	self.lock.Lock()
   376  	defer self.lock.Unlock()
   377  	return self.getNode(id)
   378  }
   379  
   380  // GetNode gets the node with the given name, returning nil if the node does
   381  // not exist
   382  func (self *Network) GetNodeByName(name string) *Node {
   383  	self.lock.Lock()
   384  	defer self.lock.Unlock()
   385  	return self.getNodeByName(name)
   386  }
   387  
   388  func (self *Network) getNode(id discover.NodeID) *Node {
   389  	i, found := self.nodeMap[id]
   390  	if !found {
   391  		return nil
   392  	}
   393  	return self.Nodes[i]
   394  }
   395  
   396  func (self *Network) getNodeByName(name string) *Node {
   397  	for _, node := range self.Nodes {
   398  		if node.Config.Name == name {
   399  			return node
   400  		}
   401  	}
   402  	return nil
   403  }
   404  
   405  // GetNodes returns the existing nodes
   406  func (self *Network) GetNodes() (nodes []*Node) {
   407  	self.lock.Lock()
   408  	defer self.lock.Unlock()
   409  
   410  	nodes = append(nodes, self.Nodes...)
   411  	return nodes
   412  }
   413  
   414  // GetConn returns the connection which exists between "one" and "other"
   415  // regardless of which node initiated the connection
   416  func (self *Network) GetConn(oneID, otherID discover.NodeID) *Conn {
   417  	self.lock.Lock()
   418  	defer self.lock.Unlock()
   419  	return self.getConn(oneID, otherID)
   420  }
   421  
   422  // GetOrCreateConn is like GetConn but creates the connection if it doesn't
   423  // already exist
   424  func (self *Network) GetOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) {
   425  	self.lock.Lock()
   426  	defer self.lock.Unlock()
   427  	return self.getOrCreateConn(oneID, otherID)
   428  }
   429  
   430  func (self *Network) getOrCreateConn(oneID, otherID discover.NodeID) (*Conn, error) {
   431  	if conn := self.getConn(oneID, otherID); conn != nil {
   432  		return conn, nil
   433  	}
   434  
   435  	one := self.getNode(oneID)
   436  	if one == nil {
   437  		return nil, fmt.Errorf("node %v does not exist", oneID)
   438  	}
   439  	other := self.getNode(otherID)
   440  	if other == nil {
   441  		return nil, fmt.Errorf("node %v does not exist", otherID)
   442  	}
   443  	conn := &Conn{
   444  		One:   oneID,
   445  		Other: otherID,
   446  		one:   one,
   447  		other: other,
   448  	}
   449  	label := ConnLabel(oneID, otherID)
   450  	self.connMap[label] = len(self.Conns)
   451  	self.Conns = append(self.Conns, conn)
   452  	return conn, nil
   453  }
   454  
   455  func (self *Network) getConn(oneID, otherID discover.NodeID) *Conn {
   456  	label := ConnLabel(oneID, otherID)
   457  	i, found := self.connMap[label]
   458  	if !found {
   459  		return nil
   460  	}
   461  	return self.Conns[i]
   462  }
   463  
   464  // InitConn(one, other) retrieves the connectiton model for the connection between
   465  // peers one and other, or creates a new one if it does not exist
   466  // the order of nodes does not matter, i.e., Conn(i,j) == Conn(j, i)
   467  // it checks if the connection is already up, and if the nodes are running
   468  // NOTE:
   469  // it also checks whether there has been recent attempt to connect the peers
   470  // this is cheating as the simulation is used as an oracle and know about
   471  // remote peers attempt to connect to a node which will then not initiate the connection
   472  func (self *Network) InitConn(oneID, otherID discover.NodeID) (*Conn, error) {
   473  	self.lock.Lock()
   474  	defer self.lock.Unlock()
   475  	if oneID == otherID {
   476  		return nil, fmt.Errorf("refusing to connect to self %v", oneID)
   477  	}
   478  	conn, err := self.getOrCreateConn(oneID, otherID)
   479  	if err != nil {
   480  		return nil, err
   481  	}
   482  	if time.Since(conn.initiated) < dialBanTimeout {
   483  		return nil, fmt.Errorf("connection between %v and %v recently attempted", oneID, otherID)
   484  	}
   485  	if conn.Up() {
   486  		return nil, fmt.Errorf("%v and %v already connected", oneID, otherID)
   487  	}
   488  	err = conn.nodesUp()
   489  	if err != nil {
   490  		return nil, fmt.Errorf("nodes not up: %v", err)
   491  	}
   492  	conn.mu.Lock()
   493  	conn.initiated = time.Now()
   494  	conn.mu.Unlock()
   495  	return conn, nil
   496  }
   497  
   498  // Shutdown stops all nodes in the network and closes the quit channel
   499  func (self *Network) Shutdown() {
   500  	for _, node := range self.Nodes {
   501  		log.Debug(fmt.Sprintf("stopping node %s", node.ID().TerminalString()))
   502  		if err := node.Stop(); err != nil {
   503  			log.Warn(fmt.Sprintf("error stopping node %s", node.ID().TerminalString()), "err", err)
   504  		}
   505  	}
   506  	close(self.quitc)
   507  }
   508  
   509  //Reset resets all network properties:
   510  //emtpies the nodes and the connection list
   511  func (self *Network) Reset() {
   512  	self.lock.Lock()
   513  	defer self.lock.Unlock()
   514  
   515  	//re-initialize the maps
   516  	self.connMap = make(map[string]int)
   517  	self.nodeMap = make(map[discover.NodeID]int)
   518  
   519  	self.Nodes = nil
   520  	self.Conns = nil
   521  }
   522  
   523  // Node is a wrapper around adapters.Node which is used to track the status
   524  // of a node in the network
   525  type Node struct {
   526  	adapters.Node `json:"-"`
   527  
   528  	// Config if the config used to created the node
   529  	Config *adapters.NodeConfig `json:"config"`
   530  
   531  	// Up tracks whether or not the node is running
   532  	Up bool `json:"up"`
   533  }
   534  
   535  // ID returns the ID of the node
   536  func (self *Node) ID() discover.NodeID {
   537  	return self.Config.ID
   538  }
   539  
   540  // String returns a log-friendly string
   541  func (self *Node) String() string {
   542  	return fmt.Sprintf("Node %v", self.ID().TerminalString())
   543  }
   544  
   545  // NodeInfo returns information about the node
   546  func (self *Node) NodeInfo() *p2p.NodeInfo {
   547  	// avoid a panic if the node is not started yet
   548  	if self.Node == nil {
   549  		return nil
   550  	}
   551  	info := self.Node.NodeInfo()
   552  	info.Name = self.Config.Name
   553  	return info
   554  }
   555  
   556  // MarshalJSON implements the json.Marshaler interface so that the encoded
   557  // JSON includes the NodeInfo
   558  func (self *Node) MarshalJSON() ([]byte, error) {
   559  	return json.Marshal(struct {
   560  		Info   *p2p.NodeInfo        `json:"info,omitempty"`
   561  		Config *adapters.NodeConfig `json:"config,omitempty"`
   562  		Up     bool                 `json:"up"`
   563  	}{
   564  		Info:   self.NodeInfo(),
   565  		Config: self.Config,
   566  		Up:     self.Up,
   567  	})
   568  }
   569  
   570  // Conn represents a connection between two nodes in the network
   571  type Conn struct {
   572  	// One is the node which initiated the connection
   573  	One discover.NodeID
   574  
   575  	// Other is the node which the connection was made to
   576  	Other discover.NodeID
   577  
   578  	one   *Node
   579  	other *Node
   580  
   581  	mu sync.RWMutex
   582  	// Up tracks whether or not the connection is active
   583  	up bool
   584  	// Registers when the connection was grabbed to dial
   585  	initiated time.Time
   586  }
   587  
   588  // nodesUp returns whether both nodes are currently up
   589  func (self *Conn) nodesUp() error {
   590  	if !self.one.Up {
   591  		return fmt.Errorf("one %v is not up", self.One)
   592  	}
   593  	if !self.other.Up {
   594  		return fmt.Errorf("other %v is not up", self.Other)
   595  	}
   596  	return nil
   597  }
   598  
   599  // String returns a log-friendly string
   600  func (self *Conn) String() string {
   601  	return fmt.Sprintf("Conn %v->%v", self.One.TerminalString(), self.Other.TerminalString())
   602  }
   603  
   604  func (self *Conn) Up() bool {
   605  	self.mu.RLock()
   606  	up := self.up
   607  	self.mu.RUnlock()
   608  	return up
   609  }
   610  
   611  func (self *Conn) SetUp(up bool) {
   612  	self.mu.Lock()
   613  	self.up = up
   614  	self.mu.Unlock()
   615  }
   616  
   617  func (self *Conn) MarshalJSON() ([]byte, error) {
   618  	type t struct {
   619  		One   discover.NodeID `json:"one"`
   620  		Other discover.NodeID `json:"other"`
   621  		Up    bool            `json:"up"`
   622  	}
   623  	cp := &t{
   624  		One:   self.One,
   625  		Other: self.Other,
   626  		Up:    self.Up(),
   627  	}
   628  	return json.Marshal(cp)
   629  }
   630  
   631  func (self *Conn) UnmarshalJSON(data []byte) error {
   632  	type t struct {
   633  		One   discover.NodeID `json:"one"`
   634  		Other discover.NodeID `json:"other"`
   635  		Up    bool            `json:"up"`
   636  	}
   637  	var cp t
   638  	err := json.Unmarshal(data, &cp)
   639  	if err != nil {
   640  		return err
   641  	}
   642  	self.One = cp.One
   643  	self.Other = cp.Other
   644  	self.SetUp(cp.Up)
   645  	return nil
   646  }
   647  
   648  // Msg represents a p2p message sent between two nodes in the network
   649  type Msg struct {
   650  	One      discover.NodeID `json:"one"`
   651  	Other    discover.NodeID `json:"other"`
   652  	Protocol string          `json:"protocol"`
   653  	Code     uint64          `json:"code"`
   654  	Received bool            `json:"received"`
   655  }
   656  
   657  // String returns a log-friendly string
   658  func (self *Msg) String() string {
   659  	return fmt.Sprintf("Msg(%d) %v->%v", self.Code, self.One.TerminalString(), self.Other.TerminalString())
   660  }
   661  
   662  // ConnLabel generates a deterministic string which represents a connection
   663  // between two nodes, used to compare if two connections are between the same
   664  // nodes
   665  func ConnLabel(source, target discover.NodeID) string {
   666  	var first, second discover.NodeID
   667  	if bytes.Compare(source.Bytes(), target.Bytes()) > 0 {
   668  		first = target
   669  		second = source
   670  	} else {
   671  		first = source
   672  		second = target
   673  	}
   674  	return fmt.Sprintf("%v-%v", first, second)
   675  }
   676  
   677  // Snapshot represents the state of a network at a single point in time and can
   678  // be used to restore the state of a network
   679  type Snapshot struct {
   680  	Nodes []NodeSnapshot `json:"nodes,omitempty"`
   681  	Conns []Conn         `json:"conns,omitempty"`
   682  }
   683  
   684  // NodeSnapshot represents the state of a node in the network
   685  type NodeSnapshot struct {
   686  	Node Node `json:"node,omitempty"`
   687  
   688  	// Snapshots is arbitrary data gathered from calling node.Snapshots()
   689  	Snapshots map[string][]byte `json:"snapshots,omitempty"`
   690  }
   691  
   692  // Snapshot creates a network snapshot
   693  func (self *Network) Snapshot() (*Snapshot, error) {
   694  	self.lock.Lock()
   695  	defer self.lock.Unlock()
   696  	snap := &Snapshot{
   697  		Nodes: make([]NodeSnapshot, len(self.Nodes)),
   698  		Conns: make([]Conn, len(self.Conns)),
   699  	}
   700  	for i, node := range self.Nodes {
   701  		snap.Nodes[i] = NodeSnapshot{Node: *node}
   702  		if !node.Up {
   703  			continue
   704  		}
   705  		snapshots, err := node.Snapshots()
   706  		if err != nil {
   707  			return nil, err
   708  		}
   709  		snap.Nodes[i].Snapshots = snapshots
   710  	}
   711  	for i, conn := range self.Conns {
   712  		conn.mu.RLock()
   713  		snap.Conns[i] = Conn{
   714  			One:       conn.One,
   715  			Other:     conn.Other,
   716  			one:       conn.one,
   717  			other:     conn.other,
   718  			up:        conn.up,
   719  			initiated: conn.initiated,
   720  		}
   721  		conn.mu.RUnlock()
   722  	}
   723  	return snap, nil
   724  }
   725  
   726  // Load loads a network snapshot
   727  func (self *Network) Load(snap *Snapshot) error {
   728  	for _, n := range snap.Nodes {
   729  		if _, err := self.NewNodeWithConfig(n.Node.Config); err != nil {
   730  			return err
   731  		}
   732  		if !n.Node.Up {
   733  			continue
   734  		}
   735  		if err := self.startWithSnapshots(n.Node.Config.ID, n.Snapshots); err != nil {
   736  			return err
   737  		}
   738  	}
   739  	for _, conn := range snap.Conns {
   740  
   741  		if !self.GetNode(conn.One).Up || !self.GetNode(conn.Other).Up {
   742  			//in this case, at least one of the nodes of a connection is not up,
   743  			//so it would result in the snapshot `Load` to fail
   744  			continue
   745  		}
   746  		if err := self.Connect(conn.One, conn.Other); err != nil {
   747  			return err
   748  		}
   749  	}
   750  	return nil
   751  }
   752  
   753  // Subscribe reads control events from a channel and executes them
   754  func (self *Network) Subscribe(events chan *Event) {
   755  	for {
   756  		select {
   757  		case event, ok := <-events:
   758  			if !ok {
   759  				return
   760  			}
   761  			if event.Control {
   762  				self.executeControlEvent(event)
   763  			}
   764  		case <-self.quitc:
   765  			return
   766  		}
   767  	}
   768  }
   769  
   770  func (self *Network) executeControlEvent(event *Event) {
   771  	log.Trace("execute control event", "type", event.Type, "event", event)
   772  	switch event.Type {
   773  	case EventTypeNode:
   774  		if err := self.executeNodeEvent(event); err != nil {
   775  			log.Error("error executing node event", "event", event, "err", err)
   776  		}
   777  	case EventTypeConn:
   778  		if err := self.executeConnEvent(event); err != nil {
   779  			log.Error("error executing conn event", "event", event, "err", err)
   780  		}
   781  	case EventTypeMsg:
   782  		log.Warn("ignoring control msg event")
   783  	}
   784  }
   785  
   786  func (self *Network) executeNodeEvent(e *Event) error {
   787  	if !e.Node.Up {
   788  		return self.Stop(e.Node.ID())
   789  	}
   790  
   791  	if _, err := self.NewNodeWithConfig(e.Node.Config); err != nil {
   792  		return err
   793  	}
   794  	return self.Start(e.Node.ID())
   795  }
   796  
   797  func (self *Network) executeConnEvent(e *Event) error {
   798  	if e.Conn.Up() {
   799  		return self.Connect(e.Conn.One, e.Conn.Other)
   800  	} else {
   801  		return self.Disconnect(e.Conn.One, e.Conn.Other)
   802  	}
   803  }