1 /* 2 * Copyright (C) 2001-2009 Jacek Sieka, arnetheduck on gmail point com 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19 #ifndef DCPLUSPLUS_DCPP_QUEUE_MANAGER_H 20 #define DCPLUSPLUS_DCPP_QUEUE_MANAGER_H 21 22 #include "TimerManager.h" 23 24 #include "CriticalSection.h" 25 #include "Exception.h" 26 #include "User.h" 27 #include "File.h" 28 #include "QueueItem.h" 29 #include "Singleton.h" 30 #include "DirectoryListing.h" 31 #include "MerkleTree.h" 32 33 #include "QueueManagerListener.h" 34 #include "SearchManagerListener.h" 35 #include "ClientManagerListener.h" 36 37 namespace dcpp { 38 39 STANDARD_EXCEPTION(QueueException); 40 41 class UserConnection; 42 43 class DirectoryItem { 44 public: 45 typedef DirectoryItem* Ptr; 46 typedef unordered_multimap<UserPtr, Ptr, User::Hash> DirectoryMap; 47 typedef DirectoryMap::iterator DirectoryIter; 48 typedef pair<DirectoryIter, DirectoryIter> DirectoryPair; 49 50 typedef vector<Ptr> List; 51 typedef List::iterator Iter; 52 DirectoryItem()53 DirectoryItem() : priority(QueueItem::DEFAULT) { } DirectoryItem(const UserPtr & aUser,const string & aName,const string & aTarget,QueueItem::Priority p)54 DirectoryItem(const UserPtr& aUser, const string& aName, const string& aTarget, 55 QueueItem::Priority p) : name(aName), target(aTarget), priority(p), user(aUser) { } ~DirectoryItem()56 ~DirectoryItem() { } 57 getUser()58 UserPtr& getUser() { return user; } setUser(const UserPtr & aUser)59 void setUser(const UserPtr& aUser) { user = aUser; } 60 61 GETSET(string, name, Name); 62 GETSET(string, target, Target); 63 GETSET(QueueItem::Priority, priority, Priority); 64 private: 65 UserPtr user; 66 }; 67 68 class ConnectionQueueItem; 69 class QueueLoader; 70 71 class QueueManager : public Singleton<QueueManager>, public Speaker<QueueManagerListener>, private TimerManagerListener, 72 private SearchManagerListener, private ClientManagerListener 73 { 74 public: 75 /** Add a file to the queue. */ 76 void add(const string& aTarget, int64_t aSize, const TTHValue& root, const UserPtr& aUser, const string& hubHint, 77 int aFlags = 0, bool addBad = true) throw(QueueException, FileException); 78 /** Add a user's filelist to the queue. */ 79 void addList(const UserPtr& aUser, const string& hubHint, int aFlags, const string& aInitialDir = Util::emptyString) throw(QueueException, FileException); 80 /** Readd a source that was removed */ 81 void readd(const string& target, const UserPtr& aUser, const string& hubHint) throw(QueueException); 82 /** Add a directory to the queue (downloads filelist and matches the directory). */ 83 void addDirectory(const string& aDir, const UserPtr& aUser, const string& hubHint, const string& aTarget, QueueItem::Priority p = QueueItem::DEFAULT) throw(); 84 85 int matchListing(const DirectoryListing& dl, const string& hubHint) throw(); 86 87 bool getTTH(const string& name, TTHValue& tth) throw(); 88 89 int64_t getSize(const string& target) throw(); 90 int64_t getPos(const string& target) throw(); 91 92 /** Move the target location of a queued item. Running items are silently ignored */ 93 void move(const string& aSource, const string& aTarget) throw(); 94 95 void remove(const string& aTarget) throw(); 96 void removeSource(const string& aTarget, const UserPtr& aUser, int reason, bool removeConn = true) throw(); 97 void removeSource(const UserPtr& aUser, int reason) throw(); 98 99 void recheck(const string& aTarget); 100 101 void setPriority(const string& aTarget, QueueItem::Priority p) throw(); 102 103 void getTargets(const TTHValue& tth, StringList& sl); lockQueue()104 QueueItem::StringMap& lockQueue() throw() { cs.enter(); return fileQueue.getQueue(); } ; unlockQueue()105 void unlockQueue() throw() { cs.leave(); } 106 107 Download* getDownload(UserConnection& aSource, bool supportsTrees) throw(); 108 void putDownload(Download* aDownload, bool finished) throw(); 109 void setFile(Download* download); 110 111 int64_t getQueued(const UserPtr& aUser) const; 112 113 /** @return The highest priority download the user has, PAUSED may also mean no downloads */ 114 QueueItem::Priority hasDownload(const UserPtr& aUser) throw(); 115 116 int countOnlineSources(const string& aTarget); 117 118 void loadQueue() throw(); 119 void saveQueue() throw(); 120 121 GETSET(uint64_t, lastSave, LastSave); 122 GETSET(string, queueFile, QueueFile); 123 private: 124 enum { MOVER_LIMIT = 10*1024*1024 }; 125 class FileMover : public Thread { 126 public: FileMover()127 FileMover() : active(false) { } ~FileMover()128 virtual ~FileMover() { join(); } 129 130 void moveFile(const string& source, const string& target); 131 virtual int run(); 132 private: 133 typedef pair<string, string> FilePair; 134 typedef vector<FilePair> FileList; 135 typedef FileList::iterator FileIter; 136 137 bool active; 138 139 FileList files; 140 CriticalSection cs; 141 } mover; 142 143 class Rechecker : public Thread { 144 struct DummyOutputStream : OutputStream { writeDummyOutputStream145 virtual size_t write(const void*, size_t n) throw(Exception) { return n; } flushDummyOutputStream146 virtual size_t flush() throw(Exception) { return 0; } 147 }; 148 149 public: Rechecker(QueueManager * qm_)150 explicit Rechecker(QueueManager* qm_) : qm(qm_), active(false) { } ~Rechecker()151 virtual ~Rechecker() { join(); } 152 153 void add(const string& file); 154 virtual int run(); 155 156 private: 157 QueueManager* qm; 158 bool active; 159 160 StringList files; 161 CriticalSection cs; 162 } rechecker; 163 164 /** All queue items by target */ 165 class FileQueue { 166 public: FileQueue()167 FileQueue() : lastInsert(queue.end()) { } ~FileQueue()168 ~FileQueue() { 169 for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i) 170 delete i->second; 171 } 172 void add(QueueItem* qi); 173 QueueItem* add(const string& aTarget, int64_t aSize, int aFlags, QueueItem::Priority p, 174 const string& aTempTarget, time_t aAdded, const TTHValue& root) 175 throw(QueueException, FileException); 176 177 QueueItem* find(const string& target); 178 void find(QueueItem::List& sl, int64_t aSize, const string& ext); 179 void find(QueueItem::List& ql, const TTHValue& tth); 180 181 bool exists(const TTHValue& tth) const; 182 183 QueueItem* findAutoSearch(StringList& recent); getSize()184 size_t getSize() { return queue.size(); } getQueue()185 QueueItem::StringMap& getQueue() { return queue; } 186 void move(QueueItem* qi, const string& aTarget); 187 void remove(QueueItem* qi); 188 private: 189 QueueItem::StringMap queue; 190 /** A hint where to insert an item... */ 191 QueueItem::StringIter lastInsert; 192 }; 193 194 /** All queue items indexed by user (this is a cache for the FileQueue really...) */ 195 class UserQueue { 196 public: 197 void add(QueueItem* qi); 198 void add(QueueItem* qi, const UserPtr& aUser); 199 QueueItem* getNext(const UserPtr& aUser, QueueItem::Priority minPrio = QueueItem::LOWEST, int64_t wantedSize = 0); 200 QueueItem* getRunning(const UserPtr& aUser); 201 void addDownload(QueueItem* qi, Download* d); 202 void removeDownload(QueueItem* qi, const UserPtr& d); getList(int p)203 QueueItem::UserListMap& getList(int p) { return userQueue[p]; } 204 void remove(QueueItem* qi, bool removeRunning = true); 205 void remove(QueueItem* qi, const UserPtr& aUser, bool removeRunning = true); 206 void setPriority(QueueItem* qi, QueueItem::Priority p); 207 getRunning()208 QueueItem::UserMap& getRunning() { return running; } isRunning(const UserPtr & aUser)209 bool isRunning(const UserPtr& aUser) const { 210 return (running.find(aUser) != running.end()); 211 } 212 int64_t getQueued(const UserPtr& aUser) const; 213 private: 214 /** QueueItems by priority and user (this is where the download order is determined) */ 215 QueueItem::UserListMap userQueue[QueueItem::LAST]; 216 /** Currently running downloads, a QueueItem is always either here or in the userQueue */ 217 QueueItem::UserMap running; 218 }; 219 220 friend class QueueLoader; 221 friend class Singleton<QueueManager>; 222 223 QueueManager(); 224 virtual ~QueueManager() throw(); 225 226 mutable CriticalSection cs; 227 228 /** QueueItems by target */ 229 FileQueue fileQueue; 230 /** QueueItems by user */ 231 UserQueue userQueue; 232 /** Directories queued for downloading */ 233 DirectoryItem::DirectoryMap directories; 234 /** Recent searches list, to avoid searching for the same thing too often */ 235 StringList recent; 236 /** The queue needs to be saved */ 237 bool dirty; 238 /** Next search */ 239 uint32_t nextSearch; 240 /** Sanity check for the target filename */ 241 static string checkTarget(const string& aTarget, int64_t aSize) throw(QueueException, FileException); 242 /** Add a source to an existing queue item */ 243 bool addSource(QueueItem* qi, const UserPtr& aUser, Flags::MaskType addBad) throw(QueueException, FileException); 244 245 void processList(const string& name, UserPtr& user, int flags); 246 247 void load(const SimpleXML& aXml); 248 void moveFile(const string& source, const string& target); 249 void moveStuckFile(QueueItem* qi); 250 void rechecked(QueueItem* qi); 251 252 void setDirty(); 253 254 string getListPath(const UserPtr& user); 255 256 // TimerManagerListener 257 virtual void on(TimerManagerListener::Second, uint32_t aTick) throw(); 258 virtual void on(TimerManagerListener::Minute, uint32_t aTick) throw(); 259 260 // SearchManagerListener 261 virtual void on(SearchManagerListener::SR, const SearchResultPtr&) throw(); 262 263 // ClientManagerListener 264 virtual void on(ClientManagerListener::UserConnected, const UserPtr& aUser) throw(); 265 virtual void on(ClientManagerListener::UserDisconnected, const UserPtr& aUser) throw(); 266 }; 267 268 } // namespace dcpp 269 270 #endif // !defined(QUEUE_MANAGER_H) 271