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

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