close method

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

Closes the network

Implementation

@override
Future<void> close() async {
  await _closedLock.synchronized(() async {
    if (_isClosed) return;
    _isClosed = true;


    // Close all listeners
    final listenersToClose = List<Listener>.from(_listeners); // Create a copy
    for (final listener in listenersToClose) {
      await listener.close(); // This might trigger onDone/onError, modifying original _listeners
    }
    _listeners.clear(); // Clear original list after all are processed

    // Close all connections
    await _connLock.synchronized(() async {
      final allConnsToClose = <SwarmConn>[];
      // Iterate over a copy of values if modification during iteration is possible
      // or clear the map after collecting all connections.
      final connectionLists = List<List<SwarmConn>>.from(_connections.values);
      for (final connsList in connectionLists) {
        allConnsToClose.addAll(connsList);
      }
      // It's safer to clear the original map after collecting all items if conn.close()
      // could lead to re-entrant calls that modify _connections.
      // However, if conn.close() only triggers notifiees that don't modify _connections directly,
      // iterating _connections.values and then _connections.clear() might be okay.
      // For max safety, let's clear after collecting.
      // _connections.clear(); // Moved down

      for (final conn in allConnsToClose) {
        await conn.close();
      }
      _connections.clear(); // Clear after all connections are processed and closed.
    });

    // Notify all notifiees about closed listeners and connections
    await _notifieeLock.synchronized(() async {
      // Create copies of lists to iterate over, to prevent concurrent modification
      final currentListenAddrs = List<MultiAddr>.from(_listenAddrs);

      // For connections, we need a deep enough copy if the inner lists could change.
      // However, connections should have been closed and removed from _connections by now.
      // The _connections map should be empty here if the above logic is correct.
      // Let's assume _notifiees list itself is stable during this block.
      final notifieesCopy = List<Notifiee>.from(_notifiees);

      for (final notifiee in notifieesCopy) {
        // Notify about closed listeners
        for (final addr in currentListenAddrs) {
          notifiee.listenClose(this, addr);
        }

        // Notify about closed connections
        // Since _connections should be empty, this loop might not run.
        // If it can run, we need to be careful.
        // The previous block iterates a copy of connections and closes them.
        // Here, we should notify based on what *was* closed.
        // This notification logic might be better integrated into the actual closing loops.
        // For now, let's assume this is for any remaining state.
        // The original code iterated _connections.values directly.
        // If _connections is cleared above, this loop is problematic.

        // Re-thinking: The notification for disconnected should happen when a conn is actually closed.
        // SwarmConn.close() calls swarm.removeConnection(), which calls notifiee.disconnected.
        // So, this explicit loop here might be redundant or even racy if removeConnection also iterates _notifiees.

        // Let's stick to notifying about listenClose for addresses that were active.
        // The disconnected notifications are handled by removeConnection.
      }
    });

    await _transportsLock.synchronized(() async {

      for (final transport in _transports){
        await transport.dispose();
      }
    });
  });
}