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 }