📄 downloadmanager.cpp
字号:
bool DownloadManager::handleData(UserConnection* aSource, const u_int8_t* aData, int aLen) {
dcassert(aSource->getState() == UserConnection::STATE_DONE);
Download* d = aSource->getDownload();
dcassert(d != NULL);
try {
if(d->isSet(Download::FLAG_ROLLBACK)) {
if(!checkRollback(d, aData, aLen)) {
fire(DownloadManagerListener::FAILED, d, STRING(ROLLBACK_INCONSISTENCY));
string target = d->getTarget();
aSource->setDownload(NULL);
removeDownload(d);
QueueManager::getInstance()->removeSource(target, aSource->getUser(), QueueItem::Source::FLAG_ROLLBACK_INCONSISTENCY);
removeConnection(aSource);
return false;
}
} else {
d->getFile()->write(aData, aLen);
}
d->addPos(aLen);
} catch(const FileException& e) {
fire(DownloadManagerListener::FAILED, d, e.getError());
aSource->setDownload(NULL);
removeDownload(d);
removeConnection(aSource);
return false;
}
return true;
}
void DownloadManager::onModeChange(UserConnection* aSource, int /*aNewMode*/) {
handleEndData(aSource);
}
/** Download finished! */
void DownloadManager::handleEndData(UserConnection* aSource) {
dcassert(aSource->getState() == UserConnection::STATE_DONE);
Download* d = aSource->getDownload();
dcassert(d != NULL);
// First, finish writing the file (flushing the buffers and closing the file...)
try {
d->getFile()->close();
// Check if we're anti-fragging...
if(d->isSet(Download::FLAG_ANTI_FRAG)) {
// Ok, rename the file to what we expect it to be...
try {
const string& tgt = d->getTempTarget().empty() ? d->getTarget() : d->getTempTarget();
File::renameFile(tgt + ANTI_FRAG_EXT, tgt);
d->unsetFlag(Download::FLAG_ANTI_FRAG);
} catch(const FileException& e) {
dcdebug("AntiFrag: %s\n", e.getError().c_str());
// Now what?
}
}
} catch(const FileException& e) {
fire(DownloadManagerListener::FAILED, d, e.getError());
aSource->setDownload(NULL);
removeDownload(d);
removeConnection(aSource);
return;
}
dcassert(d->getPos() == d->getSize());
dcdebug("Download finished: %s, size %I64d\n", d->getTarget().c_str(), d->getSize());
// Check if we have some crc:s...
dcassert(d->getFile() != NULL);
if(BOOLSETTING(SFV_CHECK)) {
d->getFile()->close();
SFVReader sfv(d->getTarget());
if(sfv.hasCRC()) {
bool crcMatch;
const string& tgt = d->getTempTarget().empty() ? d->getTarget() : d->getTempTarget();
if(d->getFile()->hasCRC32()) {
crcMatch = (d->getFile()->getCRC32() == sfv.getCRC());
} else {
// More complicated, we have to reread the file
try {
File f(tgt, File::READ, File::OPEN, true);
const u_int32_t BUF_SIZE = 16 * 65536;
AutoArray<u_int8_t> b(BUF_SIZE);
while(f.read((u_int8_t*)b, BUF_SIZE) > 0)
; // Keep on looping...
crcMatch = (f.getCRC32() == sfv.getCRC());
} catch (FileException&) {
// Nope; read failed...
goto noCRC;
}
}
if(!crcMatch) {
File::deleteFile(tgt);
dcdebug("DownloadManager: CRC32 mismatch for %s\n", d->getTarget().c_str());
fire(DownloadManagerListener::FAILED, d, STRING(SFV_INCONSISTENCY));
string target = d->getTarget();
aSource->setDownload(NULL);
removeDownload(d);
QueueManager::getInstance()->removeSource(target, aSource->getUser(), QueueItem::Source::FLAG_CRC_WARN, false);
checkDownloads(aSource);
return;
}
d->setFlag(Download::FLAG_CRC32_OK);
dcdebug("DownloadManager: CRC32 match for %s\n", d->getTarget().c_str());
}
}
noCRC:
delete d->getFile();
d->setFile(NULL);
if(BOOLSETTING(LOG_DOWNLOADS)) {
StringMap params;
params["target"] = d->getTarget();
params["user"] = aSource->getUser()->getNick();
params["hub"] = aSource->getUser()->getLastHubName();
params["hubip"] = aSource->getUser()->getLastHubIp();
params["size"] = Util::toString(d->getSize());
params["sizeshort"] = Util::formatBytes(d->getSize());
params["chunksize"] = Util::toString(d->getTotal());
params["chunksizeshort"] = Util::formatBytes(d->getTotal());
params["speed"] = Util::formatBytes(d->getAverageSpeed()) + "/s";
params["time"] = Util::formatSeconds((GET_TICK() - d->getStart()) / 1000);
params["sfv"] = Util::toString(d->isSet(Download::FLAG_CRC32_OK) ? 1 : 0);
LOG(DOWNLOAD_AREA, Util::formatParams(SETTING(LOG_FORMAT_POST_DOWNLOAD), params));
}
// Check if we need to move the file
if( !d->getTempTarget().empty() && (Util::stricmp(d->getTarget().c_str(), d->getTempTarget().c_str()) != 0) ) {
try {
Util::ensureDirectory(d->getTarget());
if(File::getSize(d->getTempTarget()) > MOVER_LIMIT) {
mover.moveFile(d->getTempTarget(), d->getTarget());
} else {
File::renameFile(d->getTempTarget(), d->getTarget());
}
d->setTempTarget(Util::emptyString);
} catch(const FileException&) {
// Huh??? Now what??? Oh well...let it be...
}
}
fire(DownloadManagerListener::COMPLETE, d);
aSource->setDownload(NULL);
removeDownload(d, true);
checkDownloads(aSource);
}
void DownloadManager::onMaxedOut(UserConnection* aSource) {
if(aSource->getState() != UserConnection::STATE_FILELENGTH) {
dcdebug("DM::onMaxedOut Bad state, ignoring\n");
return;
}
Download* d = aSource->getDownload();
dcassert(d != NULL);
fire(DownloadManagerListener::FAILED, d, STRING(NO_SLOTS_AVAILABLE));
aSource->setDownload(NULL);
removeDownload(d);
removeConnection(aSource);
}
void DownloadManager::onFailed(UserConnection* aSource, const string& aError) {
Download* d = aSource->getDownload();
if(d == NULL) {
removeConnection(aSource);
return;
}
fire(DownloadManagerListener::FAILED, d, aError);
string target = d->getTarget();
aSource->setDownload(NULL);
removeDownload(d);
if(aError.find("File Not Available") != string::npos) {
QueueManager::getInstance()->removeSource(target, aSource->getUser(), QueueItem::Source::FLAG_FILE_NOT_AVAILABLE, false);
}
removeConnection(aSource);
}
void DownloadManager::removeDownload(Download* d, bool finished /* = false */) {
if(d->getFile()) {
try {
if(d->isSet(Download::FLAG_ANTI_FRAG)) {
// Ok, set the pos to whereever it was last writing and hope for the best...
d->getFile()->close();
const string& tgt = d->getTempTarget().empty() ? d->getTarget() : d->getTempTarget();
File::renameFile(tgt + ANTI_FRAG_EXT, tgt);
d->unsetFlag(Download::FLAG_ANTI_FRAG);
} else {
d->getFile()->close();
}
delete d->getFile();
} catch(const FileException&) {
finished = false;
}
d->setFile(NULL);
}
if(d->getComp()) {
delete d->getComp();
d->setComp(NULL);
}
{
Lock l(cs);
// Either I'm stupid or the msvc7 optimizer is doing something _very_ strange here...
// STL-port -D_STL_DEBUG complains that .begin() and .end() don't have the same owner (!),
// but only in release build
dcassert(find(downloads.begin(), downloads.end(), d) != downloads.end());
// downloads.erase(find(downloads.begin(), downloads.end(), d));
for(Download::Iter i = downloads.begin(); i != downloads.end(); ++i) {
if(*i == d) {
downloads.erase(i);
break;
}
}
}
QueueManager::getInstance()->putDownload(d, finished);
}
void DownloadManager::abortDownload(const string& aTarget) {
Lock l(cs);
for(Download::Iter i = downloads.begin(); i != downloads.end(); ++i) {
Download* d = *i;
if(d->getTarget() == aTarget) {
dcassert(d->getUserConnection() != NULL);
d->getUserConnection()->disconnect();
break;
}
}
}
void DownloadManager::onFileNotAvailable(UserConnection* aSource) throw() {
Download* d = aSource->getDownload();
dcassert(d != NULL);
dcdebug("File Not Available: %s\n", d->getTarget().c_str());
if(d->getFile()) {
delete d->getFile();
d->setFile(NULL);
}
fire(DownloadManagerListener::FAILED, d, d->getTargetFileName() + ": " + STRING(FILE_NOT_AVAILABLE));
aSource->setDownload(NULL);
QueueManager::getInstance()->removeSource(d->getTarget(), aSource->getUser(), QueueItem::Source::FLAG_FILE_NOT_AVAILABLE, false);
removeDownload(d, false);
checkDownloads(aSource);
}
// UserConnectionListener
void DownloadManager::onAction(UserConnectionListener::Types type, UserConnection* conn) throw() {
switch(type) {
case UserConnectionListener::MAXED_OUT: onMaxedOut(conn); break;
case UserConnectionListener::FILE_NOT_AVAILABLE: onFileNotAvailable(conn); break;
case UserConnectionListener::SENDING: onSending(conn); break;
default: break;
}
}
void DownloadManager::onAction(UserConnectionListener::Types type, UserConnection* conn, const string& line) throw() {
switch(type) {
case UserConnectionListener::FILE_LENGTH:
onFileLength(conn, line); break;
case UserConnectionListener::FAILED:
onFailed(conn, line); break;
default:
break;
}
}
void DownloadManager::onAction(UserConnectionListener::Types type, UserConnection* conn, const u_int8_t* data, int len) throw() {
switch(type) {
case UserConnectionListener::DATA:
onData(conn, data, len); break;
default:
break;
}
}
void DownloadManager::onAction(UserConnectionListener::Types type, UserConnection* conn, int mode) throw() {
switch(type) {
case UserConnectionListener::MODE_CHANGE:
onModeChange(conn, mode); break;
default:
break;
}
}
// TimerManagerListener
void DownloadManager::onAction(TimerManagerListener::Types type, u_int32_t aTick) throw() {
switch(type) {
case TimerManagerListener::SECOND:
onTimerSecond(aTick); break;
default:
break;
}
}
/**
* @file
* $Id: DownloadManager.cpp,v 1.74 2003/06/20 10:49:27 arnetheduck Exp $
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -