close method

  1. @override
Future<void> close()
override

Closes the stream muxer and the the underlying connection.

Implementation

@override
Future<void> close() async {
  // Phase 1.3: Connection Resource Cleanup Analysis - Enhanced close logging
  final closeStart = DateTime.now();
  final timeSinceOpen = closeStart.difference(_openedAt);
  _logger.fine('[UDXSessionConn $id] CLOSE_START: Is already closed: $_isClosed, Is closing: $_isClosing, time_since_open: ${timeSinceOpen.inMilliseconds}ms');

  if (_isClosed || _isClosing) return;
  _isClosing = true;

  // Phase 1.1: UDX Connection Lifecycle Analysis - State change logging
  _logger.fine('[UDXSessionConn $id] STATE_CHANGE: open -> closing, reason: normal_close');
  _connManager.updateState(this, ConnectionState.closing, error: null);

  // Phase 1.3: Resource cleanup order logging
  _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: 1. Cancelling socket and initial stream subscriptions');
  await _socketMessageSubscription?.cancel();
  _socketMessageSubscription = null;
  await _initialStreamCloseSubscription?.cancel();
  _initialStreamCloseSubscription = null;

  _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: 2. Closing incoming streams controller');
  if (!_incomingStreamsController.isClosed) {
    await _incomingStreamsController.close();
  }

  _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: 3. Closing all active streams (${_activeStreams.length} streams)');
  List<Future<void>> closeFutures = [];
  _activeStreams.values.toList().forEach((adapter) {
    _logger.fine('[UDXSessionConn $id] Closing stream adapter ${adapter.id()}');
    closeFutures.add(adapter.close());
  });

  try {
    final streamCloseStart = DateTime.now();
    await Future.wait(closeFutures).catchError((e) {
      _logger.warning('[UDXSessionConn $id] Error closing one or more UDX streams: $e');
    });
    final streamCloseDuration = DateTime.now().difference(streamCloseStart);
    _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: All active streams closed in ${streamCloseDuration.inMilliseconds}ms');
    _activeStreams.clear();

    if (_isDialer) {
      _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: 4. Dialer session, closing its UDPSocket');
      final socketCloseStart = DateTime.now();
      await _udpSocket.close();
      final socketCloseDuration = DateTime.now().difference(socketCloseStart);
      _logger.fine('[UDXSessionConn $id] CLEANUP_ORDER: Dialer UDPSocket closed in ${socketCloseDuration.inMilliseconds}ms');
    }
  } catch (e) {
    _logger.warning('[UDXSessionConn $id] Error closing UDX resources for session $id: $e');
  }

  _isClosed = true;
  _isClosing = false;

  // Phase 1.1: UDX Connection Lifecycle Analysis - State change logging
  _logger.fine('[UDXSessionConn $id] STATE_CHANGE: closing -> closed, reason: cleanup_complete');
  _connManager.updateState(this, ConnectionState.closed, error: null);
  _onClosedCallback?.call(this);

  if (!_closedCompleter.isCompleted) {
    _logger.fine('[UDXSessionConn $id] Completing close completer.');
    _closedCompleter.complete();
  }

  final totalCloseDuration = DateTime.now().difference(closeStart);
  _logger.fine('[UDXSessionConn $id] CLOSE_COMPLETE: Total close duration: ${totalCloseDuration.inMilliseconds}ms');
}