85 lines
1.9 KiB
Go
85 lines
1.9 KiB
Go
package fasthttputil
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"sync"
|
|
)
|
|
|
|
// InmemoryListener provides in-memory dialer<->net.Listener implementation.
|
|
//
|
|
// It may be used either for fast in-process client<->server communcations
|
|
// without network stack overhead or for client<->server tests.
|
|
type InmemoryListener struct {
|
|
lock sync.Mutex
|
|
closed bool
|
|
conns chan net.Conn
|
|
}
|
|
|
|
// NewInmemoryListener returns new in-memory dialer<->net.Listener.
|
|
func NewInmemoryListener() *InmemoryListener {
|
|
return &InmemoryListener{
|
|
conns: make(chan net.Conn, 1024),
|
|
}
|
|
}
|
|
|
|
// Accept implements net.Listener's Accept.
|
|
//
|
|
// It is safe calling Accept from concurrently running goroutines.
|
|
//
|
|
// Accept returns new connection per each Dial call.
|
|
func (ln *InmemoryListener) Accept() (net.Conn, error) {
|
|
c, ok := <-ln.conns
|
|
if !ok {
|
|
return nil, fmt.Errorf("InmemoryListener is already closed: use of closed network connection")
|
|
}
|
|
return c, nil
|
|
}
|
|
|
|
// Close implements net.Listener's Close.
|
|
func (ln *InmemoryListener) Close() error {
|
|
var err error
|
|
|
|
ln.lock.Lock()
|
|
if !ln.closed {
|
|
close(ln.conns)
|
|
ln.closed = true
|
|
} else {
|
|
err = fmt.Errorf("InmemoryListener is already closed")
|
|
}
|
|
ln.lock.Unlock()
|
|
return err
|
|
}
|
|
|
|
// Addr implements net.Listener's Addr.
|
|
func (ln *InmemoryListener) Addr() net.Addr {
|
|
return &net.UnixAddr{
|
|
Name: "InmemoryListener",
|
|
Net: "memory",
|
|
}
|
|
}
|
|
|
|
// Dial creates new client<->server connection, enqueues server side
|
|
// of the connection to Accept and returns client side of the connection.
|
|
//
|
|
// It is safe calling Dial from concurrently running goroutines.
|
|
func (ln *InmemoryListener) Dial() (net.Conn, error) {
|
|
pc := NewPipeConns()
|
|
cConn := pc.Conn1()
|
|
sConn := pc.Conn2()
|
|
ln.lock.Lock()
|
|
if !ln.closed {
|
|
ln.conns <- sConn
|
|
} else {
|
|
sConn.Close()
|
|
cConn.Close()
|
|
cConn = nil
|
|
}
|
|
ln.lock.Unlock()
|
|
|
|
if cConn == nil {
|
|
return nil, fmt.Errorf("InmemoryListener is already closed")
|
|
}
|
|
return cConn, nil
|
|
}
|