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 }