public async Task <IEnumerable <Node> > ExecuteAsync() { var activeQueries = new List <Task <SendQueryEventArgs> > (); var closestNodes = new ClosestNodesCollection(InfoHash); var closestActiveNodes = new ClosestNodesCollection(InfoHash); foreach (Node node in Engine.RoutingTable.GetClosest(InfoHash)) { if (closestNodes.Add(node)) { activeQueries.Add(Engine.SendQueryAsync(new GetPeers(Engine.LocalId, InfoHash), node)); } } while (activeQueries.Count > 0) { var completed = await Task.WhenAny(activeQueries); activeQueries.Remove(completed); // If it timed out or failed just move to the next query. SendQueryEventArgs query = await completed; if (query.Response == null) { continue; } var response = (GetPeersResponse)query.Response; // The response had some actual peers if (response.Values != null) { // We have actual peers! var peers = Peer.Decode(response.Values); Engine.RaisePeersFound(InfoHash, peers); foreach (var peer in peers) { FoundPeers.Add(peer); } } // The response contains nodes which should be closer to our target. If they are closer than nodes // we've already checked, then let's query them! if (response.Nodes != null && FoundPeers.Count < MaxPeers) { foreach (Node node in Node.FromCompactNode(response.Nodes)) { if (closestNodes.Add(node)) { activeQueries.Add(Engine.SendQueryAsync(new GetPeers(Engine.LocalId, InfoHash), node)); } } } closestActiveNodes.Add(query.Node); } // Finally, return the 8 closest nodes we discovered during this phase. These are the nodes we should // announce to later. return(closestActiveNodes); }
async Task SendFindNode(IEnumerable <Node> newNodes) { var activeRequests = new List <Task <SendQueryEventArgs> > (); var nodes = new ClosestNodesCollection(engine.LocalId); foreach (Node node in newNodes) { var request = new FindNode(engine.LocalId, engine.LocalId); activeRequests.Add(engine.SendQueryAsync(request, node)); nodes.Add(node); } while (activeRequests.Count > 0) { var completed = await Task.WhenAny(activeRequests); activeRequests.Remove(completed); SendQueryEventArgs args = await completed; if (args.Response != null) { if (engine.RoutingTable.CountNodes() >= MinHealthyNodes) { initializationComplete.TrySetResult(null); } var response = (FindNodeResponse)args.Response; foreach (Node node in Node.FromCompactNode(response.Nodes)) { if (nodes.Add(node)) { var request = new FindNode(engine.LocalId, engine.LocalId); activeRequests.Add(engine.SendQueryAsync(request, node)); } } } } if (initialNodes.Count > 0 && engine.RoutingTable.NeedsBootstrap) { await new InitialiseTask(engine).ExecuteAsync(); } }