connect method

  1. @override
Future<void> connect(
  1. AddrInfo pi, {
  2. Context? context,
})
override

Connect ensures there is a connection between this host and the peer with given peer.ID. Connect will absorb the addresses in pi into its internal peerstore. If there is not an active connection, Connect will issue a h.Network.Dial, and block until a connection is open, or an error is returned.

If context is not provided, a new Context will be created.

Implementation

@override
Future<void> connect(AddrInfo pi, {Context? context}) async {
  final effectiveCtx = context ?? Context(); // Ensure context is not null

  // Use specific getters from Context
  bool forceDirect = effectiveCtx.getForceDirectDial().$1;
  bool canUseLimitedConn = effectiveCtx.getAllowLimitedConn().$1;

  if (!forceDirect) {
    final connectedness = network.connectedness(pi.id);
    if (connectedness == Connectedness.connected ||
        (canUseLimitedConn && connectedness == Connectedness.limited)) {
      return;
    }
  }

  if (pi.addrs.isNotEmpty) {
    // The Go version uses peerstore.TempAddrTTL.
    // Dart `AddressTTL.tempAddrTTL` (Duration(minutes: 2)) matches Go's `time.Second * 120`.
    await peerStore.addrBook.addAddrs(pi.id, pi.addrs, AddressTTL.tempAddrTTL);
  }

  List<MultiAddr> currentAddrs = await peerStore.addrBook.addrs(pi.id);
  if (currentAddrs.isEmpty) {
    try {
      currentAddrs = await _findPeerAddrs(effectiveCtx, pi.id);
      if (currentAddrs.isEmpty) {
        throw Exception('No addresses found for peer ${pi.id} after routing');
      }
      // Add these newly found addresses to the peerstore
      peerStore.addrBook.addAddrs(pi.id, currentAddrs, AddressTTL.tempAddrTTL);
    } catch (e) {
      // _log.warning('Failed to find peer addresses for ${pi.id}: $e');
      rethrow;
    }
  }

  // Issue 448: if our address set includes routed specific relay addrs,
  // we need to make sure the relay's addr itself is in the peerstore or else
  // we won't be able to dial it.
  for (final addr in currentAddrs) {
    if (addr.hasProtocol(multiaddr_protocol.Protocols.circuit.name)) { // Check if it's a relay address
      final String? relayIdStr = addr.valueForProtocol(multiaddr_protocol.Protocols.p2p.name);
      if (relayIdStr == null) {
          // _log.warning('Relay address $addr missing P2P component value');
          continue;
      }
      final PeerId relayId;
      try {
        relayId = PeerId.fromString(relayIdStr);
      } catch (e) {
        // _log.warning('Failed to parse relay ID in address $addr: $e');
        continue;
      }

      final relayAddrsInStore = await peerStore.addrBook.addrs(relayId);
      if (relayAddrsInStore.isNotEmpty) {
        continue; // We already have addrs for this relay
      }

      try {
        final foundRelayAddrs = await _findPeerAddrs(effectiveCtx, relayId);
        if (foundRelayAddrs.isNotEmpty) {
          peerStore.addrBook.addAddrs(relayId, foundRelayAddrs, AddressTTL.tempAddrTTL);
        } else {
          // _log.info('Could not find addresses for relay peer $relayId');
        }
      } catch (e) {
        // _log.warning('Failed to find relay $relayId addresses: $e');
        continue;
      }
    }
  }


  final addrInfoToConnect = AddrInfo(pi.id, currentAddrs);

  try {
    await _host.connect(addrInfoToConnect, context: effectiveCtx);
  } catch (connectError) {
    // We couldn't connect. Let's check if we have the most
    // up-to-date addresses for the given peer.
    List<MultiAddr> newAddrs;
    try {
      newAddrs = await _findPeerAddrs(effectiveCtx, pi.id);
    } catch (findErr) {
      // _log.debug('Failed to find more peer addresses for ${pi.id}: $findErr');
      rethrow ; // Original connect error is more relevant
    }

    if (newAddrs.isEmpty && currentAddrs.isEmpty) {
       rethrow ; // No addresses before, no new addresses now.
    }

    final currentAddrsSet = Set<String>.from(currentAddrs.map((a) => a.toString()));
    bool foundNewUniqueAddr = false;
    for (final newAddr in newAddrs) {
      if (!currentAddrsSet.contains(newAddr.toString())) {
        foundNewUniqueAddr = true;
        break;
      }
    }

    if (foundNewUniqueAddr) {
      // _log.info('Found new addresses for ${pi.id}, attempting to connect again.');
      // Add new addresses to peerstore before retrying
      peerStore.addrBook.addAddrs(pi.id, newAddrs, AddressTTL.tempAddrTTL);
      final updatedAddrInfo = AddrInfo(pi.id, newAddrs);
      // Retry connection with new addresses
      try {
        await _host.connect(updatedAddrInfo, context: effectiveCtx);
        return; // Successfully connected on retry
      } catch (retryError) {
        // _log.warning('Still failed to connect to ${pi.id} after finding new addresses: $retryError');
        rethrow ; // Throw the error from the retry attempt
      }
    }
    // No appropriate new address found, or all new addresses were already known.
    // Return the original dial error.
    rethrow;
  }
}