61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
![]() |
package service
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"net"
|
||
|
"sync"
|
||
|
)
|
||
|
|
||
|
// ListenerPipe returns a full-duplex in-memory connection, like net.Pipe.
|
||
|
// Unlike net.Pipe one end of the connection is returned as an object
|
||
|
// satisfying the net.Listener interface.
|
||
|
// The first call to the Accept method of this object will return a net.Conn
|
||
|
// connected to the other net.Conn returned by ListenerPipe.
|
||
|
// Any subsequent calls to Accept will block until the listener is closed.
|
||
|
func ListenerPipe() (net.Listener, net.Conn) {
|
||
|
conn0, conn1 := net.Pipe()
|
||
|
return &preconnectedListener{conn: conn0, closech: make(chan struct{})}, conn1
|
||
|
}
|
||
|
|
||
|
// preconnectedListener satisfies the net.Listener interface by accepting a
|
||
|
// single pre-established connection.
|
||
|
// The first call to Accept will return the conn field, any subsequent call
|
||
|
// will block until the listener is closed.
|
||
|
type preconnectedListener struct {
|
||
|
accepted bool
|
||
|
conn net.Conn
|
||
|
closech chan struct{}
|
||
|
closeMu sync.Mutex
|
||
|
acceptMu sync.Mutex
|
||
|
}
|
||
|
|
||
|
// Accept returns the pre-established connection the first time it's called,
|
||
|
// it blocks until the listener is closed on every subsequent call.
|
||
|
func (l *preconnectedListener) Accept() (net.Conn, error) {
|
||
|
l.acceptMu.Lock()
|
||
|
defer l.acceptMu.Unlock()
|
||
|
if !l.accepted {
|
||
|
l.accepted = true
|
||
|
return l.conn, nil
|
||
|
}
|
||
|
<-l.closech
|
||
|
return nil, errors.New("accept failed: listener closed")
|
||
|
}
|
||
|
|
||
|
// Close closes the listener.
|
||
|
func (l *preconnectedListener) Close() error {
|
||
|
l.closeMu.Lock()
|
||
|
defer l.closeMu.Unlock()
|
||
|
if l.closech == nil {
|
||
|
return nil
|
||
|
}
|
||
|
close(l.closech)
|
||
|
l.closech = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Addr returns the listener's network address.
|
||
|
func (l *preconnectedListener) Addr() net.Addr {
|
||
|
return l.conn.LocalAddr()
|
||
|
}
|