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 }