void Tests::compareExpectedResult(const Protos::Common::FindResult& result, const FindResult& expectedResult) { for (int i = 0; i < result.entry_size(); i++) { QVERIFY(expectedResult.contains(result.entry(i).level())); QVERIFY(expectedResult[result.entry(i).level()].contains(Common::ProtoHelper::getStr(result.entry(i).entry(), &Protos::Common::Entry::name))); } }
/** * Function called when data is recevied by the socket : The corresponding proto is created and the coresponding event is rised. */ void UDPListener::processPendingUnicastDatagrams() { while (this->unicastSocket.hasPendingDatagrams()) { QHostAddress peerAddress; const Common::MessageHeader& header = UDPListener::readDatagramToBuffer(this->unicastSocket, peerAddress); if (header.isNull()) continue; switch (header.getType()) { case Common::MessageHeader::CORE_CHUNKS_OWNED: { Protos::Core::ChunksOwned chunksOwnedMessage; chunksOwnedMessage.ParseFromArray(this->bodyBuffer, header.getSize()); if (chunksOwnedMessage.tag() != this->currentIMAliveTag) { L_WARN(QString("ChunksOwned : tag (%1) doesn't match current tag (%2)").arg(chunksOwnedMessage.tag()).arg(currentIMAliveTag)); continue; } if (chunksOwnedMessage.chunk_state_size() != this->currentChunkDownloads.size()) { L_WARN(QString("ChunksOwned : The size (%1) doesn't match the expected one (%2)").arg(chunksOwnedMessage.chunk_state_size()).arg(this->currentChunkDownloads.size())); continue; } for (int i = 0; i < chunksOwnedMessage.chunk_state_size(); i++) { if (chunksOwnedMessage.chunk_state(i)) this->currentChunkDownloads[i]->addPeerID(header.getSenderID()); else this->currentChunkDownloads[i]->rmPeerID(header.getSenderID()); } } break; case Common::MessageHeader::CORE_FIND_RESULT: { Protos::Common::FindResult findResultMessage; findResultMessage.ParseFromArray(this->bodyBuffer, header.getSize()); findResultMessage.mutable_peer_id()->set_hash(header.getSenderID().getData(), Common::Hash::HASH_SIZE); emit newFindResultMessage(findResultMessage); } break; default: L_WARN(QString("Unkown header type from unicast socket : %1").arg(header.getType(), 0, 16)); } } }
void Tests::printSearch(const QString& terms, const Protos::Common::FindResult& result) { qDebug() << "Search : " << terms; for (int i = 0; i < result.entry_size(); i++) qDebug() << "[" << result.entry(i).level() << "] " << Common::ProtoHelper::getStr(result.entry(i).entry(), &Protos::Common::Entry::name); }
/** * Function called when data is recevied by the socket : The corresponding proto is created and the coresponding event is rised. */ void UDPListener::processPendingUnicastDatagrams() { while (this->unicastSocket.hasPendingDatagrams()) { QHostAddress peerAddress; const Common::MessageHeader& header = UDPListener::readDatagramToBuffer(this->unicastSocket, peerAddress); if (header.isNull()) continue; try { const Common::Message& message = Common::Message::readMessageBody(header, this->bodyBuffer); switch (header.getType()) { case Common::MessageHeader::CORE_CHUNKS_OWNED: { const Protos::Core::ChunksOwned& chunksOwnedMessage = message.getMessage<Protos::Core::ChunksOwned>(); if (chunksOwnedMessage.tag() != this->currentIMAliveTag) { L_WARN(QString("ChunksOwned : tag (%1) doesn't match current tag (%2)").arg(chunksOwnedMessage.tag()).arg(currentIMAliveTag)); continue; } if (chunksOwnedMessage.chunk_state_size() != this->currentChunkDownloaders.size()) { L_WARN(QString("ChunksOwned : The size (%1) doesn't match the expected one (%2)").arg(chunksOwnedMessage.chunk_state_size()).arg(this->currentChunkDownloaders.size())); continue; } for (int i = 0; i < chunksOwnedMessage.chunk_state_size(); i++) if (PM::IPeer* peer = this->peerManager->getPeer(header.getSenderID())) { if (chunksOwnedMessage.chunk_state(i)) this->currentChunkDownloaders[i]->addPeer(peer); else this->currentChunkDownloaders[i]->rmPeer(peer); } } break; case Common::MessageHeader::CORE_FIND_RESULT: { Protos::Common::FindResult findResultMessage = message.getMessage<Protos::Common::FindResult>(); findResultMessage.mutable_peer_id()->set_hash(header.getSenderID().getData(), Common::Hash::HASH_SIZE); emit newFindResultMessage(findResultMessage); } break; default:; // Ignore other messages. } emit received(message); } catch(Common::ReadErrorException&) { L_WARN(QString("Unable to read an unicast message from peer %1 %2").arg(header.getSenderID().toStr()).arg(peerAddress.toString())); } } }
/** * This method is called several times, one by received entries. The entries are inserted into the model. * The given entries are sorted by their level, we will keep the sort when inserting the entry but with some modifications : * - The directories are put first. * - All entries with the same level are sorted first by their path (prefixed with the shared directory name) and then by their name. * - All file entries with the same chunks (identical data) are grouped. They can be owned by different peer. */ void SearchModel::result(const Protos::Common::FindResult& findResult) { if (findResult.entry_size() == 0) return; QList<const Protos::Common::FindResult_EntryLevel*> sortedEntries; for (int i = 0; i < findResult.entry_size(); i++) sortedEntries << &findResult.entry(i); qSort(sortedEntries.begin(), sortedEntries.end(), &findEntryLessThan); int currentIndex = 0; bool maxLevelChange = false; for (QListIterator<const Protos::Common::FindResult_EntryLevel*> i(sortedEntries); i.hasNext();) { const Protos::Common::FindResult_EntryLevel* entry = i.next(); if (this->setMaxLevel(entry->level())) maxLevelChange = true; // Search if a similar entry already exists. If so then insert the new tree as child. if (entry->entry().type() == Protos::Common::Entry_Type_FILE && entry->entry().chunk_size() > 0) { Common::Hash firstChunk = entry->entry().chunk(0).hash(); SearchTree* similarTree = 0; if ((similarTree = this->indexedFile.value(firstChunk)) && similarTree->isSameAs(entry->entry())) { if (similarTree->getNbChildren() == 0) { this->beginInsertRows(this->createIndex(0, 0, similarTree), 0, 0); similarTree->insertChild(similarTree); this->endInsertRows(); } // Search the better name (tree with the lowest level) to display it on the top. for (int i = 0; i <= similarTree->getNbChildren(); i++) { if (i == similarTree->getNbChildren() || static_cast<SearchTree*>(similarTree->getChild(i))->getLevel() > static_cast<int>(entry->level())) { this->beginInsertRows(this->createIndex(0, 0, similarTree), i, i); Common::Hash peerID = findResult.peer_id().hash(); SearchTree* newTree = similarTree->insertChild(i, *entry, peerID, this->peerListModel.getNick(peerID, tr("<unknown>"))); this->endInsertRows(); if (static_cast<int>(entry->level()) < similarTree->getLevel()) { const int row = similarTree->getOwnPosition(); similarTree->copyFrom(newTree); emit dataChanged(this->createIndex(row, 0, similarTree), this->createIndex(row, 3, similarTree)); } break; } } continue; } } currentIndex = this->insertTree(*entry, findResult.peer_id().hash(), currentIndex); } if (maxLevelChange && this->rowCount() > 0) emit dataChanged(this->createIndex(0, 2), this->createIndex(this->rowCount() - 1, 2)); }