/** Download finished! */ void DownloadManager::endData(UserConnection* aSource) { dcassert(aSource->getState() == UserConnection::STATE_RUNNING); Download* d = aSource->getDownload(); dcassert(d != NULL); if(d->getType() == Transfer::TYPE_TREE) { d->getFile()->flush(); int64_t bl = 1024; while(bl * (int64_t)d->getTigerTree().getLeaves().size() < d->getTigerTree().getFileSize()) bl *= 2; d->getTigerTree().setBlockSize(bl); d->getTigerTree().calcRoot(); if(!(d->getTTH() == d->getTigerTree().getRoot())) { // This tree is for a different file, remove from queue... removeDownload(d); fire(DownloadManagerListener::Failed(), d, _("Full tree does not match TTH root")); QueueManager::getInstance()->removeSource(d->getPath(), aSource->getUser(), QueueItem::Source::FLAG_BAD_TREE, false); QueueManager::getInstance()->putDownload(d, false); checkDownloads(aSource); return; } d->setTreeValid(true); } else { // First, finish writing the file (flushing the buffers and closing the file...) try { d->getFile()->flush(); } catch(const Exception& e) { d->resetPos(); failDownload(aSource, e.getError()); return; } aSource->setSpeed(d->getAverageSpeed()); aSource->updateChunkSize(d->getTigerTree().getBlockSize(), d->getSize(), GET_TICK() - d->getStart()); dcdebug("Download finished: %s, size " I64_FMT ", downloaded " I64_FMT "\n", d->getPath().c_str(), static_cast<long long int>(d->getSize()), static_cast<long long int>(d->getPos())); if(BOOLSETTING(LOG_DOWNLOADS) && (BOOLSETTING(LOG_FILELIST_TRANSFERS) || d->getType() == Transfer::TYPE_FILE)) { logDownload(aSource, d); } } removeDownload(d); fire(DownloadManagerListener::Complete(), d); QueueManager::getInstance()->putDownload(d, true); checkDownloads(aSource); }
void DownloadManager::on(TimerManagerListener::Second, uint64_t aTick) noexcept { typedef vector<pair<string, UserPtr> > TargetList; TargetList dropTargets; { Lock l(cs); DownloadList tickList; // Tick each ongoing download for(DownloadList::iterator i = downloads.begin(); i != downloads.end(); ++i) { if((*i)->getPos() > 0) { tickList.push_back(*i); (*i)->tick(); } } if(tickList.size() > 0) fire(DownloadManagerListener::Tick(), tickList); // Automatically remove or disconnect slow sources if((uint32_t)(aTick / 1000) % SETTING(AUTODROP_INTERVAL) == 0) { for(DownloadList::iterator i = downloads.begin(); i != downloads.end(); ++i) { Download* d = *i; uint64_t timeElapsed = aTick - d->getStart(); uint64_t timeInactive = aTick - d->getUserConnection().getLastActivity(); uint64_t bytesDownloaded = d->getPos(); bool timeElapsedOk = timeElapsed >= (uint32_t)SETTING(AUTODROP_ELAPSED) * 1000; bool timeInactiveOk = timeInactive <= (uint32_t)SETTING(AUTODROP_INACTIVITY) * 1000; bool speedTooLow = timeElapsedOk && timeInactiveOk && bytesDownloaded > 0 ? bytesDownloaded / timeElapsed * 1000 < (uint32_t)SETTING(AUTODROP_SPEED) : false; bool isUserList = d->getType() == Transfer::TYPE_FULL_LIST; bool onlineSourcesOk = isUserList ? true : QueueManager::getInstance()->countOnlineSources(d->getPath()) >= SETTING(AUTODROP_MINSOURCES); bool filesizeOk = !isUserList && d->getSize() >= ((int64_t)SETTING(AUTODROP_FILESIZE)) * 1024; bool dropIt = (isUserList && BOOLSETTING(AUTODROP_FILELISTS)) || (filesizeOk && BOOLSETTING(AUTODROP_ALL)); if(speedTooLow && onlineSourcesOk && dropIt) { if(BOOLSETTING(AUTODROP_DISCONNECT) && isUserList) { d->getUserConnection().disconnect(); } else { dropTargets.push_back(make_pair(d->getPath(), d->getUser())); } } } } } for(TargetList::iterator i = dropTargets.begin(); i != dropTargets.end(); ++i) { QueueManager::getInstance()->removeSource(i->first, i->second, QueueItem::Source::FLAG_SLOW_SOURCE); } }
void DownloadManager::fileNotAvailable(UserConnection* aSource) { if(aSource->getState() != UserConnection::STATE_SND) { dcdebug("DM::fileNotAvailable Invalid state, disconnecting"); aSource->disconnect(); return; } Download* d = aSource->getDownload(); dcassert(d != NULL); dcdebug("File Not Available: %s\n", d->getPath().c_str()); removeDownload(d); fire(DownloadManagerListener::Failed(), d, str(F_("%1%: File not available") % d->getTargetFileName())); QueueManager::getInstance()->removeSource(d->getPath(), aSource->getUser(), d->getType() == Transfer::TYPE_TREE ? QueueItem::Source::FLAG_NO_TREE : QueueItem::Source::FLAG_FILE_NOT_AVAILABLE, false); QueueManager::getInstance()->putDownload(d, false); checkDownloads(aSource); }