Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
go-libp2p
Commits
8acc21e8
Commit
8acc21e8
authored
Nov 16, 2015
by
Jeromy
Browse files
Vendor in go-peerstream
parent
a9de494f
Changes
177
Hide whitespace changes
Inline
Side-by-side
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/Godeps/Godeps.json
0 → 100644
View file @
8acc21e8
{
"ImportPath"
:
"github.com/jbenet/go-peerstream"
,
"GoVersion"
:
"go1.4.2"
,
"Packages"
:
[
"./..."
],
"Deps"
:
[
{
"ImportPath"
:
"github.com/docker/spdystream"
,
"Rev"
:
"b2c3287865f3ad6aa22821ddb7b4692b896ac207"
},
{
"ImportPath"
:
"github.com/hashicorp/yamux"
,
"Rev"
:
"b2e55852ddaf823a85c67f798080eb7d08acd71d"
},
{
"ImportPath"
:
"github.com/inconshreveable/muxado"
,
"Rev"
:
"f693c7e88ba316d1a0ae3e205e22a01aa3ec2848"
},
{
"ImportPath"
:
"github.com/jbenet/go-stream-muxer"
,
"Rev"
:
"e2e261765847234749629e0190fef193a4548303"
},
{
"ImportPath"
:
"github.com/jbenet/go-temp-err-catcher"
,
"Rev"
:
"aac704a3f4f27190b4ccc05f303a4931fd1241ff"
},
{
"ImportPath"
:
"github.com/whyrusleeping/go-multiplex"
,
"Rev"
:
"474b9aebeb391746f304ddf7c764a5da12319857"
},
{
"ImportPath"
:
"github.com/whyrusleeping/go-multistream"
,
"Rev"
:
"08e8f9c9f5665ed0c63ffde4fa5ef1d5fb3d516d"
}
]
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/LICENSE
0 → 100644
View file @
8acc21e8
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/Makefile
0 → 100644
View file @
8acc21e8
godep
:
go get github.com/tools/godep
vendor
:
godep
godep save
-r
./...
build
:
go build ./...
test
:
go
test
./...
test_race
:
go
test
-race
-cpu
5 ./...
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/README.md
0 → 100644
View file @
8acc21e8
# 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")
}
```
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/conn.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"errors"
"fmt"
"net"
"sync"
smux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
)
// ConnHandler is a function which receives a Conn. It allows
// clients to set a function to receive newly accepted
// connections. It works like StreamHandler, but is usually
// less useful than usual as most services will only use
// Streams. It is safe to pass or store the *Conn elsewhere.
// Note: the ConnHandler is called sequentially, so spawn
// goroutines or pass the Conn. See EchoHandler.
type
ConnHandler
func
(
s
*
Conn
)
// SelectConn selects a connection out of list. It allows
// delegation of decision making to clients. Clients can
// make SelectConn functons that check things connection
// qualities -- like latency andbandwidth -- or pick from
// a logical set of connections.
type
SelectConn
func
([]
*
Conn
)
*
Conn
// ErrInvalidConnSelected signals that a connection selected
// with a SelectConn function is invalid. This may be due to
// the Conn not being part of the original set given to the
// function, or the value being nil.
var
ErrInvalidConnSelected
=
errors
.
New
(
"invalid selected connection"
)
// ErrNoConnections signals that no connections are available
var
ErrNoConnections
=
errors
.
New
(
"no connections"
)
// Conn is a Swarm-associated connection.
type
Conn
struct
{
smuxConn
smux
.
Conn
netConn
net
.
Conn
// underlying connection
swarm
*
Swarm
groups
groupSet
streams
map
[
*
Stream
]
struct
{}
streamLock
sync
.
RWMutex
closed
bool
closeLock
sync
.
Mutex
}
func
newConn
(
nconn
net
.
Conn
,
tconn
smux
.
Conn
,
s
*
Swarm
)
*
Conn
{
return
&
Conn
{
netConn
:
nconn
,
smuxConn
:
tconn
,
swarm
:
s
,
groups
:
groupSet
{
m
:
make
(
map
[
Group
]
struct
{})},
streams
:
make
(
map
[
*
Stream
]
struct
{}),
}
}
// String returns a string representation of the Conn
func
(
c
*
Conn
)
String
()
string
{
c
.
streamLock
.
RLock
()
ls
:=
len
(
c
.
streams
)
c
.
streamLock
.
RUnlock
()
f
:=
"<peerstream.Conn %d streams %s <--> %s>"
return
fmt
.
Sprintf
(
f
,
ls
,
c
.
netConn
.
LocalAddr
(),
c
.
netConn
.
RemoteAddr
())
}
// Swarm returns the Swarm associated with this Conn
func
(
c
*
Conn
)
Swarm
()
*
Swarm
{
return
c
.
swarm
}
// NetConn returns the underlying net.Conn
func
(
c
*
Conn
)
NetConn
()
net
.
Conn
{
return
c
.
netConn
}
// Conn returns the underlying transport Connection we use
// Warning: modifying this object is undefined.
func
(
c
*
Conn
)
Conn
()
smux
.
Conn
{
return
c
.
smuxConn
}
// Groups returns the Groups this Conn belongs to
func
(
c
*
Conn
)
Groups
()
[]
Group
{
return
c
.
groups
.
Groups
()
}
// InGroup returns whether this Conn belongs to a Group
func
(
c
*
Conn
)
InGroup
(
g
Group
)
bool
{
return
c
.
groups
.
Has
(
g
)
}
// AddGroup assigns given Group to Conn
func
(
c
*
Conn
)
AddGroup
(
g
Group
)
{
c
.
groups
.
Add
(
g
)
}
// Stream returns a stream associated with this Conn
func
(
c
*
Conn
)
NewStream
()
(
*
Stream
,
error
)
{
return
c
.
swarm
.
NewStreamWithConn
(
c
)
}
func
(
c
*
Conn
)
Streams
()
[]
*
Stream
{
c
.
streamLock
.
RLock
()
defer
c
.
streamLock
.
RUnlock
()
streams
:=
make
([]
*
Stream
,
0
,
len
(
c
.
streams
))
for
s
:=
range
c
.
streams
{
streams
=
append
(
streams
,
s
)
}
return
streams
}
// Close closes this connection
func
(
c
*
Conn
)
Close
()
error
{
c
.
closeLock
.
Lock
()
defer
c
.
closeLock
.
Unlock
()
if
c
.
closed
{
return
nil
}
c
.
closed
=
true
// close streams
streams
:=
c
.
Streams
()
for
_
,
s
:=
range
streams
{
s
.
Close
()
}
// close underlying connection
c
.
swarm
.
removeConn
(
c
)
err
:=
c
.
smuxConn
.
Close
()
c
.
swarm
.
notifyAll
(
func
(
n
Notifiee
)
{
n
.
Disconnected
(
c
)
})
return
err
}
// ConnsWithGroup narrows down a set of connections to those in a given group.
func
ConnsWithGroup
(
g
Group
,
conns
[]
*
Conn
)
[]
*
Conn
{
var
out
[]
*
Conn
for
_
,
c
:=
range
conns
{
if
c
.
InGroup
(
g
)
{
out
=
append
(
out
,
c
)
}
}
return
out
}
func
ConnInConns
(
c1
*
Conn
,
conns
[]
*
Conn
)
bool
{
for
_
,
c2
:=
range
conns
{
if
c2
==
c1
{
return
true
}
}
return
false
}
// ------------------------------------------------------------------
// All the connection setup logic here, in one place.
// these are mostly *Swarm methods, but i wanted a less-crowded place
// for them.
// ------------------------------------------------------------------
// addConn is the internal version of AddConn. we need the server bool
// as spdystream requires it.
func
(
s
*
Swarm
)
addConn
(
netConn
net
.
Conn
,
isServer
bool
)
(
*
Conn
,
error
)
{
c
,
err
:=
s
.
setupConn
(
netConn
,
isServer
)
if
err
!=
nil
{
return
nil
,
err
}
s
.
ConnHandler
()(
c
)
// go listen for incoming streams on this connection
go
c
.
smuxConn
.
Serve
(
func
(
ss
smux
.
Stream
)
{
// log.Printf("accepted stream %d from %s\n", ssS.Identifier(), netConn.RemoteAddr())
stream
:=
s
.
setupStream
(
ss
,
c
)
s
.
StreamHandler
()(
stream
)
// call our handler
})
s
.
notifyAll
(
func
(
n
Notifiee
)
{
n
.
Connected
(
c
)
})
return
c
,
nil
}
// setupConn adds the relevant connection to the map, first checking if it
// was already there.
func
(
s
*
Swarm
)
setupConn
(
netConn
net
.
Conn
,
isServer
bool
)
(
*
Conn
,
error
)
{
if
netConn
==
nil
{
return
nil
,
errors
.
New
(
"nil conn"
)
}
// first, check if we already have it, to avoid constructing it
// if it is already there
s
.
connLock
.
Lock
()
for
c
:=
range
s
.
conns
{
if
c
.
netConn
==
netConn
{
s
.
connLock
.
Unlock
()
return
c
,
nil
}
}
s
.
connLock
.
Unlock
()
// construct the connection without hanging onto the lock
// (as there could be deadlock if so.)
// create a new spdystream connection
ssConn
,
err
:=
s
.
transport
.
NewConn
(
netConn
,
isServer
)
if
err
!=
nil
{
return
nil
,
err
}
// take the lock to add it to the map.
s
.
connLock
.
Lock
()
defer
s
.
connLock
.
Unlock
()
// check for it again as it may have been added already. (TOCTTOU)
for
c
:=
range
s
.
conns
{
if
c
.
netConn
==
netConn
{
return
c
,
nil
}
}
// add the connection
c
:=
newConn
(
netConn
,
ssConn
,
s
)
s
.
conns
[
c
]
=
struct
{}{}
return
c
,
nil
}
// createStream is the internal function that creates a new stream. assumes
// all validation has happened.
func
(
s
*
Swarm
)
createStream
(
c
*
Conn
)
(
*
Stream
,
error
)
{
// Create a new smux.Stream
smuxStream
,
err
:=
c
.
smuxConn
.
OpenStream
()
if
err
!=
nil
{
return
nil
,
err
}
return
s
.
setupStream
(
smuxStream
,
c
),
nil
}
// newStream is the internal function that creates a new stream. assumes
// all validation has happened.
func
(
s
*
Swarm
)
setupStream
(
smuxStream
smux
.
Stream
,
c
*
Conn
)
*
Stream
{
// create a new stream
stream
:=
newStream
(
smuxStream
,
c
)
// add it to our streams maps
s
.
streamLock
.
Lock
()
c
.
streamLock
.
Lock
()
s
.
streams
[
stream
]
=
struct
{}{}
c
.
streams
[
stream
]
=
struct
{}{}
s
.
streamLock
.
Unlock
()
c
.
streamLock
.
Unlock
()
s
.
notifyAll
(
func
(
n
Notifiee
)
{
n
.
OpenedStream
(
stream
)
})
return
stream
}
func
(
s
*
Swarm
)
removeStream
(
stream
*
Stream
)
error
{
// remove from our maps
s
.
streamLock
.
Lock
()
stream
.
conn
.
streamLock
.
Lock
()
delete
(
s
.
streams
,
stream
)
delete
(
stream
.
conn
.
streams
,
stream
)
s
.
streamLock
.
Unlock
()
stream
.
conn
.
streamLock
.
Unlock
()
err
:=
stream
.
smuxStream
.
Close
()
s
.
notifyAll
(
func
(
n
Notifiee
)
{
n
.
ClosedStream
(
stream
)
})
return
err
}
func
(
s
*
Swarm
)
removeConn
(
conn
*
Conn
)
{
// remove from our maps
s
.
connLock
.
Lock
()
delete
(
s
.
conns
,
conn
)
s
.
connLock
.
Unlock
()
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/doc.go
0 → 100644
View file @
8acc21e8
// 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
//
package
peerstream
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/example/.gitignore
0 → 100644
View file @
8acc21e8
example
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/example/blockhandler/blockhandler.go
0 → 100644
View file @
8acc21e8
package
main
import
(
"bufio"
"fmt"
"net"
"os"
"time"
spdy
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/spdystream"
ps
"QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream"
)
func
die
(
err
error
)
{
fmt
.
Fprintf
(
os
.
Stderr
,
"error: %s
\n
"
)
os
.
Exit
(
1
)
}
func
main
()
{
// create a new Swarm
swarm
:=
ps
.
NewSwarm
(
spdy
.
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
log
(
s
string
,
ifs
...
interface
{})
{
fmt
.
Fprintf
(
os
.
Stderr
,
s
+
"
\n
"
,
ifs
...
)
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/example/example.go
0 → 100644
View file @
8acc21e8
package
main
import
(
"fmt"
"io"
"net"
"os"
spdy
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/spdystream"
ps
"QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream"
)
func
main
()
{
log
(
"creating a new swarm with spdystream transport"
)
// create a new Swarm
swarm
:=
ps
.
NewSwarm
(
spdy
.
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
)
}
func
log
(
s
string
)
{
fmt
.
Fprintf
(
os
.
Stderr
,
s
+
"
\n
"
)
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/group.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"errors"
"sync"
"unsafe"
)
// ErrGroupNotFound signals no such group exists
var
ErrGroupNotFound
=
errors
.
New
(
"group not found"
)
// Group is an object used to associate a group of
// Streams, Connections, and Listeners. It can be anything,
// it is meant to work like a KeyType in maps
type
Group
interface
{}
// Groupable is an interface for a set of objects that can
// be assigned groups: Streams, Connections, and Listeners.
// Objects inherit groups (e.g. a Stream inherits the groups
// of its parent Connection, and in turn that of its Listener).
type
Groupable
interface
{
// Groups returns the groups this object belongs to
Groups
()
[]
Group
// InGroup returns whether this object belongs to a Group
InGroup
(
g
Group
)
bool
// AddGroup adds this object to a group
AddGroup
(
g
Group
)
}
// groupSet is a struct designed to be embedded and
// give things group memebership
type
groupSet
struct
{
m
map
[
Group
]
struct
{}
sync
.
RWMutex
}
func
(
gs
*
groupSet
)
Add
(
g
Group
)
{
gs
.
Lock
()
defer
gs
.
Unlock
()
gs
.
m
[
g
]
=
struct
{}{}
}
func
(
gs
*
groupSet
)
Remove
(
g
Group
)
{
gs
.
Lock
()
defer
gs
.
Unlock
()
delete
(
gs
.
m
,
g
)
}
func
(
gs
*
groupSet
)
Has
(
g
Group
)
bool
{
gs
.
RLock
()
defer
gs
.
RUnlock
()
_
,
ok
:=
gs
.
m
[
g
]
return
ok
}
func
(
gs
*
groupSet
)
Groups
()
[]
Group
{
gs
.
RLock
()
defer
gs
.
RUnlock
()
out
:=
make
([]
Group
,
0
,
len
(
gs
.
m
))
for
k
:=
range
gs
.
m
{
out
=
append
(
out
,
k
)
}
return
out
}
// AddSet adds all elements in another set.
func
(
gs
*
groupSet
)
AddSet
(
gs2
*
groupSet
)
{
// acquire locks in order
p1
:=
uintptr
(
unsafe
.
Pointer
(
gs
))
p2
:=
uintptr
(
unsafe
.
Pointer
(
gs2
))
switch
{
case
p1
<
p2
:
gs
.
Lock
()
gs2
.
RLock
()
defer
gs
.
Unlock
()
defer
gs2
.
RUnlock
()
case
p1
>
p2
:
gs2
.
Lock
()
gs
.
Lock
()
defer
gs2
.
Unlock
()
defer
gs
.
Unlock
()
default
:
return
// they're the same!
}
for
g
:=
range
gs2
.
m
{
gs
.
m
[
g
]
=
struct
{}{}
}
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/handlers.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"io"
"math/rand"
)
var
SelectRandomConn
=
func
(
conns
[]
*
Conn
)
*
Conn
{
if
len
(
conns
)
==
0
{
return
nil
}
return
conns
[
rand
.
Intn
(
len
(
conns
))]
}
func
EchoHandler
(
s
*
Stream
)
{
go
func
()
{
io
.
Copy
(
s
,
s
)
s
.
Close
()
}()
}
func
CloseHandler
(
s
*
Stream
)
{
s
.
Close
()
}
func
NoOpStreamHandler
(
s
*
Stream
)
{}
func
NoOpConnHandler
(
c
*
Conn
)
{}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/listener.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"errors"
"fmt"
"net"
"sync"
tec
"QmWtLNgjHvFnRHcHUheAMGx4sLYYYGSacNA3eG52ywy2UQ/go-temp-err-catcher"
)
// AcceptConcurrency is how many connections can simultaneously be
// in process of being accepted. Handshakes can sometimes occur as
// part of this process, so it may take some time. It is imporant to
// rate limit lest a malicious influx of connections would cause our
// node to consume all its resources accepting new connections.
var
AcceptConcurrency
=
200
type
Listener
struct
{
netList
net
.
Listener
groups
groupSet
swarm
*
Swarm
acceptErr
chan
error
}
func
newListener
(
nl
net
.
Listener
,
s
*
Swarm
)
*
Listener
{
return
&
Listener
{
netList
:
nl
,
swarm
:
s
,
acceptErr
:
make
(
chan
error
,
10
),
}
}
// String returns a string representation of the Listener
func
(
l
*
Listener
)
String
()
string
{
f
:=
"<peerstream.Listener %s>"
return
fmt
.
Sprintf
(
f
,
l
.
netList
.
Addr
())
}
// NetListener is the underlying net.Listener
func
(
l
*
Listener
)
NetListener
()
net
.
Listener
{
return
l
.
netList
}
// Groups returns the groups this Listener belongs to
func
(
l
*
Listener
)
Groups
()
[]
Group
{
return
l
.
groups
.
Groups
()
}
// InGroup returns whether this Listener belongs to a Group
func
(
l
*
Listener
)
InGroup
(
g
Group
)
bool
{
return
l
.
groups
.
Has
(
g
)
}
// AddGroup assigns given Group to Listener
func
(
l
*
Listener
)
AddGroup
(
g
Group
)
{
l
.
groups
.
Add
(
g
)
}
// ListenersWithGroup narrows down a set of listeners to those in given group.
func
ListenersWithGroup
(
g
Group
,
ls
[]
*
Listener
)
[]
*
Listener
{
var
out
[]
*
Listener
for
_
,
l
:=
range
ls
{
if
l
.
InGroup
(
g
)
{
out
=
append
(
out
,
l
)
}
}
return
out
}
// accept continously accepts incoming connections and
// adds them to the listener's Swarm. is is meant to be
// run in a goroutine.
// TODO: add rate limiting
func
(
l
*
Listener
)
accept
()
{
var
wg
sync
.
WaitGroup
defer
func
()
{
wg
.
Wait
()
// must happen before teardown
l
.
teardown
()
}()
// catching the error here is odd. doing what net/http does:
// http://golang.org/src/net/http/server.go?s=51504:51550#L1728
// Using the lib: https://godoc.org/github.com/jbenet/go-temp-err-catcher
var
catcher
tec
.
TempErrCatcher
// rate limit concurrency
limit
:=
make
(
chan
struct
{},
AcceptConcurrency
)
// loop forever accepting connections
for
{
conn
,
err
:=
l
.
netList
.
Accept
()
if
err
!=
nil
{
if
catcher
.
IsTemporary
(
err
)
{
continue
}
l
.
acceptErr
<-
fmt
.
Errorf
(
"peerstream listener failed: %s"
,
err
)
return
// ok, problems. bail.
}
// add conn to swarm and listen for incoming streams
// do this in a goroutine to avoid blocking the Accept loop.
// note that this does not rate limit accepts.
limit
<-
struct
{}{}
// sema down
wg
.
Add
(
1
)
go
func
(
conn
net
.
Conn
)
{
defer
func
()
{
<-
limit
}()
// sema up
defer
wg
.
Done
()
conn2
,
err
:=
l
.
swarm
.
addConn
(
conn
,
true
)
if
err
!=
nil
{
l
.
acceptErr
<-
err
return
}
conn2
.
groups
.
AddSet
(
&
l
.
groups
)
// add out groups
}(
conn
)
}
}
// AcceptError returns the error that we **might** on listener close
func
(
l
*
Listener
)
AcceptErrors
()
<-
chan
error
{
return
l
.
acceptErr
}
func
(
l
*
Listener
)
teardown
()
{
// in case we exit from network errors (accept fails) but
// (a) client doesn't call Close, and (b) listener remains open)
l
.
netList
.
Close
()
close
(
l
.
acceptErr
)
// remove self from swarm
l
.
swarm
.
listenerLock
.
Lock
()
delete
(
l
.
swarm
.
listeners
,
l
)
l
.
swarm
.
listenerLock
.
Unlock
()
}
func
(
l
*
Listener
)
Close
()
error
{
return
l
.
netList
.
Close
()
}
// addListener is the internal version of AddListener.
func
(
s
*
Swarm
)
addListener
(
nl
net
.
Listener
)
(
*
Listener
,
error
)
{
if
nl
==
nil
{
return
nil
,
errors
.
New
(
"nil listener"
)
}
s
.
listenerLock
.
Lock
()
defer
s
.
listenerLock
.
Unlock
()
// first, check if we already have it...
for
l
:=
range
s
.
listeners
{
if
l
.
netList
==
nl
{
return
l
,
nil
}
}
l
:=
newListener
(
nl
,
s
)
s
.
listeners
[
l
]
=
struct
{}{}
go
l
.
accept
()
return
l
,
nil
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/muxtest/hack.go
0 → 100644
View file @
8acc21e8
package
muxtest
import
(
multiplex
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/multiplex"
multistream
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/multistream"
muxado
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/muxado"
spdy
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/spdystream"
yamux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/yamux"
)
var
_
=
multiplex
.
DefaultTransport
var
_
=
multistream
.
NewTransport
var
_
=
muxado
.
Transport
var
_
=
spdy
.
Transport
var
_
=
yamux
.
DefaultTransport
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/muxtest/mux_test.go
0 → 100644
View file @
8acc21e8
package
muxtest
import
(
"testing"
multiplex
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/multiplex"
multistream
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/multistream"
muxado
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/muxado"
spdy
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/spdystream"
yamux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer/yamux"
)
func
TestYamuxTransport
(
t
*
testing
.
T
)
{
SubtestAll
(
t
,
yamux
.
DefaultTransport
)
}
func
TestSpdyStreamTransport
(
t
*
testing
.
T
)
{
t
.
SkipNow
()
SubtestAll
(
t
,
spdy
.
Transport
)
}
func
TestMultiplexTransport
(
t
*
testing
.
T
)
{
SubtestAll
(
t
,
multiplex
.
DefaultTransport
)
}
func
TestMuxadoTransport
(
t
*
testing
.
T
)
{
SubtestAll
(
t
,
muxado
.
Transport
)
}
func
TestMultistreamTransport
(
t
*
testing
.
T
)
{
SubtestAll
(
t
,
multistream
.
NewTransport
())
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/muxtest/muxt.go
0 → 100644
View file @
8acc21e8
package
muxtest
import
(
"bytes"
crand
"crypto/rand"
"fmt"
"io"
mrand
"math/rand"
"net"
"os"
"reflect"
"runtime"
"sync"
"testing"
ps
"QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream"
smux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
)
var
randomness
[]
byte
var
nextPort
=
20000
var
verbose
=
false
func
init
()
{
// read 1MB of randomness
randomness
=
make
([]
byte
,
1
<<
20
)
if
_
,
err
:=
crand
.
Read
(
randomness
);
err
!=
nil
{
panic
(
err
)
}
}
func
randBuf
(
size
int
)
[]
byte
{
n
:=
len
(
randomness
)
-
size
if
size
<
1
{
panic
(
fmt
.
Errorf
(
"requested too large buffer (%d). max is %d"
,
size
,
len
(
randomness
)))
}
start
:=
mrand
.
Intn
(
n
)
return
randomness
[
start
:
start
+
size
]
}
func
checkErr
(
t
*
testing
.
T
,
err
error
)
{
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
}
func
log
(
s
string
,
v
...
interface
{})
{
if
verbose
{
fmt
.
Fprintf
(
os
.
Stderr
,
"> "
+
s
+
"
\n
"
,
v
...
)
}
}
type
echoSetup
struct
{
swarm
*
ps
.
Swarm
conns
[]
*
ps
.
Conn
}
func
singleConn
(
t
*
testing
.
T
,
tr
smux
.
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
},
}
}
func
makeSwarm
(
t
*
testing
.
T
,
tr
smux
.
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
makeSwarms
(
t
*
testing
.
T
,
tr
smux
.
Transport
,
nSwarms
,
nListeners
int
)
[]
*
ps
.
Swarm
{
swarms
:=
make
([]
*
ps
.
Swarm
,
nSwarms
)
for
i
:=
0
;
i
<
nSwarms
;
i
++
{
swarms
[
i
]
=
makeSwarm
(
t
,
tr
,
nListeners
)
}
return
swarms
}
func
SubtestConstructSwarm
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
ps
.
NewSwarm
(
tr
)
}
func
SubtestSimpleWrite
(
t
*
testing
.
T
,
tr
smux
.
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
SubtestSimpleWrite100msgs
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
msgs
:=
100
msgsize
:=
1
<<
19
es
:=
singleConn
(
t
,
tr
)
defer
es
.
swarm
.
Close
()
log
(
"creating stream"
)
stream
,
err
:=
es
.
conns
[
0
]
.
NewStream
()
checkErr
(
t
,
err
)
bufs
:=
make
(
chan
[]
byte
,
msgs
)
var
wg
sync
.
WaitGroup
wg
.
Add
(
1
)
go
func
()
{
defer
wg
.
Done
()
for
i
:=
0
;
i
<
msgs
;
i
++
{
buf
:=
randBuf
(
msgsize
)
bufs
<-
buf
log
(
"writing %d bytes (message %d/%d #%x)"
,
len
(
buf
),
i
,
msgs
,
buf
[
:
3
])
if
_
,
err
:=
stream
.
Write
(
buf
);
err
!=
nil
{
t
.
Error
(
fmt
.
Errorf
(
"stream.Write(buf): %s"
,
err
))
continue
}
}
close
(
bufs
)
}()
wg
.
Add
(
1
)
go
func
()
{
defer
wg
.
Done
()
buf2
:=
make
([]
byte
,
msgsize
)
i
:=
0
for
buf1
:=
range
bufs
{
log
(
"reading %d bytes (message %d/%d #%x)"
,
len
(
buf1
),
i
,
msgs
,
buf1
[
:
3
])
i
++
if
_
,
err
:=
io
.
ReadFull
(
stream
,
buf2
);
err
!=
nil
{
t
.
Error
(
fmt
.
Errorf
(
"readFull(stream, buf2): %s"
,
err
))
continue
}
if
!
bytes
.
Equal
(
buf1
,
buf2
)
{
t
.
Error
(
fmt
.
Errorf
(
"buffers not equal (%x != %x)"
,
buf1
[
:
3
],
buf2
[
:
3
]))
}
}
}()
wg
.
Wait
()
}
func
SubtestStressNSwarmNConnNStreamNMsg
(
t
*
testing
.
T
,
tr
smux
.
Transport
,
nSwarm
,
nConn
,
nStream
,
nMsg
int
)
{
msgsize
:=
1
<<
11
rateLimitN
:=
5000
rateLimitChan
:=
make
(
chan
struct
{},
rateLimitN
)
// max of 5k funcs.
for
i
:=
0
;
i
<
rateLimitN
;
i
++
{
rateLimitChan
<-
struct
{}{}
}
rateLimit
:=
func
(
f
func
())
{
<-
rateLimitChan
f
()
rateLimitChan
<-
struct
{}{}
}
writeStream
:=
func
(
s
*
ps
.
Stream
,
bufs
chan
<-
[]
byte
)
{
log
(
"writeStream %p, %d nMsg"
,
s
,
nMsg
)
for
i
:=
0
;
i
<
nMsg
;
i
++
{
buf
:=
randBuf
(
msgsize
)
bufs
<-
buf
log
(
"%p writing %d bytes (message %d/%d #%x)"
,
s
,
len
(
buf
),
i
,
nMsg
,
buf
[
:
3
])
if
_
,
err
:=
s
.
Write
(
buf
);
err
!=
nil
{
t
.
Error
(
fmt
.
Errorf
(
"s.Write(buf): %s"
,
err
))
continue
}
}
}
readStream
:=
func
(
s
*
ps
.
Stream
,
bufs
<-
chan
[]
byte
)
{
log
(
"readStream %p, %d nMsg"
,
s
,
nMsg
)
buf2
:=
make
([]
byte
,
msgsize
)
i
:=
0
for
buf1
:=
range
bufs
{
i
++
log
(
"%p reading %d bytes (message %d/%d #%x)"
,
s
,
len
(
buf1
),
i
-
1
,
nMsg
,
buf1
[
:
3
])
if
_
,
err
:=
io
.
ReadFull
(
s
,
buf2
);
err
!=
nil
{
log
(
"%p failed to read %d bytes (message %d/%d #%x)"
,
s
,
len
(
buf1
),
i
-
1
,
nMsg
,
buf1
[
:
3
])
t
.
Error
(
fmt
.
Errorf
(
"io.ReadFull(s, buf2): %s"
,
err
))
continue
}
if
!
bytes
.
Equal
(
buf1
,
buf2
)
{
t
.
Error
(
fmt
.
Errorf
(
"buffers not equal (%x != %x)"
,
buf1
[
:
3
],
buf2
[
:
3
]))
}
}
}
openStreamAndRW
:=
func
(
c
*
ps
.
Conn
)
{
log
(
"openStreamAndRW %p, %d nMsg"
,
c
,
nMsg
)
s
,
err
:=
c
.
NewStream
()
if
err
!=
nil
{
t
.
Error
(
fmt
.
Errorf
(
"Failed to create NewStream: %s"
,
err
))
return
}
bufs
:=
make
(
chan
[]
byte
,
nMsg
)
go
func
()
{
writeStream
(
s
,
bufs
)
close
(
bufs
)
}()
readStream
(
s
,
bufs
)
s
.
Close
()
}
openConnAndRW
:=
func
(
a
,
b
*
ps
.
Swarm
)
{
log
(
"openConnAndRW %p -> %p, %d nStream"
,
a
,
b
,
nConn
)
ls
:=
b
.
Listeners
()
l
:=
ls
[
mrand
.
Intn
(
len
(
ls
))]
nl
:=
l
.
NetListener
()
nla
:=
nl
.
Addr
()
nc
,
err
:=
net
.
Dial
(
nla
.
Network
(),
nla
.
String
())
if
err
!=
nil
{
t
.
Fatal
(
fmt
.
Errorf
(
"net.Dial(%s, %s): %s"
,
nla
.
Network
(),
nla
.
String
(),
err
))
return
}
c
,
err
:=
a
.
AddConn
(
nc
)
if
err
!=
nil
{
t
.
Fatal
(
fmt
.
Errorf
(
"a.AddConn(%s <--> %s): %s"
,
nc
.
LocalAddr
(),
nc
.
RemoteAddr
(),
err
))
return
}
var
wg
sync
.
WaitGroup
for
i
:=
0
;
i
<
nStream
;
i
++
{
wg
.
Add
(
1
)
go
rateLimit
(
func
()
{
defer
wg
.
Done
()
openStreamAndRW
(
c
)
})
}
wg
.
Wait
()
c
.
Close
()
}
openConnsAndRW
:=
func
(
a
,
b
*
ps
.
Swarm
)
{
log
(
"openConnsAndRW %p -> %p, %d conns"
,
a
,
b
,
nConn
)
var
wg
sync
.
WaitGroup
for
i
:=
0
;
i
<
nConn
;
i
++
{
wg
.
Add
(
1
)
go
rateLimit
(
func
()
{
defer
wg
.
Done
()
openConnAndRW
(
a
,
b
)
})
}
wg
.
Wait
()
}
connectSwarmsAndRW
:=
func
(
swarms
[]
*
ps
.
Swarm
)
{
log
(
"connectSwarmsAndRW %d swarms"
,
len
(
swarms
))
var
wg
sync
.
WaitGroup
for
_
,
a
:=
range
swarms
{
for
_
,
b
:=
range
swarms
{
wg
.
Add
(
1
)
a
:=
a
// race
b
:=
b
// race
go
rateLimit
(
func
()
{
defer
wg
.
Done
()
openConnsAndRW
(
a
,
b
)
})
}
}
wg
.
Wait
()
}
swarms
:=
makeSwarms
(
t
,
tr
,
nSwarm
,
3
)
// 3 listeners per swarm.
connectSwarmsAndRW
(
swarms
)
for
_
,
s
:=
range
swarms
{
s
.
Close
()
}
}
func
SubtestStress1Swarm1Conn1Stream1Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
1
,
1
,
1
,
1
)
}
func
SubtestStress1Swarm1Conn1Stream100Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
1
,
1
,
1
,
100
)
}
func
SubtestStress1Swarm1Conn100Stream100Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
1
,
1
,
100
,
100
)
}
func
SubtestStress1Swarm10Conn50Stream50Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
1
,
10
,
50
,
50
)
}
func
SubtestStress5Swarm2Conn20Stream20Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
5
,
2
,
20
,
20
)
}
func
SubtestStress10Swarm2Conn100Stream100Msg
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
SubtestStressNSwarmNConnNStreamNMsg
(
t
,
tr
,
10
,
2
,
100
,
100
)
}
func
SubtestAll
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
{
tests
:=
[]
TransportTest
{
SubtestConstructSwarm
,
SubtestSimpleWrite
,
SubtestSimpleWrite100msgs
,
SubtestStress1Swarm1Conn1Stream1Msg
,
SubtestStress1Swarm1Conn1Stream100Msg
,
SubtestStress1Swarm1Conn100Stream100Msg
,
SubtestStress1Swarm10Conn50Stream50Msg
,
SubtestStress5Swarm2Conn20Stream20Msg
,
// SubtestStress10Swarm2Conn100Stream100Msg, <-- this hoses the osx network stack...
}
for
_
,
f
:=
range
tests
{
if
testing
.
Verbose
()
{
fmt
.
Fprintf
(
os
.
Stderr
,
"==== RUN %s
\n
"
,
GetFunctionName
(
f
))
}
f
(
t
,
tr
)
}
}
type
TransportTest
func
(
t
*
testing
.
T
,
tr
smux
.
Transport
)
func
TestNoOp
(
t
*
testing
.
T
)
{}
func
GetFunctionName
(
i
interface
{})
string
{
return
runtime
.
FuncForPC
(
reflect
.
ValueOf
(
i
)
.
Pointer
())
.
Name
()
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/package.json
0 → 100644
View file @
8acc21e8
{
"name"
:
"go-peerstream"
,
"author"
:
"whyrusleeping"
,
"version"
:
"1.0.0"
,
"gxDependencies"
:
[
{
"name"
:
"go-temp-err-catcher"
,
"hash"
:
"QmWtLNgjHvFnRHcHUheAMGx4sLYYYGSacNA3eG52ywy2UQ"
,
"version"
:
"1.0.0"
},
{
"name"
:
"go-stream-muxer"
,
"hash"
:
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q"
,
"version"
:
"1.0.0"
}
],
"language"
:
"go"
,
"gx"
:
{
"dvcsimport"
:
"github.com/jbenet/go-peerstream"
}
}
\ No newline at end of file
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/stream.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"fmt"
smux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
)
// StreamHandler is a function which receives a Stream. It
// allows clients to set a function to receive newly created
// streams, and decide whether to continue adding them.
// It works sort of like a http.HandleFunc.
// Note: the StreamHandler is called sequentially, so spawn
// goroutines or pass the Stream. See EchoHandler.
type
StreamHandler
func
(
s
*
Stream
)
// Stream is an io.{Read,Write,Close}r to a remote counterpart.
// It wraps a spdystream.Stream, and links it to a Conn and groups
type
Stream
struct
{
smuxStream
smux
.
Stream
conn
*
Conn
groups
groupSet
}
func
newStream
(
ss
smux
.
Stream
,
c
*
Conn
)
*
Stream
{
s
:=
&
Stream
{
conn
:
c
,
smuxStream
:
ss
,
groups
:
groupSet
{
m
:
make
(
map
[
Group
]
struct
{})},
}
s
.
groups
.
AddSet
(
&
c
.
groups
)
// inherit groups
return
s
}
// String returns a string representation of the Stream
func
(
s
*
Stream
)
String
()
string
{
f
:=
"<peerstream.Stream %s <--> %s>"
return
fmt
.
Sprintf
(
f
,
s
.
conn
.
NetConn
()
.
LocalAddr
(),
s
.
conn
.
NetConn
()
.
RemoteAddr
())
}
// SPDYStream returns the underlying *spdystream.Stream
func
(
s
*
Stream
)
Stream
()
smux
.
Stream
{
return
s
.
smuxStream
}
// Conn returns the Conn associated with this Stream
func
(
s
*
Stream
)
Conn
()
*
Conn
{
return
s
.
conn
}
// Swarm returns the Swarm asociated with this Stream
func
(
s
*
Stream
)
Swarm
()
*
Swarm
{
return
s
.
conn
.
swarm
}
// Groups returns the Groups this Stream belongs to
func
(
s
*
Stream
)
Groups
()
[]
Group
{
return
s
.
groups
.
Groups
()
}
// InGroup returns whether this stream belongs to a Group
func
(
s
*
Stream
)
InGroup
(
g
Group
)
bool
{
return
s
.
groups
.
Has
(
g
)
}
// AddGroup assigns given Group to Stream
func
(
s
*
Stream
)
AddGroup
(
g
Group
)
{
s
.
groups
.
Add
(
g
)
}
func
(
s
*
Stream
)
Read
(
p
[]
byte
)
(
n
int
,
err
error
)
{
return
s
.
smuxStream
.
Read
(
p
)
}
func
(
s
*
Stream
)
Write
(
p
[]
byte
)
(
n
int
,
err
error
)
{
return
s
.
smuxStream
.
Write
(
p
)
}
func
(
s
*
Stream
)
Close
()
error
{
return
s
.
conn
.
swarm
.
removeStream
(
s
)
}
// StreamsWithGroup narrows down a set of streams to those in given group.
func
StreamsWithGroup
(
g
Group
,
streams
[]
*
Stream
)
[]
*
Stream
{
var
out
[]
*
Stream
for
_
,
s
:=
range
streams
{
if
s
.
InGroup
(
g
)
{
out
=
append
(
out
,
s
)
}
}
return
out
}
vendor/QmTgxFwS1nDK126fH5XPnLFcxcDFsxKbPPnCBwyRWNAjDX/go-peerstream/swarm.go
0 → 100644
View file @
8acc21e8
package
peerstream
import
(
"errors"
"fmt"
"net"
"sync"
"time"
smux
"QmPxuHs2NQjz16gnvndgkzHkm5PjtqbB5rwoSpLusBkQ7Q/go-stream-muxer"
)
// fd is a (file) descriptor, unix style
type
fd
uint32
// GarbageCollectTimeout governs the periodic connection closer.
var
GarbageCollectTimeout
=
5
*
time
.
Second
type
Swarm
struct
{
// the transport we'll use.
transport
smux
.
Transport
// active streams.
streams
map
[
*
Stream
]
struct
{}
streamLock
sync
.
RWMutex
// active connections. generate new Streams
conns
map
[
*
Conn
]
struct
{}
connLock
sync
.
RWMutex
// active listeners. generate new Listeners
listeners
map
[
*
Listener
]
struct
{}
listenerLock
sync
.
RWMutex
// these handlers should be accessed with their getter/setter
// as this pointer may be changed at any time.
handlerLock
sync
.
RWMutex
// protects the functions below
connHandler
ConnHandler
// receives Conns intiated remotely
streamHandler
StreamHandler
// receives Streams initiated remotely
selectConn
SelectConn
// default SelectConn function
// notification listeners
notifiees
map
[
Notifiee
]
struct
{}
notifieeLock
sync
.
RWMutex
closed
chan
struct
{}
}
func
NewSwarm
(
t
smux
.
Transport
)
*
Swarm
{
s
:=
&
Swarm
{
transport
:
t
,
streams
:
make
(
map
[
*
Stream
]
struct
{}),
conns
:
make
(
map
[
*
Conn
]
struct
{}),
listeners
:
make
(
map
[
*
Listener
]
struct
{}),
notifiees
:
make
(
map
[
Notifiee
]
struct
{}),
selectConn
:
SelectRandomConn
,
streamHandler
:
NoOpStreamHandler
,
connHandler
:
NoOpConnHandler
,
closed
:
make
(
chan
struct
{}),
}
go
s
.
connGarbageCollect
()
return
s
}
// String returns a string with various internal stats
func
(
s
*
Swarm
)
String
()
string
{
s
.
listenerLock
.
Lock
()
ls
:=
len
(
s
.
listeners
)
s
.
listenerLock
.
Unlock
()
s
.
connLock
.
Lock
()
cs
:=
len
(
s
.
conns
)
s
.
connLock
.
Unlock
()
s
.
streamLock
.
Lock
()
ss
:=
len
(
s
.
streams
)
s
.
streamLock
.
Unlock
()
str
:=
"<peerstream.Swarm %d listeners %d conns %d streams>"
return
fmt
.
Sprintf
(
str
,
ls
,
cs
,
ss
)
}
// Dump returns a string with all the internal state
func
(
s
*
Swarm
)
Dump
()
string
{
str
:=
s
.
String
()
+
"
\n
"
s
.
listenerLock
.
Lock
()
for
l
,
_
:=
range
s
.
listeners
{
str
+=
fmt
.
Sprintf
(
"
\t
%s %v
\n
"
,
l
,
l
.
Groups
())
}
s
.
listenerLock
.
Unlock
()
s
.
connLock
.
Lock
()
for
c
,
_
:=
range
s
.
conns
{
str
+=
fmt
.
Sprintf
(
"
\t
%s %v
\n
"
,
c
,
c
.
Groups
())
}
s
.
connLock
.
Unlock
()
s
.
streamLock
.
Lock
()
for
ss
,
_
:=
range
s
.
streams
{
str
+=
fmt
.
Sprintf
(
"
\t
%s %v
\n
"
,
ss
,
ss
.
Groups
())
}
s
.
streamLock
.
Unlock
()
return
str
}
// SetStreamHandler assigns the stream handler in the swarm.
// The handler assumes responsibility for closing the stream.
// This need not happen at the end of the handler, leaving the
// stream open (to be used and closed later) is fine.
// It is also fine to keep a pointer to the Stream.
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
SetStreamHandler
(
sh
StreamHandler
)
{
s
.
handlerLock
.
Lock
()
defer
s
.
handlerLock
.
Unlock
()
s
.
streamHandler
=
sh
}
// StreamHandler returns the Swarm's current StreamHandler.
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
StreamHandler
()
StreamHandler
{
s
.
handlerLock
.
RLock
()
defer
s
.
handlerLock
.
RUnlock
()
if
s
.
streamHandler
==
nil
{
return
NoOpStreamHandler
}
return
s
.
streamHandler
}
// SetConnHandler assigns the conn handler in the swarm.
// Unlike the StreamHandler, the ConnHandler has less respon-
// ibility for the Connection. The Swarm is still its client.
// This handler is only a notification.
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
SetConnHandler
(
ch
ConnHandler
)
{
s
.
handlerLock
.
Lock
()
defer
s
.
handlerLock
.
Unlock
()
s
.
connHandler
=
ch
}
// ConnHandler returns the Swarm's current ConnHandler.
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
ConnHandler
()
ConnHandler
{
s
.
handlerLock
.
RLock
()
defer
s
.
handlerLock
.
RUnlock
()
if
s
.
connHandler
==
nil
{
return
NoOpConnHandler
}
return
s
.
connHandler
}
// SetConnSelect assigns the connection selector in the swarm.
// If cs is nil, will use SelectRandomConn
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
SetSelectConn
(
cs
SelectConn
)
{
s
.
handlerLock
.
Lock
()
defer
s
.
handlerLock
.
Unlock
()
s
.
selectConn
=
cs
}
// ConnSelect returns the Swarm's current connection selector.
// ConnSelect is used in order to select the best of a set of
// possible connections. The default chooses one at random.
// This is a threadsafe (atomic) operation
func
(
s
*
Swarm
)
SelectConn
()
SelectConn
{
s
.
handlerLock
.
RLock
()
defer
s
.
handlerLock
.
RUnlock
()
if
s
.
selectConn
==
nil
{
return
SelectRandomConn
}
return
s
.
selectConn
}
// Conns returns all the connections associated with this Swarm.
func
(
s
*
Swarm
)
Conns
()
[]
*
Conn
{
s
.
connLock
.
RLock
()
conns
:=
make
([]
*
Conn
,
0
,
len
(
s
.
conns
))
for
c
:=
range
s
.
conns
{
conns
=
append
(
conns
,
c
)
}
s
.
connLock
.
RUnlock
()
open
:=
make
([]
*
Conn
,
0
,
len
(
conns
))
for
_
,
c
:=
range
conns
{
if
c
.
smuxConn
.
IsClosed
()
{
c
.
Close
()
}
else
{
open
=
append
(
open
,
c
)
}
}
return
open
}
// Listeners returns all the listeners associated with this Swarm.
func
(
s
*
Swarm
)
Listeners
()
[]
*
Listener
{
s
.
listenerLock
.
RLock
()
out
:=
make
([]
*
Listener
,
0
,
len
(
s
.
listeners
))
for
c
:=
range
s
.
listeners
{
out
=
append
(
out
,
c
)
}
s
.
listenerLock
.
RUnlock
()
return
out
}
// Streams returns all the streams associated with this Swarm.
func
(
s
*
Swarm
)
Streams
()
[]
*
Stream
{
s
.
streamLock
.
RLock
()
out
:=
make
([]
*
Stream
,
0
,
len
(
s
.
streams
))
for
c
:=
range
s
.
streams
{
out
=
append
(
out
,
c
)
}
s
.
streamLock
.
RUnlock
()
return
out
}
// AddListener adds net.Listener to the Swarm, and immediately begins
// accepting incoming connections.
func
(
s
*
Swarm
)
AddListener
(
l
net
.
Listener
)
(
*
Listener
,
error
)
{
return
s
.
addListener
(
l
)
}
// AddListenerWithRateLimit adds Listener to the Swarm, and immediately
// begins accepting incoming connections. The rate of connection acceptance
// depends on the RateLimit option
// func (s *Swarm) AddListenerWithRateLimit(net.Listner, RateLimit) // TODO
// AddConn gives the Swarm ownership of net.Conn. The Swarm will open a
// SPDY session and begin listening for Streams.
// Returns the resulting Swarm-associated peerstream.Conn.
// Idempotent: if the Connection has already been added, this is a no-op.
func
(
s
*
Swarm
)
AddConn
(
netConn
net
.
Conn
)
(
*
Conn
,
error
)
{
return
s
.
addConn
(
netConn
,
false
)
}
// NewStream opens a new Stream on the best available connection,
// as selected by current swarm.SelectConn.
func
(
s
*
Swarm
)
NewStream
()
(
*
Stream
,
error
)
{
return
s
.
NewStreamSelectConn
(
s
.
SelectConn
())
}
func
(
s
*
Swarm
)
newStreamSelectConn
(
selConn
SelectConn
,
conns
[]
*
Conn
)
(
*
Stream
,
error
)
{
if
selConn
==
nil
{
return
nil
,
errors
.
New
(
"nil SelectConn"
)
}
best
:=
selConn
(
conns
)
if
best
==
nil
||
!
ConnInConns
(
best
,
conns
)
{
return
nil
,
ErrInvalidConnSelected
}
return
s
.
NewStreamWithConn
(
best
)
}
// NewStreamWithSelectConn opens a new Stream on a connection selected
// by selConn.
func
(
s
*
Swarm
)
NewStreamSelectConn
(
selConn
SelectConn
)
(
*
Stream
,
error
)
{
if
selConn
==
nil
{
return
nil
,
errors
.
New
(
"nil SelectConn"
)
}
conns
:=
s
.
Conns
()
if
len
(
conns
)
==
0
{
return
nil
,
ErrNoConnections
}
return
s
.
newStreamSelectConn
(
selConn
,
conns
)
}
// NewStreamWithGroup opens a new Stream on an available connection in
// the given group. Uses the current swarm.SelectConn to pick between
// multiple connections.
func
(
s
*
Swarm
)
NewStreamWithGroup
(
group
Group
)
(
*
Stream
,
error
)
{
conns
:=
s
.
ConnsWithGroup
(
group
)
return
s
.
newStreamSelectConn
(
s
.
SelectConn
(),
conns
)
}
// NewStreamWithNetConn opens a new Stream on given net.Conn.
// Calls s.AddConn(netConn).
func
(
s
*
Swarm
)
NewStreamWithNetConn
(
netConn
net
.
Conn
)
(
*
Stream
,
error
)
{
c
,
err
:=
s
.
AddConn
(
netConn
)
if
err
!=
nil
{
return
nil
,
err
}
return
s
.
NewStreamWithConn
(
c
)
}
// NewStreamWithConnection opens a new Stream on given connection.
func
(
s
*
Swarm
)
NewStreamWithConn
(
conn
*
Conn
)
(
*
Stream
,
error
)
{
if
conn
==
nil
{
return
nil
,
errors
.
New
(
"nil Conn"
)
}
if
conn
.
Swarm
()
!=
s
{
return
nil
,
errors
.
New
(
"connection not associated with swarm"
)
}
if
conn
.
smuxConn
.
IsClosed
()
{
go
conn
.
Close
()
return
nil
,
errors
.
New
(
"conn is closed"
)
}
s
.
connLock
.
RLock
()
if
_
,
found
:=
s
.
conns
[
conn
];
!
found
{
s
.
connLock
.
RUnlock
()
return
nil
,
errors
.
New
(
"connection not associated with swarm"
)
}
s
.
connLock
.
RUnlock
()
return
s
.
createStream
(
conn
)
}
// AddConnToGroup assigns given Group to conn
func
(
s
*
Swarm
)
AddConnToGroup
(
conn
*
Conn
,
g
Group
)
{
conn
.
groups
.
Add
(
g
)
}
// ConnsWithGroup returns all the connections with a given Group
func
(
s
*
Swarm
)
ConnsWithGroup
(
g
Group
)
[]
*
Conn
{
return
ConnsWithGroup
(
g
,
s
.
Conns
())
}
// StreamsWithGroup returns all the streams with a given Group
func
(
s
*
Swarm
)
StreamsWithGroup
(
g
Group
)
[]
*
Stream
{
return
StreamsWithGroup
(
g
,
s
.
Streams
())
}
// Close shuts down the Swarm, and it's listeners.
func
(
s
*
Swarm
)
Close
()
error
{
defer
close
(
s
.
closed
)
// automatically close everything new we get.
s
.
SetConnHandler
(
func
(
c
*
Conn
)
{
c
.
Close
()
})
s
.
SetStreamHandler
(
func
(
s
*
Stream
)
{
s
.
Close
()
})
var
wgl
sync
.
WaitGroup
for
_
,
l
:=
range
s
.
Listeners
()
{
wgl
.
Add
(
1
)
go
func
(
list
*
Listener
)
{
list
.
Close
()
wgl
.
Done
()
}(
l
)
}
wgl
.
Wait
()
var
wgc
sync
.
WaitGroup
for
_
,
c
:=
range
s
.
Conns
()
{
wgc
.
Add
(
1
)
go
func
(
conn
*
Conn
)
{
conn
.
Close
()
wgc
.
Done
()
}(
c
)
}
wgc
.
Wait
()
return
nil
}
// connGarbageCollect periodically sweeps conns to make sure
// they're still alive. if any are closed, remvoes them.
func
(
s
*
Swarm
)
connGarbageCollect
()
{
for
{
select
{
case
<-
s
.
closed
:
return
case
<-
time
.
After
(
GarbageCollectTimeout
)
:
}
for
_
,
c
:=
range
s
.
Conns
()
{
if
c
.
smuxConn
.
IsClosed
()
{
go
c
.
Close
()
}
}
}
}
// Notify signs up Notifiee to receive signals when events happen
func
(
s
*
Swarm
)
Notify
(
n
Notifiee
)
{
s
.
notifieeLock
.
Lock
()
s
.
notifiees
[
n
]
=
struct
{}{}
s
.
notifieeLock
.
Unlock
()
}
// StopNotify unregisters Notifiee fromr receiving signals
func
(
s
*
Swarm
)
StopNotify
(
n
Notifiee
)
{
s
.
notifieeLock
.
Lock
()
delete
(
s
.
notifiees
,
n
)
s
.
notifieeLock
.
Unlock
()
}
// notifyAll runs the notification function on all Notifiees
func
(
s
*
Swarm
)
notifyAll
(
notification
func
(
n
Notifiee
))
{
s
.
notifieeLock
.
RLock
()
for
n
:=
range
s
.
notifiees
{
// make sure we dont block
// and they dont block each other.
go
notification
(
n
)
}
s
.
notifieeLock
.
RUnlock
()
}
// Notifiee is an interface for an object wishing to receive
// notifications from a Swarm
type
Notifiee
interface
{
Connected
(
*
Conn
)
// called when a connection opened
Disconnected
(
*
Conn
)
// called when a connection closed
OpenedStream
(
*
Stream
)
// called when a stream opened
ClosedStream
(
*
Stream
)
// called when a stream closed
}
vendor/QmWtLNgjHvFnRHcHUheAMGx4sLYYYGSacNA3eG52ywy2UQ/go-temp-err-catcher/.travis.yml
0 → 100644
View file @
8acc21e8
language
:
go
go
:
-
1.3
-
release
-
tip
script
:
-
go test -race -cpu=5 -v ./...
vendor/QmWtLNgjHvFnRHcHUheAMGx4sLYYYGSacNA3eG52ywy2UQ/go-temp-err-catcher/LICENSE
0 → 100644
View file @
8acc21e8
The MIT License (MIT)
Copyright (c) 2014 Juan Batiz-Benet
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Prev
1
2
3
4
5
6
7
8
9
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment