github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/simulation/simulation.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:43</date> 10 //</624450114806616064> 11 12 13 package simulation 14 15 import ( 16 "context" 17 "errors" 18 "net/http" 19 "sync" 20 "time" 21 22 "github.com/ethereum/go-ethereum/log" 23 "github.com/ethereum/go-ethereum/node" 24 "github.com/ethereum/go-ethereum/p2p/enode" 25 "github.com/ethereum/go-ethereum/p2p/simulations" 26 "github.com/ethereum/go-ethereum/p2p/simulations/adapters" 27 "github.com/ethereum/go-ethereum/swarm/network" 28 ) 29 30 //此包中的函数返回的常见错误。 31 var ( 32 ErrNodeNotFound = errors.New("node not found") 33 ) 34 35 //仿真提供了网络、节点和服务的方法 36 //管理它们。 37 type Simulation struct { 38 //NET作为一种访问低级功能的方式被公开 39 //P2P/Simulations.Network的。 40 Net *simulations.Network 41 42 serviceNames []string 43 cleanupFuncs []func() 44 buckets map[enode.ID]*sync.Map 45 shutdownWG sync.WaitGroup 46 done chan struct{} 47 mu sync.RWMutex 48 neighbourhoodSize int 49 50 httpSrv *http.Server //通过模拟选项附加HTTP服务器 51 handler *simulations.Server //服务器的HTTP处理程序 52 runC chan struct{} //前端信号准备就绪的通道 53 } 54 55 //servicefunc在new中用于声明新的服务构造函数。 56 //第一个参数提供来自适配器包的ServiceContext 57 //例如对nodeid的访问。第二个参数是sync.map 58 //所有与服务相关的“全局”状态都应该保存在哪里。 59 //施工服务和任何其他施工所需的所有清理 60 //对象应该在单个返回的清理函数中提供。 61 //close函数将调用返回的cleanup函数 62 //网络关闭后。 63 type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) 64 65 //新建创建新的模拟实例 66 //服务映射必须具有唯一的键作为服务名和 67 //每个servicefunc都必须返回一个唯一类型的node.service。 68 //node.node.start()函数需要此限制 69 //用于启动node.servicefunc返回的服务。 70 func New(services map[string]ServiceFunc) (s *Simulation) { 71 s = &Simulation{ 72 buckets: make(map[enode.ID]*sync.Map), 73 done: make(chan struct{}), 74 neighbourhoodSize: network.NewKadParams().NeighbourhoodSize, 75 } 76 77 adapterServices := make(map[string]adapters.ServiceFunc, len(services)) 78 for name, serviceFunc := range services { 79 //正确地确定这个变量的范围 80 //因为它们将出现在稍后访问的adapterservices[name]函数中。 81 name, serviceFunc := name, serviceFunc 82 s.serviceNames = append(s.serviceNames, name) 83 adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) { 84 b := new(sync.Map) 85 service, cleanup, err := serviceFunc(ctx, b) 86 if err != nil { 87 return nil, err 88 } 89 s.mu.Lock() 90 defer s.mu.Unlock() 91 if cleanup != nil { 92 s.cleanupFuncs = append(s.cleanupFuncs, cleanup) 93 } 94 s.buckets[ctx.Config.ID] = b 95 return service, nil 96 } 97 } 98 99 s.Net = simulations.NewNetwork( 100 adapters.NewTCPAdapter(adapterServices), 101 &simulations.NetworkConfig{ID: "0"}, 102 ) 103 104 return s 105 } 106 107 //runfunc是将调用的函数 108 //在Simulation.Run方法调用中。 109 type RunFunc func(context.Context, *Simulation) error 110 111 //结果是Simulation.Run方法的返回值。 112 type Result struct { 113 Duration time.Duration 114 Error error 115 } 116 117 //run在处理时调用runfunc函数 118 //通过上下文提供的取消。 119 func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) { 120 //如果该选项设置为使用模拟运行HTTP服务器, 121 //初始化服务器并启动它 122 start := time.Now() 123 if s.httpSrv != nil { 124 log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)") 125 //等待前端连接 126 select { 127 case <-s.runC: 128 case <-ctx.Done(): 129 return Result{ 130 Duration: time.Since(start), 131 Error: ctx.Err(), 132 } 133 } 134 log.Info("Received signal from frontend - starting simulation run.") 135 } 136 errc := make(chan error) 137 quit := make(chan struct{}) 138 defer close(quit) 139 go func() { 140 select { 141 case errc <- f(ctx, s): 142 case <-quit: 143 } 144 }() 145 var err error 146 select { 147 case <-ctx.Done(): 148 err = ctx.Err() 149 case err = <-errc: 150 } 151 return Result{ 152 Duration: time.Since(start), 153 Error: err, 154 } 155 } 156 157 //对上清理函数的最大并行调用数 158 //模拟关闭。 159 var maxParallelCleanups = 10 160 161 //close调用由返回的所有清理函数 162 //servicefunc,等待它们全部完成 163 //显式阻止shutdownwg的函数 164 //(如Simulation.PeerEvents)并关闭网络 165 //最后。它用于清除 166 //模拟。 167 func (s *Simulation) Close() { 168 close(s.done) 169 170 sem := make(chan struct{}, maxParallelCleanups) 171 s.mu.RLock() 172 cleanupFuncs := make([]func(), len(s.cleanupFuncs)) 173 for i, f := range s.cleanupFuncs { 174 if f != nil { 175 cleanupFuncs[i] = f 176 } 177 } 178 s.mu.RUnlock() 179 var cleanupWG sync.WaitGroup 180 for _, cleanup := range cleanupFuncs { 181 cleanupWG.Add(1) 182 sem <- struct{}{} 183 go func(cleanup func()) { 184 defer cleanupWG.Done() 185 defer func() { <-sem }() 186 187 cleanup() 188 }(cleanup) 189 } 190 cleanupWG.Wait() 191 192 if s.httpSrv != nil { 193 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) 194 defer cancel() 195 err := s.httpSrv.Shutdown(ctx) 196 if err != nil { 197 log.Error("Error shutting down HTTP server!", "err", err) 198 } 199 close(s.runC) 200 } 201 202 s.shutdownWG.Wait() 203 s.Net.Shutdown() 204 } 205 206 //完成返回模拟时关闭的通道 207 //用Close方法关闭。它对信号终端很有用 208 //在测试中创建的所有可能的goroutine中。 209 func (s *Simulation) Done() <-chan struct{} { 210 return s.done 211 } 212