github.com/igggame/nebulas-go@v2.1.0+incompatible/net/testing/seed/main.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"encoding/hex"
     8  	"fmt"
     9  	"log"
    10  	"time"
    11  
    12  	crypto "github.com/libp2p/go-libp2p-crypto"
    13  	host "github.com/libp2p/go-libp2p-host"
    14  	inet "github.com/libp2p/go-libp2p-net"
    15  	peer "github.com/libp2p/go-libp2p-peer"
    16  	ps "github.com/libp2p/go-libp2p-peerstore"
    17  	swarm "github.com/libp2p/go-libp2p-swarm"
    18  	ma "github.com/multiformats/go-multiaddr"
    19  
    20  	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
    21  	multicodec "github.com/multiformats/go-multicodec"
    22  	json "github.com/multiformats/go-multicodec/json"
    23  )
    24  
    25  const proto = "/example/1.0.0"
    26  
    27  // Message is a serializable/encodable object that we will send
    28  // on a Stream.
    29  type Message struct {
    30  	Msg    string
    31  	Index  int
    32  	HangUp bool
    33  }
    34  
    35  // WrappedStream wraps a libp2p stream. We encode/decode whenever we
    36  // write/read from a stream, so we can just carry the encoders
    37  // and bufios with us
    38  type WrappedStream struct {
    39  	stream inet.Stream
    40  	enc    multicodec.Encoder
    41  	dec    multicodec.Decoder
    42  	w      *bufio.Writer
    43  	r      *bufio.Reader
    44  }
    45  
    46  // WrapStream takes a stream and complements it with r/w bufios and
    47  // decoder/encoder. In order to write raw data to the stream we can use
    48  // wrap.w.Write(). To encode something into it we can wrap.enc.Encode().
    49  // Finally, we should wrap.w.Flush() to actually send the data. Handling
    50  // incoming data works similarly with wrap.r.Read() for raw-reading and
    51  // wrap.dec.Decode() to decode.
    52  func WrapStream(s inet.Stream) *WrappedStream {
    53  	reader := bufio.NewReader(s)
    54  	writer := bufio.NewWriter(s)
    55  	// This is where we pick our specific multicodec. In order to change the
    56  	// codec, we only need to change this place.
    57  	// See https://godoc.org/github.com/multiformats/go-multicodec/json
    58  	dec := json.Multicodec(false).Decoder(reader)
    59  	enc := json.Multicodec(false).Encoder(writer)
    60  	return &WrappedStream{
    61  		stream: s,
    62  		r:      reader,
    63  		w:      writer,
    64  		enc:    enc,
    65  		dec:    dec,
    66  	}
    67  }
    68  
    69  // messages that will be sent between the hosts.
    70  var conversationMsgs = []string{
    71  	"Hello!",
    72  	"Hey!",
    73  	"How are you doing?",
    74  	"Very good! It is great that you can send data on a stream to me!",
    75  	"Not only that, the data is encoded in a JSON object.",
    76  	"Yeah, and we are using the multicodecs interface to encode and decode.",
    77  	"This way we could swap it easily for, say, cbor, or msgpack!",
    78  	"Let's leave that as an excercise for the reader...",
    79  	"Agreed, our last message should activate the HangUp flag",
    80  	"Yes, and the example code will close streams. So sad :(. Bye!",
    81  }
    82  
    83  func makeRandomHost(port int) host.Host {
    84  	// Ignoring most errors for brevity
    85  	// See echo example for more details and better implementation
    86  	// priv, pub, _ := crypto.GenerateKeyPair(crypto.RSA, 2048)
    87  	randseed, _ := hex.DecodeString("0123456789ABCDEF0123456789ABCDE10123456789ABCDEF0123456789ABCDEF")
    88  	priv, pub, _ := crypto.GenerateEd25519Key(
    89  		bytes.NewReader(randseed),
    90  	)
    91  	pid, _ := peer.IDFromPublicKey(pub)
    92  	log.Println(pid.Pretty())
    93  	listen, _ := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))
    94  	ps := ps.NewPeerstore()
    95  	ps.AddPrivKey(pid, priv)
    96  	ps.AddPubKey(pid, pub)
    97  	n, _ := swarm.NewNetwork(context.Background(),
    98  		[]ma.Multiaddr{listen}, pid, ps, nil)
    99  	return bhost.New(n)
   100  }
   101  
   102  func main() {
   103  
   104  	// Choose random ports between 10000-10100
   105  	// rand.Seed(666)
   106  	// port1 := rand.Intn(100) + 10000
   107  	// port2 := port1 + 1
   108  
   109  	// Make 2 hosts
   110  	// h1 := makeRandomHost(port1)
   111  	h := makeRandomHost(51413)
   112  
   113  	// bootAddr, bootID, err := p2p.ParseAddressFromMultiaddr("/ip4/127.0.0.1/tcp/51413/ipfs/QmPyr4ZbDmwF1nWxymTktdzspcBFPL6X1v3Q5nT7PGNtUN")
   114  	// // h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), ps.PermanentAddrTTL)
   115  	// h.Peerstore().AddAddrs(bootID, bootAddr, ps.PermanentAddrTTL)
   116  
   117  	// log.Printf("This is a conversation between %s and %s\n", h1.ID(), h2.ID())
   118  
   119  	// Define a stream handler for host number 2
   120  	h.SetStreamHandler(proto, func(stream inet.Stream) {
   121  		// wrappedStream := WrapStream(stream)
   122  		log.Println("start")
   123  		stream.Close()
   124  		log.Println("end")
   125  		// handleStream(wrappedStream)
   126  	})
   127  
   128  	select {}
   129  	// Create new stream from h1 to h2 and start the conversation
   130  	// start := time.Now().Unix()
   131  	// stream, err := h1.NewStream(context.Background(), bootID, proto)
   132  	// log.Error("HelloPerf", time.Now().Unix()-start, "err", err)
   133  	// if err != nil {
   134  	// 	log.Fatal(err)
   135  	// }
   136  	// wrappedStream := WrapStream(stream)
   137  	// // This sends the first message
   138  	// sendMessage(0, wrappedStream)
   139  	// // We keep the conversation on the created stream so we launch
   140  	// // this to handle any responses
   141  	// handleStream(wrappedStream)
   142  	// // When we are done, close the stream on our side and exit.
   143  	// stream.Close()
   144  	// c := make(chan os.Signal, 1)
   145  	// signal.Notify(c, os.Interrupt, syscall.SIGTERM)
   146  	// go func() {
   147  	// 	<-c
   148  	// 	// When we are done, close the stream on our side and exit.
   149  	// 	stream.Close()
   150  
   151  	// 	// TODO: remove this once p2pManager handles stop properly.
   152  	// 	os.Exit(1)
   153  	// }()
   154  }
   155  
   156  // receiveMessage reads and decodes a message from the stream
   157  func receiveMessage(ws *WrappedStream) (*Message, error) {
   158  	var msg Message
   159  	err := ws.dec.Decode(&msg)
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  	return &msg, nil
   164  }
   165  
   166  // sendMessage encodes and writes a message to the stream
   167  func sendMessage(index int, ws *WrappedStream) error {
   168  	msg := &Message{
   169  		Msg:    conversationMsgs[index],
   170  		Index:  index,
   171  		HangUp: index >= len(conversationMsgs)-1,
   172  	}
   173  
   174  	err := ws.enc.Encode(msg)
   175  	// Because output is buffered with bufio, we need to flush!
   176  	ws.w.Flush()
   177  	return err
   178  }
   179  
   180  // handleStream is a for loop which receives and then sends a message
   181  // an artificial delay of 500ms happens in-between.
   182  // When Message.HangUp is true, it exists. This will close the stream
   183  // on one of the sides. The other side's receiveMessage() will error
   184  // with EOF, thus also breaking out from the loop.
   185  func handleStream(ws *WrappedStream) {
   186  	for {
   187  		// Read
   188  		msg, err := receiveMessage(ws)
   189  		if err != nil {
   190  			break
   191  		}
   192  		pid := ws.stream.Conn().LocalPeer()
   193  		log.Printf("%s says: %s\n", pid, msg.Msg)
   194  		time.Sleep(500 * time.Millisecond)
   195  		if msg.HangUp {
   196  			break
   197  		}
   198  		// Send response
   199  		err = sendMessage(msg.Index+1, ws)
   200  		if err != nil {
   201  			break
   202  		}
   203  	}
   204  }