1 /* 2 * Copyright (C) 2001-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 #pragma once 20 21 #include "TimerManager.h" 22 #include "CriticalSection.h" 23 #include "Exception.h" 24 #include "User.h" 25 #include "File.h" 26 #include "QueueItem.h" 27 #include "Singleton.h" 28 #include "DirectoryListing.h" 29 #include "MerkleTree.h" 30 #include "QueueManagerListener.h" 31 #include "SearchManagerListener.h" 32 #include "ClientManagerListener.h" 33 34 namespace dcpp { 35 36 STANDARD_EXCEPTION(QueueException); 37 38 class UserConnection; 39 40 class DirectoryItem { 41 public: 42 typedef DirectoryItem* Ptr; 43 typedef unordered_multimap<UserPtr, Ptr, User::Hash> DirectoryMap; 44 typedef DirectoryMap::iterator DirectoryIter; 45 typedef pair<DirectoryIter, DirectoryIter> DirectoryPair; 46 47 typedef vector<Ptr> List; 48 typedef List::iterator Iter; 49 DirectoryItem()50 DirectoryItem() : priority(QueueItem::DEFAULT) { } DirectoryItem(const UserPtr & aUser,const string & aName,const string & aTarget,QueueItem::Priority p)51 DirectoryItem(const UserPtr& aUser, const string& aName, const string& aTarget, 52 QueueItem::Priority p) : name(aName), target(aTarget), priority(p), user(aUser) { } ~DirectoryItem()53 ~DirectoryItem() { } 54 getUser()55 UserPtr& getUser() { return user; } setUser(const UserPtr & aUser)56 void setUser(const UserPtr& aUser) { user = aUser; } 57 58 GETSET(string, name, Name); 59 GETSET(string, target, Target); 60 GETSET(QueueItem::Priority, priority, Priority); 61 private: 62 UserPtr user; 63 }; 64 65 class ConnectionQueueItem; 66 class QueueLoader; 67 68 class QueueManager : public Singleton<QueueManager>, public Speaker<QueueManagerListener>, private TimerManagerListener, 69 private SearchManagerListener, private ClientManagerListener 70 { 71 public: 72 //NOTE: freedcpp 73 void add(const string& aTarget, int64_t aSize, const TTHValue& root); 74 75 /** Add a file to the queue. */ 76 void add(const string& aTarget, int64_t aSize, const TTHValue& root, const HintedUser& aUser, 77 int aFlags = 0, bool addBad = true); 78 /** Add a user's filelist to the queue. */ 79 void addList(const HintedUser& HintedUser, int aFlags, const string& aInitialDir = Util::emptyString); 80 /** Readd a source that was removed */ 81 void readd(const string& target, const HintedUser& aUser); 82 /** Add a directory to the queue (downloads filelist and matches the directory). */ 83 void addDirectory(const string& aDir, const HintedUser& aUser, const string& aTarget, 84 QueueItem::Priority p = QueueItem::DEFAULT) noexcept; 85 86 int matchListing(const DirectoryListing& dl) noexcept; 87 void matchAllListings(); 88 89 bool getTTH(const string& name, TTHValue& tth) noexcept; 90 91 int64_t getSize(const string& target) noexcept; 92 int64_t getPos(const string& target) noexcept; 93 94 /** Move the target location of a queued item. Running items are silently ignored */ 95 void move(const string& aSource, const string& aTarget) noexcept; 96 97 void remove(const string& aTarget) noexcept; 98 void removeSource(const string& aTarget, const UserPtr& aUser, int reason, bool removeConn = true) noexcept; 99 void removeSource(const UserPtr& aUser, int reason) noexcept; 100 101 void recheck(const string& aTarget); 102 103 void setPriority(const string& aTarget, QueueItem::Priority p) noexcept; 104 105 void getTargets(const TTHValue& tth, StringList& sl); lockQueue()106 QueueItem::StringMap& lockQueue() noexcept { cs.lock(); return fileQueue.getQueue(); } ; unlockQueue()107 void unlockQueue() noexcept { cs.unlock(); } 108 109 Download* getDownload(UserConnection& aSource, bool supportsTrees) noexcept; 110 void putDownload(Download* aDownload, bool finished) noexcept; 111 void setFile(Download* download); 112 113 int64_t getQueued(const UserPtr& aUser) const; 114 115 /** @return The highest priority download the user has, PAUSED may also mean no downloads */ 116 QueueItem::Priority hasDownload(const UserPtr& aUser) noexcept; 117 118 bool getQueueInfo(const UserPtr& aUser, string& aTarget, int64_t& aSize, int& aFlags) noexcept; 119 120 int countOnlineSources(const string& aTarget); 121 122 void loadQueue() noexcept; 123 void saveQueue(bool force = false) noexcept; 124 125 void noDeleteFileList(const string& path); 126 127 bool handlePartialSearch(const TTHValue& tth, PartsInfo& _outPartsInfo); 128 bool handlePartialResult(const UserPtr& aUser, const string& hubHint, const TTHValue& tth, const QueueItem::PartialSource& partialSource, PartsInfo& outPartialInfo); 129 isChunkDownloaded(const TTHValue & tth,int64_t startPos,int64_t & bytes,string & tempTarget,int64_t & size)130 bool isChunkDownloaded(const TTHValue& tth, int64_t startPos, int64_t& bytes, string& tempTarget, int64_t& size) { 131 Lock l(cs); 132 QueueItem::List ql; 133 fileQueue.find(ql, tth); 134 135 if(ql.empty()) return false; 136 137 QueueItem* qi = ql.front(); 138 139 tempTarget = qi->getTempTarget(); 140 size = qi->getSize(); 141 142 return qi->isChunkDownloaded(startPos, bytes); 143 } 144 145 GETSET(uint64_t, lastSave, LastSave); 146 GETSET(string, queueFile, QueueFile); 147 private: 148 enum { MOVER_LIMIT = 10*1024*1024 }; 149 class FileMover : public Thread { 150 public: FileMover()151 FileMover() : active(false) { } ~FileMover()152 virtual ~FileMover() { join(); } 153 154 void moveFile(const string& source, const string& target); 155 virtual int run(); 156 private: 157 typedef pair<string, string> FilePair; 158 typedef vector<FilePair> FileList; 159 typedef FileList::iterator FileIter; 160 161 bool active; 162 163 FileList files; 164 CriticalSection cs; 165 } mover; 166 167 typedef vector<pair<QueueItem::SourceConstIter, const QueueItem*> > PFSSourceList; 168 169 class Rechecker : public Thread { 170 struct DummyOutputStream : OutputStream { writeDummyOutputStream171 virtual size_t write(const void*, size_t n) { return n; } flushDummyOutputStream172 virtual size_t flush() { return 0; } 173 }; 174 175 public: Rechecker(QueueManager * qm_)176 explicit Rechecker(QueueManager* qm_) : qm(qm_), active(false) { } ~Rechecker()177 virtual ~Rechecker() { join(); } 178 179 void add(const string& file); 180 virtual int run(); 181 182 private: 183 QueueManager* qm; 184 bool active; 185 186 StringList files; 187 CriticalSection cs; 188 } rechecker; 189 190 /** All queue items by target */ 191 class FileQueue { 192 public: FileQueue()193 FileQueue() : lastInsert(queue.end()) { } ~FileQueue()194 ~FileQueue() { 195 for(QueueItem::StringIter i = queue.begin(); i != queue.end(); ++i) 196 delete i->second; 197 } 198 void add(QueueItem* qi); 199 QueueItem* add(const string& aTarget, int64_t aSize, int aFlags, QueueItem::Priority p, 200 const string& aTempTarget, time_t aAdded, const TTHValue& root); 201 202 QueueItem* find(const string& target); 203 void find(QueueItem::List& sl, int64_t aSize, const string& ext); 204 void find(QueueItem::List& ql, const TTHValue& tth); 205 // find some PFS sources to exchange parts info 206 void findPFSSources(PFSSourceList&); 207 bool exists(const TTHValue& tth) const; 208 209 #ifdef WITH_DHT 210 // return a PFS tth to DHT publish 211 TTHValue* findPFSPubTTH(); 212 #endif 213 214 QueueItem* findAutoSearch(StringList& recent); getSize()215 size_t getSize() { return queue.size(); } getQueue()216 QueueItem::StringMap& getQueue() { return queue; } 217 void move(QueueItem* qi, const string& aTarget); 218 void remove(QueueItem* qi); 219 private: 220 QueueItem::StringMap queue; 221 /** A hint where to insert an item... */ 222 QueueItem::StringIter lastInsert; 223 }; 224 225 /** All queue items indexed by user (this is a cache for the FileQueue really...) */ 226 class UserQueue { 227 public: 228 void add(QueueItem* qi); 229 void add(QueueItem* qi, const UserPtr& aUser); 230 QueueItem* getNext(const UserPtr& aUser, QueueItem::Priority minPrio = QueueItem::LOWEST, int64_t wantedSize = 0,int64_t lastSpeed =0 ,bool allowRemove = true); 231 QueueItem* getRunning(const UserPtr& aUser); 232 void addDownload(QueueItem* qi, Download* d); 233 void removeDownload(QueueItem* qi, const UserPtr& d); getList(int p)234 QueueItem::UserListMap& getList(int p) { return userQueue[p]; } 235 void remove(QueueItem* qi, bool removeRunning = true); 236 void remove(QueueItem* qi, const UserPtr& aUser, bool removeRunning = true); 237 void setPriority(QueueItem* qi, QueueItem::Priority p); 238 getRunning()239 QueueItem::UserMap& getRunning() { return running; } isRunning(const UserPtr & aUser)240 bool isRunning(const UserPtr& aUser) const { 241 return (running.find(aUser) != running.end()); 242 } 243 int64_t getQueued(const UserPtr& aUser) const; 244 private: 245 /** QueueItems by priority and user (this is where the download order is determined) */ 246 QueueItem::UserListMap userQueue[QueueItem::LAST]; 247 /** Currently running downloads, a QueueItem is always either here or in the userQueue */ 248 QueueItem::UserMap running; 249 }; 250 251 friend class QueueLoader; 252 friend class Singleton<QueueManager>; 253 254 QueueManager(); 255 virtual ~QueueManager(); 256 257 mutable CriticalSection cs; 258 259 /** QueueItems by target */ 260 FileQueue fileQueue; 261 /** QueueItems by user */ 262 UserQueue userQueue; 263 /** Directories queued for downloading */ 264 DirectoryItem::DirectoryMap directories; 265 /** Recent searches list, to avoid searching for the same thing too often */ 266 StringList recent; 267 /** The queue needs to be saved */ 268 bool dirty; 269 /** Next search */ 270 uint64_t nextSearch; 271 /** File lists not to delete */ 272 StringList protectedFileLists; 273 /** Sanity check for the target filename */ 274 static string checkTarget(const string& aTarget, bool checkExsistence); 275 /** Add a source to an existing queue item */ 276 bool addSource(QueueItem* qi, const HintedUser& aUser, Flags::MaskType addBad); 277 278 void processList(const string& name, const HintedUser& user, int flags); 279 280 void load(const SimpleXML& aXml); 281 void moveFile(const string& source, const string& target); 282 static void moveFile_(const string& source, const string& target); 283 void moveStuckFile(QueueItem* qi); 284 void rechecked(QueueItem* qi); 285 286 void setDirty(); 287 288 string getListPath(const HintedUser& user); 289 290 bool checkSfv(QueueItem* qi, Download* d); 291 uint32_t calcCrc32(const string& file); 292 293 void logFinishedDownload(QueueItem* qi, Download* d, bool crcError); 294 295 // TimerManagerListener 296 virtual void on(TimerManagerListener::Second, uint64_t aTick) noexcept; 297 virtual void on(TimerManagerListener::Minute, uint64_t aTick) noexcept; 298 299 // SearchManagerListener 300 virtual void on(SearchManagerListener::SR, const SearchResultPtr&) noexcept; 301 302 // ClientManagerListener 303 virtual void on(ClientManagerListener::UserConnected, const UserPtr& aUser) noexcept; 304 virtual void on(ClientManagerListener::UserDisconnected, const UserPtr& aUser) noexcept; 305 }; 306 307 } // namespace dcpp 308