master
go 98 lines 2.07 KB
Raw
1 package p2p
2
3 import (
4 "errors"
5 "sync"
6
7 p2phost "github.com/libp2p/go-libp2p/core/host"
8 net "github.com/libp2p/go-libp2p/core/network"
9 "github.com/libp2p/go-libp2p/core/protocol"
10 ma "github.com/multiformats/go-multiaddr"
11 )
12
13 // Listener listens for connections and proxies them to a target.
14 type Listener interface {
15 Protocol() protocol.ID
16 ListenAddress() ma.Multiaddr
17 TargetAddress() ma.Multiaddr
18
19 key() protocol.ID
20
21 // close closes the listener. Does not affect child streams
22 close()
23
24 // Done returns a channel that is closed when the listener is closed.
25 // This allows callers to detect when a listener has been removed.
26 Done() <-chan struct{}
27 }
28
29 // Listeners manages a group of Listener implementations,
30 // checking for conflicts and optionally dispatching connections.
31 type Listeners struct {
32 sync.RWMutex
33
34 Listeners map[protocol.ID]Listener
35 }
36
37 func newListenersLocal() *Listeners {
38 return &Listeners{
39 Listeners: map[protocol.ID]Listener{},
40 }
41 }
42
43 func newListenersP2P(host p2phost.Host) *Listeners {
44 reg := &Listeners{
45 Listeners: map[protocol.ID]Listener{},
46 }
47
48 host.SetStreamHandlerMatch("/x/", func(p protocol.ID) bool {
49 reg.RLock()
50 defer reg.RUnlock()
51
52 _, ok := reg.Listeners[p]
53 return ok
54 }, func(stream net.Stream) {
55 reg.RLock()
56 defer reg.RUnlock()
57
58 l := reg.Listeners[stream.Protocol()]
59 if l != nil {
60 go l.(*remoteListener).handleStream(stream)
61 }
62 })
63
64 return reg
65 }
66
67 // Register registers listenerInfo into this registry and starts it.
68 func (r *Listeners) Register(l Listener) error {
69 r.Lock()
70 defer r.Unlock()
71
72 if _, ok := r.Listeners[l.key()]; ok {
73 return errors.New("listener already registered")
74 }
75
76 r.Listeners[l.key()] = l
77 return nil
78 }
79
80 // Close removes and closes all listeners for which matchFunc returns true.
81 // Returns the number of listeners closed.
82 func (r *Listeners) Close(matchFunc func(listener Listener) bool) int {
83 var todo []Listener
84 r.Lock()
85 for _, l := range r.Listeners {
86 if matchFunc(l) {
87 delete(r.Listeners, l.key())
88 todo = append(todo, l)
89 }
90 }
91 r.Unlock()
92
93 for _, l := range todo {
94 l.close()
95 }
96
97 return len(todo)
98 }