Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jbenet/go-peerstream

p2p stream multi-multiplexing in Go (with https://github.com/docker/spdystream)
https://github.com/jbenet/go-peerstream

Last synced: 8 days ago
JSON representation

p2p stream multi-multiplexing in Go (with https://github.com/docker/spdystream)

Awesome Lists containing this project

README

        

# go-peerstream p2p multi-multixplexing

Package peerstream is a peer-to-peer networking library that multiplexes
connections to many hosts. It tried to simplify the complexity of:

* accepting incoming connections over **multiple** listeners
* dialing outgoing connections over **multiple** transports
* multiplexing **multiple** connections per-peer
* multiplexing **multiple** different servers or protocols
* handling backpressure correctly
* handling stream multiplexing (we use SPDY, but maybe QUIC some day)
* providing a **simple** interface to the user

### Godoc: https://godoc.org/github.com/jbenet/go-peerstream

---

See this working [example/example.go](example/example):

```Go
package main

import (
"fmt"
"io"
"net"
"os"

ps "github.com/jbenet/go-peerstream"
)

func main() {
// create a new Swarm
swarm := ps.NewSwarm()
defer swarm.Close()

// tell swarm what to do with a new incoming streams.
// EchoHandler just echos back anything they write.
swarm.SetStreamHandler(ps.EchoHandler)

// Okay, let's try listening on some transports
l1, err := net.Listen("tcp", "localhost:8001")
if err != nil {
panic(err)
}

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
nc1, err := net.Dial("tcp", "localhost:8001")
if err != nil {
panic(err)
}

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
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)
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)
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:

for i, stream := range []ps.Stream{s1, s2, s3} {
stream.Wait()
str := "stream %d ready:"
fmt.Fprintf(stream, str, i)

buf := make([]byte, len(str))
stream.Read(buf)
fmt.Println(string(buf))
}

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)
}

func log(s string) {
fmt.Fprintf(os.Stderr, s+"\n")
}
```