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