in conn.go [454:489]
func (c *Conn) close() {
c.closeOnce.Do(func() {
defer close(c.done)
close(c.rxtxExit)
// wait for writing to stop, allows it to send the final close frame
<-c.txDone
closeErr := c.net.Close()
// check rxDone after closing net, otherwise may block
// for up to c.idleTimeout
<-c.rxDone
if errors.Is(c.rxErr, net.ErrClosed) {
// this is the expected error when the connection is closed, swallow it
c.rxErr = nil
}
if c.txErr == nil && c.rxErr == nil && closeErr == nil {
// if there are no errors, it means user initiated close() and we shut down cleanly
c.doneErr = &ConnError{}
} else if amqpErr, ok := c.rxErr.(*Error); ok {
// we experienced a peer-initiated close that contained an Error. return it
c.doneErr = &ConnError{RemoteErr: amqpErr}
} else if c.txErr != nil {
// c.txErr is already wrapped in a ConnError
c.doneErr = c.txErr
} else if c.rxErr != nil {
c.doneErr = &ConnError{inner: c.rxErr}
} else {
c.doneErr = &ConnError{inner: closeErr}
}
})
}