mex.go
func (mex *messageExchange) recvPeerFrame() (*Frame, error) {
	// We have to check frames/errors in a very specific order here:
	// 1. Timeouts/cancellation (mex.ctx errors)
	// 2. Any pending frames (non-blocking select over mex.recvCh)
	// 3. Other mex errors (mex.errCh)
	// Which is why we check the context error only (instead of mex.checkError)e
	// In the mex.errCh case, we do a non-blocking read from recvCh to prioritize it.
	if err := mex.ctx.Err(); err != nil {
		return nil, GetContextError(err)
	}

	select {
	case frame := <-mex.recvCh:
		if err := mex.checkFrame(frame); err != nil {
			return nil, err
		}
		return frame, nil
	case <-mex.ctx.Done():
		return nil, GetContextError(mex.ctx.Err())
	case <-mex.errCh.c:
		// Select will randomly choose a case, but we want to prioritize
		// receiving a frame over errCh. Try a non-blocking read.
		select {
		case frame := <-mex.recvCh:
			if err := mex.checkFrame(frame); err != nil {
				return nil, err
			}
			return frame, nil
		default:
		}
		return nil, mex.errCh.err
	}
}
func (mex *messageExchange) recvPeerFrame() (*Frame, error) {
	// We have to check frames/errors in a very specific order here:
	// 1. Timeouts/cancellation (mex.ctx errors)
	// 2. Any pending frames (non-blocking select over mex.recvCh)
	// 3. Other mex errors (mex.errCh)
	// Which is why we check the context error only (instead of mex.checkError)e
	// In the mex.errCh case, we do a non-blocking read from recvCh to prioritize it.
	if err := mex.ctx.Err(); err != nil {
		return nil, GetContextError(err)
	}

	select {
	case frame := <-mex.recvCh:
		if err := mex.checkFrame(frame); err != nil {
			return nil, err
		}
		return frame, nil
	case <-mex.ctx.Done():
		return nil, GetContextError(mex.ctx.Err())
	case <-mex.errCh.c:
		// Select will randomly choose a case, but we want to prioritize
		// receiving a frame over errCh. Try a non-blocking read.
		select {
		case frame := <-mex.recvCh:
			if err := mex.checkFrame(frame); err != nil {
				return nil, err
			}
			return frame, nil
		default:
		}
		return nil, mex.errCh.err
	}
}
// recvPeerFrame waits for a new frame from the peer, or until the context
// expires or is cancelled