func (cp *ConnectionPool) Shutdown() {
	cp.shutdownCancel()
	cp.connMutex.Lock()
	if cp.shutdown {
		cp.connMutex.Unlock()
		cp.logger.Error("shutdown was already called")
		return
	}
	cp.shutdown = true
	cp.connMutex.Unlock()
	cp.dialWait.Wait()
	cp.closeConnections()
}
Shutdown gracefully shuts down the ConnectionPool:
- Closes all open connections
- Waits for all Dial routines to complete and unblock any routines waiting for GetConnection
package connectionpool
import (
	"context"
	"fmt"
	inet "net"
	"github.com/libonomy/libonomy-p2p/log"
	"github.com/libonomy/libonomy-p2p/p2p/net"
	"github.com/libonomy/libonomy-p2p/p2p/p2pcrypto"
	"bytes"
	"errors"
	"sync"
)
type dialResult struct {
	conn net.Connection
	err  error
}
type DialFunc func(ctx context.Context, address inet.Addr, remotePublicKey p2pcrypto.PublicKey) (net.Connection, error)
type ConnectionPool struct {
	localPub    p2pcrypto.PublicKey
	dialFunc    DialFunc
	connections map[p2pcrypto.PublicKey]net.Connection
	connMutex   sync.RWMutex
	pending     map[p2pcrypto.PublicKey][]chan dialResult
	pendMutex   sync.Mutex
	dialWait    sync.WaitGroup
	logger      log.Log
	shutdownCtx    context.Context
	shutdownCancel context.CancelFunc
	shutdown       bool
}
func NewConnectionPool(dialFunc DialFunc, lPub p2pcrypto.PublicKey, logger log.Log) *ConnectionPool {
	shutdownCtx, cancel := context.WithCancel(context.Background())
	cPool := &ConnectionPool{
		localPub:       lPub,
		dialFunc:       dialFunc,
		connections:    make(map[p2pcrypto.PublicKey]net.Connection),
		connMutex:      sync.RWMutex{},
		pending:        make(map[p2pcrypto.PublicKey][]chan dialResult),
		pendMutex:      sync.Mutex{},
		dialWait:       sync.WaitGroup{},
		logger:         logger,
		shutdown:       false,
		shutdownCtx:    shutdownCtx,
		shutdownCancel: cancel,
	}
	return cPool
}
func (cp *ConnectionPool) OnNewConnection(nce net.NewConnectionEvent) error {
	if cp.isShuttingDown() {
		return errors.New("shutting down")
	}
	return cp.handleNewConnection(nce.Conn.RemotePublicKey(), nce.Conn, net.Remote)
}
func (cp *ConnectionPool) OnClosedConnection(cwe net.ConnectionWithErr) {
	if cp.isShuttingDown() {
		return
	}
	conn := cwe.Conn
	cp.logger.With().Info("connection_closed", log.String("id", conn.String()), log.String("remote", conn.RemotePublicKey().String()), log.Err(cwe.Err))
	cp.handleClosedConnection(conn)
}
func (cp *ConnectionPool) isShuttingDown() bool {
	var isd bool
	cp.connMutex.RLock()
	isd = cp.shutdown
	cp.connMutex.RUnlock()
	return isd
}