github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/network/simulation/simulation.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //
    10  //
    11  //
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  
    25  package simulation
    26  
    27  import (
    28  	"context"
    29  	"errors"
    30  	"net/http"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/log"
    35  	"github.com/ethereum/go-ethereum/node"
    36  	"github.com/ethereum/go-ethereum/p2p/discover"
    37  	"github.com/ethereum/go-ethereum/p2p/simulations"
    38  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    39  )
    40  
    41  //
    42  var (
    43  	ErrNodeNotFound = errors.New("node not found")
    44  	ErrNoPivotNode  = errors.New("no pivot node set")
    45  )
    46  
    47  //
    48  //
    49  type Simulation struct {
    50  //
    51  //
    52  	Net *simulations.Network
    53  
    54  	serviceNames []string
    55  	cleanupFuncs []func()
    56  	buckets      map[discover.NodeID]*sync.Map
    57  	pivotNodeID  *discover.NodeID
    58  	shutdownWG   sync.WaitGroup
    59  	done         chan struct{}
    60  	mu           sync.RWMutex
    61  
    62  httpSrv *http.Server        //
    63  handler *simulations.Server //
    64  runC    chan struct{}       //
    65  }
    66  
    67  //
    68  //
    69  //
    70  //
    71  //
    72  //
    73  //
    74  //
    75  type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error)
    76  
    77  //
    78  //
    79  func New(services map[string]ServiceFunc) (s *Simulation) {
    80  	s = &Simulation{
    81  		buckets: make(map[discover.NodeID]*sync.Map),
    82  		done:    make(chan struct{}),
    83  	}
    84  
    85  	adapterServices := make(map[string]adapters.ServiceFunc, len(services))
    86  	for name, serviceFunc := range services {
    87  		s.serviceNames = append(s.serviceNames, name)
    88  		adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) {
    89  			b := new(sync.Map)
    90  			service, cleanup, err := serviceFunc(ctx, b)
    91  			if err != nil {
    92  				return nil, err
    93  			}
    94  			s.mu.Lock()
    95  			defer s.mu.Unlock()
    96  			if cleanup != nil {
    97  				s.cleanupFuncs = append(s.cleanupFuncs, cleanup)
    98  			}
    99  			s.buckets[ctx.Config.ID] = b
   100  			return service, nil
   101  		}
   102  	}
   103  
   104  	s.Net = simulations.NewNetwork(
   105  		adapters.NewSimAdapter(adapterServices),
   106  		&simulations.NetworkConfig{ID: "0"},
   107  	)
   108  
   109  	return s
   110  }
   111  
   112  //
   113  //
   114  type RunFunc func(context.Context, *Simulation) error
   115  
   116  //
   117  type Result struct {
   118  	Duration time.Duration
   119  	Error    error
   120  }
   121  
   122  //
   123  //
   124  func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) {
   125  //
   126  //
   127  	start := time.Now()
   128  	if s.httpSrv != nil {
   129  		log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)")
   130  //
   131  		select {
   132  		case <-s.runC:
   133  		case <-ctx.Done():
   134  			return Result{
   135  				Duration: time.Since(start),
   136  				Error:    ctx.Err(),
   137  			}
   138  		}
   139  		log.Info("Received signal from frontend - starting simulation run.")
   140  	}
   141  	errc := make(chan error)
   142  	quit := make(chan struct{})
   143  	defer close(quit)
   144  	go func() {
   145  		select {
   146  		case errc <- f(ctx, s):
   147  		case <-quit:
   148  		}
   149  	}()
   150  	var err error
   151  	select {
   152  	case <-ctx.Done():
   153  		err = ctx.Err()
   154  	case err = <-errc:
   155  	}
   156  	return Result{
   157  		Duration: time.Since(start),
   158  		Error:    err,
   159  	}
   160  }
   161  
   162  //
   163  //
   164  var maxParallelCleanups = 10
   165  
   166  //
   167  //
   168  //
   169  //
   170  //
   171  //
   172  func (s *Simulation) Close() {
   173  	close(s.done)
   174  
   175  //
   176  //
   177  //
   178  	for _, c := range s.Net.Conns {
   179  		if c.Up {
   180  			s.Net.Disconnect(c.One, c.Other)
   181  		}
   182  	}
   183  	s.shutdownWG.Wait()
   184  	s.Net.Shutdown()
   185  
   186  	sem := make(chan struct{}, maxParallelCleanups)
   187  	s.mu.RLock()
   188  	cleanupFuncs := make([]func(), len(s.cleanupFuncs))
   189  	for i, f := range s.cleanupFuncs {
   190  		if f != nil {
   191  			cleanupFuncs[i] = f
   192  		}
   193  	}
   194  	s.mu.RUnlock()
   195  	var cleanupWG sync.WaitGroup
   196  	for _, cleanup := range cleanupFuncs {
   197  		cleanupWG.Add(1)
   198  		sem <- struct{}{}
   199  		go func(cleanup func()) {
   200  			defer cleanupWG.Done()
   201  			defer func() { <-sem }()
   202  
   203  			cleanup()
   204  		}(cleanup)
   205  	}
   206  	cleanupWG.Wait()
   207  
   208  	if s.httpSrv != nil {
   209  		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
   210  		defer cancel()
   211  		err := s.httpSrv.Shutdown(ctx)
   212  		if err != nil {
   213  			log.Error("Error shutting down HTTP server!", "err", err)
   214  		}
   215  		close(s.runC)
   216  	}
   217  }
   218  
   219  //
   220  //
   221  //
   222  func (s *Simulation) Done() <-chan struct{} {
   223  	return s.done
   224  }