github.com/phillinzzz/newBsc@v1.1.6/p2p/simulations/examples/ping-pong.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 main 18 19 import ( 20 "flag" 21 "fmt" 22 "io/ioutil" 23 "net/http" 24 "os" 25 "sync/atomic" 26 "time" 27 28 "github.com/phillinzzz/newBsc/common/gopool" 29 "github.com/phillinzzz/newBsc/log" 30 "github.com/phillinzzz/newBsc/node" 31 "github.com/phillinzzz/newBsc/p2p" 32 "github.com/phillinzzz/newBsc/p2p/enode" 33 "github.com/phillinzzz/newBsc/p2p/simulations" 34 "github.com/phillinzzz/newBsc/p2p/simulations/adapters" 35 ) 36 37 var adapterType = flag.String("adapter", "sim", `node adapter to use (one of "sim", "exec" or "docker")`) 38 39 // main() starts a simulation network which contains nodes running a simple 40 // ping-pong protocol 41 func main() { 42 flag.Parse() 43 44 // set the log level to Trace 45 log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 46 47 // register a single ping-pong service 48 services := map[string]adapters.LifecycleConstructor{ 49 "ping-pong": func(ctx *adapters.ServiceContext, stack *node.Node) (node.Lifecycle, error) { 50 pps := newPingPongService(ctx.Config.ID) 51 stack.RegisterProtocols(pps.Protocols()) 52 return pps, nil 53 }, 54 } 55 adapters.RegisterLifecycles(services) 56 57 // create the NodeAdapter 58 var adapter adapters.NodeAdapter 59 60 switch *adapterType { 61 62 case "sim": 63 log.Info("using sim adapter") 64 adapter = adapters.NewSimAdapter(services) 65 66 case "exec": 67 tmpdir, err := ioutil.TempDir("", "p2p-example") 68 if err != nil { 69 log.Crit("error creating temp dir", "err", err) 70 } 71 defer os.RemoveAll(tmpdir) 72 log.Info("using exec adapter", "tmpdir", tmpdir) 73 adapter = adapters.NewExecAdapter(tmpdir) 74 75 default: 76 log.Crit(fmt.Sprintf("unknown node adapter %q", *adapterType)) 77 } 78 79 // start the HTTP API 80 log.Info("starting simulation server on 0.0.0.0:8888...") 81 network := simulations.NewNetwork(adapter, &simulations.NetworkConfig{ 82 DefaultService: "ping-pong", 83 }) 84 if err := http.ListenAndServe(":8888", simulations.NewServer(network)); err != nil { 85 log.Crit("error starting simulation server", "err", err) 86 } 87 } 88 89 // pingPongService runs a ping-pong protocol between nodes where each node 90 // sends a ping to all its connected peers every 10s and receives a pong in 91 // return 92 type pingPongService struct { 93 id enode.ID 94 log log.Logger 95 received int64 96 } 97 98 func newPingPongService(id enode.ID) *pingPongService { 99 return &pingPongService{ 100 id: id, 101 log: log.New("node.id", id), 102 } 103 } 104 105 func (p *pingPongService) Protocols() []p2p.Protocol { 106 return []p2p.Protocol{{ 107 Name: "ping-pong", 108 Version: 1, 109 Length: 2, 110 Run: p.Run, 111 NodeInfo: p.Info, 112 }} 113 } 114 115 func (p *pingPongService) Start() error { 116 p.log.Info("ping-pong service starting") 117 return nil 118 } 119 120 func (p *pingPongService) Stop() error { 121 p.log.Info("ping-pong service stopping") 122 return nil 123 } 124 125 func (p *pingPongService) Info() interface{} { 126 return struct { 127 Received int64 `json:"received"` 128 }{ 129 atomic.LoadInt64(&p.received), 130 } 131 } 132 133 const ( 134 pingMsgCode = iota 135 pongMsgCode 136 ) 137 138 // Run implements the ping-pong protocol which sends ping messages to the peer 139 // at 10s intervals, and responds to pings with pong messages. 140 func (p *pingPongService) Run(peer *p2p.Peer, rw p2p.MsgReadWriter) error { 141 log := p.log.New("peer.id", peer.ID()) 142 143 errC := make(chan error) 144 gopool.Submit(func() { 145 for range time.Tick(10 * time.Second) { 146 log.Info("sending ping") 147 if err := p2p.Send(rw, pingMsgCode, "PING"); err != nil { 148 errC <- err 149 return 150 } 151 } 152 }) 153 gopool.Submit(func() { 154 for { 155 msg, err := rw.ReadMsg() 156 if err != nil { 157 errC <- err 158 return 159 } 160 payload, err := ioutil.ReadAll(msg.Payload) 161 if err != nil { 162 errC <- err 163 return 164 } 165 log.Info("received message", "msg.code", msg.Code, "msg.payload", string(payload)) 166 atomic.AddInt64(&p.received, 1) 167 if msg.Code == pingMsgCode { 168 log.Info("sending pong") 169 gopool.Submit(func() { p2p.Send(rw, pongMsgCode, "PONG") }) 170 } 171 } 172 }) 173 return <-errC 174 }