⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 queuemanager.cpp

📁 DC++ SourceCode P2P源码,具有一定的研究性
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* 
 * Copyright (C) 2001-2003 Jacek Sieka, j_s@telia.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "stdinc.h"
#include "DCPlusPlus.h"

#include "QueueManager.h"
#include "ConnectionManager.h"
#include "SearchManager.h"
#include "ClientManager.h"
#include "DownloadManager.h"
#include "UserConnection.h"
#include "SimpleXML.h"
#include "StringTokenizer.h"
#include "DirectoryListing.h"
#include "CryptoManager.h"
#include "ShareManager.h"
#include "DirectoryListing.h"

QueueManager* Singleton<QueueManager>::instance = NULL;

const string QueueManager::USER_LIST_NAME = "MyList.DcLst";

void QueueManager::UserQueue::add(QueueItem* qi, bool inFront /* = false */) {
	for(QueueItem::Source::Iter i = qi->getSources().begin(); i != qi->getSources().end(); ++i) {
		add(qi, (*i)->getUser(), inFront);
	}
}

void QueueManager::UserQueue::add(QueueItem* qi, const User::Ptr& aUser, bool inFront /* = false */) {
	dcassert(qi->getStatus() == QueueItem::STATUS_WAITING);
	dcassert(qi->isSource(aUser));
	dcassert(qi->getCurrent() == NULL);

	QueueItem::List& l = userQueue[qi->getPriority()][aUser];
	if(inFront) {
		l.insert(l.begin(), qi);		//l.push_front(qi);
	} else {
		l.push_back(qi);
	}
}

QueueItem* QueueManager::UserQueue::getNext(const User::Ptr& aUser, QueueItem::Priority minPrio) {
	int p = QueueItem::LAST - 1;

	do {
		QueueItem::UserListIter i = userQueue[p].find(aUser);
		if(i != userQueue[p].end()) {
			dcassert(!i->second.empty());
			return i->second.front();
		}
		p--;
	} while(p >= minPrio);

	return NULL;
}

void QueueManager::UserQueue::setRunning(QueueItem* qi, const User::Ptr& aUser) {
	dcassert(qi->getCurrent() == NULL);
	dcassert(qi->getStatus() == QueueItem::STATUS_WAITING);

	// Remove the download from the userQueue...
	remove(qi);
	
	// Set the flag to running...
	qi->setStatus(QueueItem::STATUS_RUNNING);
	qi->setCurrent(aUser);

	// Move the download to the running list...
	dcassert(running.find(aUser) == running.end());
	running[aUser] = qi;

}

void QueueManager::UserQueue::setWaiting(QueueItem* qi) {
	dcassert(qi->getCurrent() != NULL);
	dcassert(qi->getStatus() == QueueItem::STATUS_RUNNING);

	dcassert(running.find(qi->getCurrent()->getUser()) != running.end());
	// Remove the download from running
	running.erase(qi->getCurrent()->getUser());

	// Set flag to waiting
	qi->setCurrent(NULL);
	qi->setStatus(QueueItem::STATUS_WAITING);

	// Add to the userQueue
	add(qi);
}

QueueItem* QueueManager::UserQueue::getRunning(const User::Ptr& aUser) {
	QueueItem::UserIter i = running.find(aUser);
	return (i == running.end()) ? NULL : i->second;
}

void QueueManager::UserQueue::getUserList(User::List& l, QueueItem::Priority p) {
	QueueItem::UserListIter i = userQueue[p].begin();
	while(i != userQueue[p].end()) {
		if(i->first->isOnline())
			l.push_back(i->first);
		
		i++;
	}
}

void QueueManager::UserQueue::remove(QueueItem* qi) {
	if(qi->getStatus() == QueueItem::STATUS_RUNNING) {
		dcassert(qi->getCurrent() != NULL);
		remove(qi, qi->getCurrent()->getUser());
	} else {
		for(QueueItem::Source::Iter i = qi->getSources().begin(); i != qi->getSources().end(); ++i) {
			remove(qi, (*i)->getUser());
		}
	}
}

void QueueManager::UserQueue::remove(QueueItem* qi, const User::Ptr& aUser) {
	if(qi->getStatus() == QueueItem::STATUS_RUNNING) {
		// Remove from running...
		dcassert(qi->getCurrent() != NULL);
		dcassert(running.find(aUser) != running.end());
		running.erase(aUser);
	} else {
		dcassert(qi->isSource(aUser));
		dcassert(qi->getCurrent() == NULL);
		QueueItem::UserListMap& ulm = userQueue[qi->getPriority()];
		QueueItem::UserListIter j = ulm.find(aUser);
		dcassert(j != ulm.end());
		QueueItem::List& l = j->second;
		dcassert(find(l.begin(), l.end(), qi) != l.end());
		l.erase(find(l.begin(), l.end(), qi));
		
		if(l.empty()) {
			ulm.erase(j);
		}
	}
}

QueueManager::QueueManager() : dirty(false), searched(false), lastSave(0), queueFile(Util::getAppPath() + "Queue.xml") { 
	TimerManager::getInstance()->addListener(this); 
	SearchManager::getInstance()->addListener(this);
	ClientManager::getInstance()->addListener(this);
	Util::ensureDirectory(Util::getAppPath() + "FileLists\\");
	lastInsert = queue.end();
};

QueueManager::~QueueManager() { 
	SearchManager::getInstance()->removeListener(this);
	TimerManager::getInstance()->removeListener(this); 
	ClientManager::getInstance()->removeListener(this);

	saveQueue();

#ifdef WIN32

	if(!BOOLSETTING(KEEP_LISTS)) {
		string path = Util::getAppPath() + "FileLists\\";
		WIN32_FIND_DATA data;
		HANDLE hFind;
		
		hFind = FindFirstFile((path + "\\*.bz2").c_str(), &data);
		if(hFind != INVALID_HANDLE_VALUE) {
			do {
				File::deleteFile(path + data.cFileName);			
			} while(FindNextFile(hFind, &data));
			
			FindClose(hFind);
		}
		
		hFind = FindFirstFile((path + "\\*.DcLst").c_str(), &data);
		if(hFind != INVALID_HANDLE_VALUE) {
			do {
				File::deleteFile(path + data.cFileName);			
			} while(FindNextFile(hFind, &data));
			
			FindClose(hFind);
		}
	}
#endif
	for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i) {
		delete i->second;
	}
};

void QueueManager::onTimerMinute(u_int32_t /*aTick*/) {
	if(BOOLSETTING(AUTO_SEARCH)) {
		if(searched) {
			searched = false;
			return;
		}

		// We keep max 30 recent searches...this way we get an hour between
		// each duplicate search.
		while(recent.size() > 30) {
			recent.erase(recent.begin());
		}

		string fn;
		int64_t sz = 0;

		{
			Lock l(cs);
			if(queue.size() > 0) {
				// We pick a start position at random, hoping that we will find something to search for...
				QueueItem::StringMap::size_type start = (QueueItem::StringMap::size_type)Util::rand(queue.size());

				QueueItem::StringIter i = queue.begin();
				advance(i, start);
				QueueItem::StringIter j = i;
				for(; j != queue.end(); ++j) {
					QueueItem* q = j->second;
					
					if( (q->isSet(QueueItem::FLAG_USER_LIST)) || 
						(q->getStatus() == QueueItem::STATUS_RUNNING) ||
						(q->getPriority() == QueueItem::PAUSED) ||
						(q->hasOnlineUsers()) ||
						(find(recent.begin(), recent.end(), q->getTargetFileName()) != recent.end())
					  ) {
						continue;
					}
					searched = true;
					fn = q->getTargetFileName();
					sz = q->getSize() - 1;
					recent.push_back(q->getTargetFileName());
					break;
				}

				if(!searched) {
					for(j = queue.begin(); j != i; ++j) {
						QueueItem* q = j->second;

						if( (q->isSet(QueueItem::FLAG_USER_LIST)) || 
							(q->getStatus() == QueueItem::STATUS_RUNNING) ||
							(q->getPriority() == QueueItem::PAUSED) ||
							(q->hasOnlineUsers()) ||
							(find(recent.begin(), recent.end(), q->getTargetFileName()) != recent.end())
							) {
								continue;
						}

						fn = q->getTargetFileName();
						sz = q->getSize() - 1;
						recent.push_back(q->getTargetFileName());
						searched = true;
						break;
					}
				}
			}
		}

		if(!fn.empty())
			SearchManager::getInstance()->search(SearchManager::clean(fn), sz, ShareManager::getInstance()->getType(fn), SearchManager::SIZE_ATLEAST);
	}
}

enum { TEMP_LENGTH = 8 };
string QueueManager::getTempName(const string& aFileName) {
	string tmp;
	tmp.reserve(aFileName.length() + TEMP_LENGTH);
	string::size_type j = aFileName.rfind('.');
	
	if(j == string::npos) {
		tmp.append(aFileName);
	} else {
		tmp.append(aFileName.data(), j);
	}
	for(int i = 0; i < TEMP_LENGTH; i++) {
		tmp.append(1, (char)Util::rand('a', 'z'));
	}
	if(j != string::npos) {
		tmp.append(aFileName.data() + j, aFileName.length() - j);
	}
	return tmp;
}

void QueueManager::add(const string& aFile, int64_t aSize, User::Ptr aUser, const string& aTarget, 
					   bool aResume /* = true */, QueueItem::Priority p /* = QueueItem::DEFAULT */,
					   const string& aTempTarget /* = Util::emptyString */, bool addBad /* = true */, 
					   bool isDirectory /* = false */) throw(QueueException, FileException) {
	
	bool wantConnection = true;
	
	// Check that we're not downloading from ourselves...
	if(aUser->getClientNick() == aUser->getNick()) {
		throw QueueException(STRING(NO_DOWNLOADS_FROM_SELF));
	}

#ifdef WIN32
	if(aTarget.length() > MAX_PATH) {
		throw QueueException(STRING(TARGET_FILENAME_TOO_LONG));
	}
#endif

	// Check that target contains at least one directory...we don't want headless files...
	if(aTarget.find('\\') == string::npos) {
		throw QueueException(STRING(INVALID_TARGET_FILE));
	}

	string target = Util::filterFileName(aTarget);
	// Check that the file doesn't already exist...
	if( (aSize != -1) && (aSize <= File::getSize(target)) )  {
		throw FileException(STRING(LARGER_TARGET_FILE_EXISTS));
	}

	// Check if it's a zero-byte file, if so, create and return...
	if(aSize == 0) {
		if(!BOOLSETTING(SKIP_ZERO_BYTE)) {
			File f(aTarget, File::WRITE, File::CREATE);
		}
		return;
	}

	{
		Lock l(cs);
		// Alright, get a queue item, new or old...
		bool newItem = false;
		QueueItem* q = getQueueItem(target, aSize, aResume, newItem);
		QueueItem::Source* s = NULL;
		
		if(aFile == USER_LIST_NAME) {
			q->setFlag(QueueItem::FLAG_USER_LIST);
			q->setPriority(QueueItem::HIGHEST);
		}

		if(q->isSet(QueueItem::FLAG_USER_LIST)) {
			q->setFlag(isDirectory ? QueueItem::FLAG_DIRECTORY_DOWNLOAD : QueueItem::FLAG_CLIENT_VIEW);

			// We've done what we could...
			if(!newItem) {
				return;
			}
		}
		
		if(q->isSource(aUser)) {
			throw QueueException(STRING(DUPLICATE_SOURCE));
		}

		{
			for(QueueItem::Source::Iter i = q->getSources().begin(); i != q->getSources().end(); ++i) {
				if(((*i)->getUser()->getNick() == aUser->getNick()) && ((*i)->getPath() == aFile) ) {
					throw QueueException(STRING(DUPLICATE_SOURCE));
				}
			}
		}
		if(!addBad) {
			if(q->isBadSource(aUser)) {
				throw QueueException(STRING(DUPLICATE_SOURCE));
			}
			for(QueueItem::Source::Iter i = q->getBadSources().begin(); i != q->getBadSources().end(); ++i) {
				if( ((*i)->getUser()->getNick() == aUser->getNick() && (*i)->getPath() == aFile) ) {
					throw QueueException(STRING(DUPLICATE_SOURCE));
				}
			}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -