close method
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');
}