📄 queuemanager.cpp
字号:
/*
* 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 + -