/// <summary> /// Permette di ricevere una risposta da un vicino. /// </summary> /// <param name="sourceNodeId">L'identificatore associato al vicino.</param> /// <param name="reply">La risposta inviata dal vicino.</param> public void Reply(string sourceNodeId, ReplyData reply) { if (m_KnownNeighbors.Contains(sourceNodeId)) { WriteToLog("The received reply from node {0} has been accepted: {1}.", sourceNodeId, reply.MsgId); m_MessagesHandler.HandleReceivedReply(reply); } else { WriteToLog("The received reply from node {0} has been dropped: {1}.", sourceNodeId, reply.MsgId); } }
/// <summary> /// Verifica se l'identificativo della connessione specificata esiste e se è associato ad una connessione /// attiva con un vicino ed in tal caso invia la risposta specificata con i risultati di una ricerca. /// </summary> /// <param name="reply">I dati della risposta da inviare.</param> /// <param name="connectionId">L'identificativo della connessione su cui inviare la risposta.</param> private void SendReply(ReplyData reply, string connectionId) { m_NeighborhoodManager.SendReply(reply, connectionId); WriteToLog("Reply {0} sent back to connection {1}. Found services: [{2}].", reply.MsgId, connectionId, string.Join(", ", reply.FoundServices)); }
/// <summary> /// Verifica quali, tra le risorse conosciute da questo nodo, sono compatibili con le opzioni di ricerca /// specificate nella query ricevuta, quindi invia l'eventuale risposta sulla connessione di provenienza /// della query. /// </summary> /// <param name="query">I dati della richiesta ricevuta.</param> /// <param name="sourceConnectionId">L'identificativo della connessione di provenienza della richiesta.</param> /// <remarks> /// Se si specifica null per almeno uno dei due parametri oppure se l'identificativo della connessione /// di provenienza della richiesta è una stringa vuota oppure formata da soli spazi, questo metodo non /// esegue alcuna azione, ignorando i parametri specificati. /// </remarks> private void ReplyToQuery(QueryData query, string sourceConnectionId) { Thread.Sleep(100); // simula ritardo di rete if (string.IsNullOrWhiteSpace(sourceConnectionId) || query == null) return; WriteToLog("Processing query {0} ...", query.MsgId); List<Uri> found = m_ResourceCache.Search( delegate(Uri uri, IEnumerable<TaskPerformerInfo> resources) { foreach (var resource in resources) { if (resource.Name == query.Options.Name && resource.Version == query.Options.Version) { return true; } } return false; } ).ToList<Uri>(); WriteToLog("Processed query {0}: {1} resources found.", query.MsgId, found.Count); if (found.Count > 0) { ReplyData reply = new ReplyData(query.MsgId, query.HopsCount, 0) { FoundServices = found }; SendReply(reply, sourceConnectionId); } }
/// <summary> /// Inoltra una risposta ricevuta da un vicino, verificando se occorre inviarla ad uno dei vicini successivi /// oppure se è giunta a destinazione, ovvero presso il nodo da cui è partita la richiesta a cui tale risposta /// si riferisce. /// La procedura prevede l'aggiornamento preliminare di due proprietà relative alla risposta: il TimeToLive /// viene decrementato di 1, mentre HopsCount viene incrementato di 1. Se il TimeToLive si mantiene maggiore /// di zero, la risposta viene inviata al vicino successivo, altrimenti vuol dire che la risposta è arrivata /// a destinazione: in quest'ultimo caso, recupera il riferimento alla ricerca inizialmente inviata e lo usa /// per aggiornare i risultati della ricerca con quelli contenuti nella risposta. /// </summary> /// <param name="reply">I dati della risposta ricevuta da un vicino.</param> /// <remarks> /// Se si specifica null per l'unico parametro previsto, questo metodo non esegue alcuna azione, ignorando /// il parametro specificato. /// </remarks> private void ForwardReceivedReply(ReplyData reply) { Thread.Sleep(100); // simula ritardo di rete if (reply == null || reply.TimeToLive == 0) return; reply.TimeToLive--; reply.HopsCount++; if (reply.TimeToLive > 0) // verifica che la risposta non sia giunta a destinazione { string targetConnectionId; lock (m_ForwardingTableLocker) { if (!m_ForwardingTable.TryGetSourceConnection(reply.MsgId, out targetConnectionId) || targetConnectionId == null) { return; // ignora messaggio con identificativo non trovato } } WriteToLog("Sending received reply {0} back to connection {1}. Found services: [{2}].", reply.MsgId, targetConnectionId, string.Join(", ", reply.FoundServices)); SendReply(reply, targetConnectionId); // inoltra messaggio al vicino di provenienza della richiesta } else // TTL si è azzerato { WriteToLog("Reply {0} arrived to destination. Found services: [{1}].", reply.MsgId, string.Join(", ", reply.FoundServices)); SearchData searchReference = null; // riferimento alla ricerca inizialmente inviata lock (m_ForwardingTableLocker) { ForwardingTable.Entry entry = m_ForwardingTable.GetEntry(reply.MsgId); if (entry != null && entry.SourceConnection == null) { searchReference = entry.SearchReference; } } if (searchReference != null) { bool updated = m_SearchManager.UpdateResult(searchReference, reply.FoundServices); if (updated) { // aggiornamento completato correttamente WriteToLog("Updated search results from the reply {0}.", reply.MsgId); } else { // ricerca scaduta WriteToLog("Expired target search for the reply {0}.", reply.MsgId); } } } }
/// <summary> /// Gestisce una risposta ricevuta da un vicino, verificando se occorre inviarla ad uno dei vicini successivi /// oppure se è giunta a destinazione, ovvero presso il nodo da cui è partita la richiesta a cui tale risposta /// si riferisce. /// La procedura prevede l'aggiornamento preliminare di due proprietà relative alla risposta: il TimeToLive /// viene decrementato di 1, mentre HopsCount viene incrementato di 1. Se il TimeToLive si mantiene maggiore /// di zero, la risposta viene inviata al vicino successivo, altrimenti vuol dire che la risposta è arrivata /// a destinazione: in quest'ultimo caso, recupera il riferimento alla ricerca inizialmente inviata e lo usa /// per aggiornare i risultati della ricerca con quelli contenuti nella risposta. /// </summary> /// <param name="reply">I dati della risposta ricevuta da un vicino.</param> /// <remarks> /// Se si specifica null per l'unico parametro previsto, questo metodo non esegue alcuna azione, ignorando /// il parametro specificato. /// </remarks> public void HandleReceivedReply(ReplyData reply) { if (reply.TimeToLive > 0) { Task.Factory.StartNew(() => ForwardReceivedReply(reply), CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } }