/// <summary> /// Ask the next peer the question. /// </summary> async Task AskAsync(int taskId) { int pass = 0; int waits = 20; while (!runningQuery.IsCancellationRequested && waits > 0) { // Get the nearest peer that has not been visited. var peer = Dht.RoutingTable .NearestPeers(QueryKey) .Where(p => !visited.Contains(p)) .FirstOrDefault(); if (peer == null) { --waits; await Task.Delay(100); continue; } ++pass; visited.Add(peer); // Ask the nearest peer. await askCount.WaitAsync(runningQuery.Token).ConfigureAwait(false); var start = DateTime.Now; log.Debug($"Q{Id}.{taskId}.{pass} ask {peer}"); try { using (var timeout = new CancellationTokenSource(askTime)) using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, runningQuery.Token)) using (var stream = await Dht.Swarm.DialAsync(peer, Dht.ToString(), cts.Token).ConfigureAwait(false)) { // Send the KAD query and get a response. ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, queryMessage, PrefixStyle.Base128); await stream.FlushAsync(cts.Token).ConfigureAwait(false); var response = await ProtoBufHelper.ReadMessageAsync <DhtMessage>(stream, cts.Token).ConfigureAwait(false); // Process answer ProcessProviders(response.ProviderPeers); ProcessCloserPeers(response.CloserPeers); } var time = DateTime.Now - start; log.Debug($"Q{Id}.{taskId}.{pass} ok {peer} ({time.TotalMilliseconds} ms)"); } catch (Exception e) { Interlocked.Increment(ref failedConnects); var time = DateTime.Now - start; log.Warn($"Q{Id}.{taskId}.{pass} failed ({time.TotalMilliseconds} ms) - {e.Message}"); // eat it } finally { askCount.Release(); } } }
/// <summary> /// Ask the next peer the question. /// </summary> async Task AskAsync(int taskId) { int pass = 0; while (!runningQuery.IsCancellationRequested) { ++pass; // Get the nearest peer that has not been visited. var peer = Dht.RoutingTable .NearestPeers(QueryKey) .Where(p => !visited.Contains(p)) .FirstOrDefault(); if (peer == null) { return; } visited.Add(peer); // Ask the nearest peer. try { await askCount.WaitAsync(runningQuery.Token); log.Debug($"Q{Id}.{taskId}.{pass} ask {peer}"); using (var timeout = new CancellationTokenSource(askTime)) using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, runningQuery.Token)) using (var stream = await Dht.Swarm.DialAsync(peer, Dht.ToString(), cts.Token)) { // Send the KAD query and get a response. ProtoBuf.Serializer.SerializeWithLengthPrefix(stream, queryMessage, PrefixStyle.Base128); await stream.FlushAsync(cts.Token); var response = await ProtoBufHelper.ReadMessageAsync <DhtMessage>(stream, cts.Token); // Process answer ProcessProviders(response.ProviderPeers); ProcessCloserPeers(response.CloserPeers); } } catch (Exception e) { log.Warn($"Q{Id}.{taskId}.{pass} ask failed {e.Message}"); // eat it } finally { askCount.Release(); } } }