example_test.go raw

   1  package peer_test
   2  
   3  import (
   4  	"fmt"
   5  	"github.com/p9c/p9/pkg/log"
   6  	"github.com/p9c/p9/version"
   7  	"net"
   8  	"time"
   9  	
  10  	"github.com/p9c/p9/pkg/qu"
  11  	
  12  	"github.com/p9c/p9/pkg/chaincfg"
  13  	"github.com/p9c/p9/pkg/peer"
  14  	"github.com/p9c/p9/pkg/wire"
  15  )
  16  
  17  var subsystem = log.AddLoggerSubsystem(version.PathBase)
  18  var F, E, W, I, D, T log.LevelPrinter = log.GetLogPrinterSet(subsystem)
  19  
  20  // mockRemotePeer creates a basic inbound peer listening on the simnet port for use with Example_peerConnection. It does
  21  // not return until the listner is active.
  22  func mockRemotePeer() (e error) {
  23  	// Configure peer to act as a simnet node that offers no services.
  24  	peerCfg := &peer.Config{
  25  		UserAgentName:    "peer",  // User agent name to advertise.
  26  		UserAgentVersion: "1.0.0", // User agent version to advertise.
  27  		ChainParams:      &chaincfg.SimNetParams,
  28  		TrickleInterval:  time.Second * 10,
  29  	}
  30  	// Accept connections on the simnet port.
  31  	listener, e := net.Listen("tcp", "127.0.0.1:18555")
  32  	if e != nil {
  33  		return e
  34  	}
  35  	go func() {
  36  		conn, e := listener.Accept()
  37  		if e != nil {
  38  			E.F("Accept: error %v", e)
  39  			return
  40  		}
  41  		// Create and start the inbound peer.
  42  		p := peer.NewInboundPeer(peerCfg)
  43  		p.AssociateConnection(conn)
  44  	}()
  45  	return nil
  46  }
  47  
  48  // This example demonstrates the basic process for initializing and creating an outbound peer. Peers negotiate by
  49  // exchanging version and verack messages. For demonstration, a simple handler for version message is attached to the
  50  // peer.
  51  func Example_newOutboundPeer() {
  52  	// Ordinarily this will not be needed since the outbound peer will be connecting to a remote peer, however, since this example is executed and tested, a mock remote peer is needed to listen for the outbound peer.
  53  	if e := mockRemotePeer(); E.Chk(e) {
  54  		E.F("mockRemotePeer: unexpected error %v", e)
  55  		return
  56  	}
  57  	// Create an outbound peer that is configured to act as a simnet node that offers no services and has listeners for the version and verack messages.  The verack listener is used here to signal the code below when the handshake has been finished by signalling a channel.
  58  	verack := qu.T()
  59  	peerCfg := &peer.Config{
  60  		UserAgentName:    "peer",  // User agent name to advertise.
  61  		UserAgentVersion: "1.0.0", // User agent version to advertise.
  62  		ChainParams:      &chaincfg.SimNetParams,
  63  		Services:         0,
  64  		TrickleInterval:  time.Second * 10,
  65  		Listeners: peer.MessageListeners{
  66  			OnVersion: func(p *peer.Peer, msg *wire.MsgVersion) *wire.MsgReject {
  67  				fmt.Println("outbound: received version")
  68  				return nil
  69  			},
  70  			OnVerAck: func(p *peer.Peer, msg *wire.MsgVerAck) {
  71  				verack <- struct{}{}
  72  			},
  73  		},
  74  	}
  75  	p, e := peer.NewOutboundPeer(peerCfg, "127.0.0.1:18555")
  76  	if e != nil {
  77  		E.F("NewOutboundPeer: error %v", e)
  78  		return
  79  	}
  80  	// Establish the connection to the peer address and mark it connected.
  81  	conn, e := net.Dial("tcp", p.Addr())
  82  	if e != nil {
  83  		E.F("net.Dial: error %v", e)
  84  		return
  85  	}
  86  	p.AssociateConnection(conn)
  87  	// Wait for the verack message or timeout in case of failure.
  88  	select {
  89  	case <-verack.Wait():
  90  	case <-time.After(time.Second * 1):
  91  		E.F("Example_peerConnection: verack timeout")
  92  	}
  93  	// Disconnect the peer.
  94  	p.Disconnect()
  95  	p.WaitForDisconnect()
  96  	// Output:
  97  	// outbound: received version
  98  }
  99