github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/p2p/simulations/examples/ping-pong.go (about)

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