getReachability method

  1. @override
Future<Result> getReachability(
  1. PeerId peerId,
  2. List<Request> requests
)
override

Check reachability for the given addresses with a specific peer

Implementation

@override
Future<Result> getReachability(PeerId peerId, List<Request> requests) async {
  // Create a stream to the peer
  final context = Context();
  final protocols = [AutoNATv2Protocols.dialProtocol];
  final stream = await host.newStream(peerId, protocols, context);

  try{
    await stream.scope().setService(AutoNATv2Protocols.serviceName);
  }catch(ex){
    stream.reset();
    throw Exception('Failed to attach stream ${AutoNATv2Protocols.dialProtocol} to service ${AutoNATv2Protocols.serviceName}');
  }

  try {
    await stream.scope().reserveMemory(maxMsgSize, ReservationPriority.always);
    // Reserve memory
  }catch(ex){
    stream.reset();
    throw Exception('Failed to reserve memory for stream ${AutoNATv2Protocols.dialProtocol}');
  }

  // Set deadline
  stream.setDeadline(DateTime.now().add(streamTimeout));

  // Generate a random nonce
  final nonce = Random().nextInt(1 << 32);

  // Create a completer for the dial-back
  final completer = Completer<MultiAddr>();
  _dialBackQueues[nonce] = completer;

  try {
    // Create and send the dial request
    final request = _createDialRequest(requests, nonce);
    await stream.write(request.writeToBuffer());

    // Read the response
    Message response;
    try {
      final responseData = await stream.read();
      response = Message.fromBuffer(responseData);
    } catch (e) {
      stream.reset();
      throw Exception('Dial message read failed: $e');
    }

    // Handle the response
    if (response.hasDialResponse()) {
      // Process the dial response
      return _processDialResponse(response.dialResponse, requests, completer);
    } else if (response.hasDialDataRequest()) {
      // Handle dial data request
      try {
        await _validateAndSendDialData(requests, response, stream);
      } catch (e) {
        stream.reset();
        throw Exception('Invalid dial data request: $e');
      }

      // Read the dial response after sending dial data
      try {
        final responseData = await stream.read();
        response = Message.fromBuffer(responseData);
      } catch (e) {
        stream.reset();
        throw Exception('Dial response read failed: $e');
      }

      if (!response.hasDialResponse()) {
        stream.reset();
        throw Exception('Invalid response type after dial data');
      }

      // Process the dial response
      return _processDialResponse(response.dialResponse, requests, completer);
    } else {
      stream.reset();
      throw Exception('Invalid message type: ${response.whichMsg()}');
    }
  } finally {
    _dialBackQueues.remove(nonce);
    stream.close();
  }
}