func singleConn(t *testing.T, tr pst.Transport) echoSetup { swarm := ps.NewSwarm(tr) swarm.SetStreamHandler(func(s *ps.Stream) { defer s.Close() log("accepted stream") io.Copy(s, s) // echo everything log("closing stream") }) log("listening at %s", "localhost:0") l, err := net.Listen("tcp", "localhost:0") checkErr(t, err) _, err = swarm.AddListener(l) checkErr(t, err) log("dialing to %s", l.Addr()) nc1, err := net.Dial("tcp", l.Addr().String()) checkErr(t, err) c1, err := swarm.AddConn(nc1) checkErr(t, err) return echoSetup{ swarm: swarm, conns: []*ps.Conn{c1}, } }
// NewSwarm constructs a Swarm, with a Chan. func NewSwarm(ctx context.Context, listenAddrs []ma.Multiaddr, local peer.ID, peers peer.Peerstore, bwc metrics.Reporter) (*Swarm, error) { listenAddrs, err := filterAddrs(listenAddrs) if err != nil { return nil, err } s := &Swarm{ swarm: ps.NewSwarm(PSTransport), local: local, peers: peers, ctx: ctx, dialT: DialTimeout, notifs: make(map[inet.Notifiee]ps.Notifiee), bwc: bwc, Filters: filter.NewFilters(), } // configure Swarm s.proc = goprocessctx.WithContextAndTeardown(ctx, s.teardown) s.SetConnHandler(nil) // make sure to setup our own conn handler. // setup swarm metrics prom.MustRegisterOrGet(peersTotal) s.Notify((*metricsNotifiee)(s)) return s, s.listen(listenAddrs) }
func main() { // create a new Swarm swarm := ps.NewSwarm(pstss.Transport) defer swarm.Close() // tell swarm what to do with a new incoming streams. // EchoHandler just echos back anything they write. swarm.SetStreamHandler(ps.EchoHandler) l, err := net.Listen("tcp", "localhost:8001") if err != nil { die(err) } if _, err := swarm.AddListener(l); err != nil { die(err) } nc, err := net.Dial("tcp", "localhost:8001") if err != nil { die(err) } c, err := swarm.AddConn(nc) if err != nil { die(err) } nRcvStream := 0 bio := bufio.NewReader(os.Stdin) swarm.SetStreamHandler(func(s *ps.Stream) { log("handling new stream %d", nRcvStream) nRcvStream++ line, err := bio.ReadString('\n') if err != nil { die(err) } _ = line // line = "read: " + line // s.Write([]byte(line)) s.Close() }) nSndStream := 0 for { <-time.After(200 * time.Millisecond) _, err := swarm.NewStreamWithConn(c) if err != nil { die(err) } log("sender got new stream %d", nSndStream) nSndStream++ } }
func SubtestSimpleWrite(t *testing.T, tr pst.Transport) { swarm := ps.NewSwarm(tr) defer swarm.Close() piper, pipew := io.Pipe() swarm.SetStreamHandler(func(s *ps.Stream) { defer s.Close() log("accepted stream") w := io.MultiWriter(s, pipew) io.Copy(w, s) // echo everything and write it to pipew log("closing stream") }) log("listening at %s", "localhost:0") l, err := net.Listen("tcp", "localhost:0") checkErr(t, err) _, err = swarm.AddListener(l) checkErr(t, err) log("dialing to %s", l.Addr().String()) nc1, err := net.Dial("tcp", l.Addr().String()) checkErr(t, err) c1, err := swarm.AddConn(nc1) checkErr(t, err) defer c1.Close() log("creating stream") s1, err := c1.NewStream() checkErr(t, err) defer s1.Close() buf1 := randBuf(4096) log("writing %d bytes to stream", len(buf1)) _, err = s1.Write(buf1) checkErr(t, err) buf2 := make([]byte, len(buf1)) log("reading %d bytes from stream (echoed)", len(buf2)) _, err = s1.Read(buf2) checkErr(t, err) if string(buf2) != string(buf1) { t.Error("buf1 and buf2 not equal: %s != %s", string(buf1), string(buf2)) } buf3 := make([]byte, len(buf1)) log("reading %d bytes from pipe (tee)", len(buf3)) _, err = piper.Read(buf3) checkErr(t, err) if string(buf3) != string(buf1) { t.Error("buf1 and buf3 not equal: %s != %s", string(buf1), string(buf3)) } }
func makeSwarm(t *testing.T, tr pst.Transport, nListeners int) *ps.Swarm { swarm := ps.NewSwarm(tr) swarm.SetStreamHandler(func(s *ps.Stream) { defer s.Close() log("accepted stream") io.Copy(s, s) // echo everything log("closing stream") }) for i := 0; i < nListeners; i++ { log("%p listening at %s", swarm, "localhost:0") l, err := net.Listen("tcp", "localhost:0") checkErr(t, err) _, err = swarm.AddListener(l) checkErr(t, err) } return swarm }
func main() { // create a new Swarm log("creating a new swarm with spdystream transport") swarm := ps.NewSwarm(pstss.Transport) defer swarm.Close() // tell swarm what to do with a new incoming streams. // EchoHandler just echos back anything they write. log("setup EchoHandler") swarm.SetStreamHandler(ps.EchoHandler) // Okay, let's try listening on some transports log("listening at localhost:8001") l1, err := net.Listen("tcp", "localhost:8001") if err != nil { panic(err) } log("listening at localhost:8002") l2, err := net.Listen("tcp", "localhost:8002") if err != nil { panic(err) } // tell swarm to accept incoming connections on these // listeners. Swarm will start accepting new connections. if _, err := swarm.AddListener(l1); err != nil { panic(err) } if _, err := swarm.AddListener(l2); err != nil { panic(err) } // ok, let's try some outgoing connections log("dialing localhost:8001") nc1, err := net.Dial("tcp", "localhost:8001") if err != nil { panic(err) } log("dialing localhost:8002") nc2, err := net.Dial("tcp", "localhost:8002") if err != nil { panic(err) } // add them to the swarm c1, err := swarm.AddConn(nc1) if err != nil { panic(err) } c2, err := swarm.AddConn(nc2) if err != nil { panic(err) } // Swarm treats listeners as sources of new connections and does // not distinguish between outgoing or incoming connections. // It provides the net.Conn to the StreamHandler so you can // distinguish between them however you wish. // now let's try opening some streams! // You can specify what connection you want to use log("opening stream with NewStreamWithConn(c1)") s1, err := swarm.NewStreamWithConn(c1) if err != nil { panic(err) } // Or, you can specify a SelectConn function that picks between all // (it calls NewStreamWithConn underneath the hood) log("opening stream with NewStreamSelectConn(.)") s2, err := swarm.NewStreamSelectConn(func(conns []*ps.Conn) *ps.Conn { if len(conns) > 0 { return conns[0] } return nil }) if err != nil { panic(err) } // Or, you can bind connections to ConnGroup ids. You can bind a conn to // multiple groups. And, if conn wasn't in swarm, it calls swarm.AddConn. // You can use any Go `KeyType` as a group A `KeyType` as in maps...) swarm.AddConnToGroup(c2, 1) // And then use that group to select a connection. Swarm will use any // connection it finds in that group, using a SelectConn you can rebind: // swarm.SetGroupSelectConn(1, SelectConn) // swarm.SetDegaultGroupSelectConn(SelectConn) log("opening stream with NewStreamWithGroup(1)") s3, err := swarm.NewStreamWithGroup(1) if err != nil { panic(err) } // Why groups? It's because with many connections, and many transports, // and many Servers (or Protocols), we can use the Swarm to associate // a different StreamHandlers per group, and to let us create NewStreams // on a given group. // Ok, we have streams. now what. Use them! Our Streams are basically // streams from github.com/docker/spdystream, so they work the same // way: log("preparing the streams") for i, stream := range []*ps.Stream{s1, s2, s3} { str := "stream %d ready:" fmt.Fprintf(stream, str, i) buf := make([]byte, len(str)) log(fmt.Sprintf("reading from stream %d", i)) stream.Read(buf) fmt.Println(string(buf)) } log("let's test the streams") log("enter some text below:\n") go io.Copy(os.Stdout, s1) go io.Copy(os.Stdout, s2) go io.Copy(os.Stdout, s3) io.Copy(io.MultiWriter(s1, s2, s3), os.Stdin) }