www.pudn.com > DCPlusPlus-src.zip > DownloadManager.h


/*  
 * Copyright (C) 2001-2004 Jacek Sieka, j_s at 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. 
 */ 
 
#if !defined(AFX_DOWNLOADMANAGER_H__D6409156_58C2_44E9_B63C_B58C884E36A3__INCLUDED_) 
#define AFX_DOWNLOADMANAGER_H__D6409156_58C2_44E9_B63C_B58C884E36A3__INCLUDED_ 
 
#if _MSC_VER > 1000 
#pragma once 
#endif // _MSC_VER > 1000 
 
#include "TimerManager.h" 
 
#include "UserConnection.h" 
#include "Singleton.h" 
#include "FilteredFile.h" 
#include "ZUtils.h" 
#include "MerkleTree.h" 
 
class QueueItem; 
class ConnectionQueueItem; 
 
class Download : public Transfer, public Flags { 
public: 
	static const string ANTI_FRAG_EXT; 
 
	typedef Download* Ptr; 
	typedef vector List; 
	typedef List::iterator Iter; 
 
	enum { 
		FLAG_USER_LIST = 0x01, 
		FLAG_RESUME = 0x02, 
		FLAG_ROLLBACK = 0x04, 
		FLAG_ZDOWNLOAD = 0x08, 
		FLAG_CALC_CRC32 = 0x10, 
		FLAG_CRC32_OK = 0x20, 
		FLAG_ANTI_FRAG = 0x40, 
		FLAG_UTF8 = 0x80, 
		FLAG_TREE_DOWNLOAD = 0x100, 
		FLAG_TREE_TRIED = 0x200, 
	}; 
 
	Download() throw(); 
	Download(QueueItem* qi) throw(); 
 
	virtual ~Download() { } 
 
	string getTargetFileName() { 
		string::size_type i = getTarget().rfind('\\'); 
		if(i != string::npos) { 
			return getTarget().substr(i + 1); 
		} else { 
			return getTarget(); 
		} 
	}; 
 
	string getDownloadTarget() { 
		const string& tgt = (getTempTarget().empty() ? getTarget() : getTempTarget()); 
		return isSet(FLAG_ANTI_FRAG) ? tgt + ANTI_FRAG_EXT : tgt;			 
	} 
 
	TigerTree& getTigerTree() { 
		return tt; 
	} 
 
	Command getCommand(bool zlib, bool tthf) { 
		Command cmd = Command(Command::GET()); 
		if(isSet(FLAG_TREE_DOWNLOAD)) { 
			cmd.addParam("tthl"); 
		} else { 
			cmd.addParam("file"); 
		} 
		if(tthf && getTTH() != NULL) { 
			cmd.addParam("TTH/" + getTTH()->toBase32()); 
		} else { 
			cmd.addParam(Util::toAdcFile(getSource())); 
		} 
		cmd.addParam(Util::toString(getPos())); 
		cmd.addParam(Util::toString(getSize() - getPos())); 
 
		if(zlib && getSize() != -1 && BOOLSETTING(COMPRESS_TRANSFERS)) { 
			setFlag(FLAG_ZDOWNLOAD); 
			cmd.addParam("ZL1"); 
		} 
 
		return cmd; 
	} 
 
	typedef CalcOutputStream CrcOS; 
	GETSET(string, source, Source); 
	GETSET(string, target, Target); 
	GETSET(string, tempTarget, TempTarget); 
	GETSET(OutputStream*, file, File); 
	GETSET(CrcOS*, crcCalc, CrcCalc); 
	GETSET(bool, treeValid, TreeValid); 
	GETSET(Download*, oldDownload, OldDownload); 
	GETSET(TTHValue*, tth, TTH); 
 
private: 
	Download(const Download&); 
 
	Download& operator=(const Download&); 
 
	TigerTree tt; 
}; 
 
class DownloadManagerListener { 
public: 
	template	struct X { enum { TYPE = I };  }; 
 
	typedef X<0> Complete; 
	typedef X<1> Failed; 
	typedef X<2> Starting; 
	typedef X<3> Tick; 
 
	/** This is the first message sent before a download starts. No other messages will be sent before. */ 
	virtual void on(Starting, Download*) throw() { }; 
	/** Sent once a second if something has actually been downloaded. */ 
	virtual void on(Tick, const Download::List&) throw() { }; 
	/** This is the last message sent before a download is deleted. No more messages will be sent after it. */ 
	virtual void on(Complete, Download*) throw() { }; 
	/** This indicates some sort of failure with a particular download. No more messages will be sent after it */ 
	virtual void on(Failed, Download*, const string&) throw() { }; 
}; 
 
class DownloadManager : public Speaker,  
	private UserConnectionListener, private TimerManagerListener,  
	public Singleton 
{ 
public: 
 
	void addConnection(UserConnection::Ptr conn) { 
		conn->addListener(this); 
		checkDownloads(conn); 
	} 
 
	void abortDownload(const string& aTarget); 
	int getAverageSpeed() { 
		Lock l(cs); 
		int avg = 0; 
		for(Download::Iter i = downloads.begin(); i != downloads.end(); ++i) { 
			Download* d = *i; 
			avg += (int)d->getRunningAverage(); 
		} 
		return avg; 
	} 
	size_t getDownloads() { 
		Lock l(cs); 
		return downloads.size(); 
	} 
private: 
 
	enum { MOVER_LIMIT = 10*1024*1024 }; 
	class FileMover : public Thread { 
	public: 
		FileMover() : active(false) { }; 
		virtual ~FileMover() { join(); }; 
 
		void moveFile(const string& source, const string& target); 
		virtual int run(); 
	private: 
		typedef pair FilePair; 
		typedef vector FileList; 
		typedef FileList::iterator FileIter; 
 
		bool active; 
 
		FileList files; 
		CriticalSection cs; 
	} mover; 
	 
	CriticalSection cs; 
	Download::List downloads; 
	 
	bool checkRollback(Download* aDownload, const u_int8_t* aBuf, int aLen) throw(FileException); 
	void removeConnection(UserConnection::Ptr aConn, bool reuse = false); 
	void removeDownload(Download* aDown, bool full, bool finished = false); 
	 
	friend class Singleton; 
	DownloadManager() {  
		TimerManager::getInstance()->addListener(this); 
	}; 
 
	virtual ~DownloadManager() { 
		TimerManager::getInstance()->removeListener(this); 
		while(true) { 
			{ 
				Lock l(cs); 
				if(downloads.empty()) 
					break; 
			} 
			Thread::sleep(100); 
		} 
	}; 
	 
	void checkDownloads(UserConnection* aConn); 
	void handleEndData(UserConnection* aSource); 
	 
	// UserConnectionListener 
	virtual void on(Data, UserConnection*, const u_int8_t*, size_t) throw(); 
	virtual void on(Failed, UserConnection*, const string&) throw(); 
	virtual void on(Sending, UserConnection*, int64_t) throw(); 
	virtual void on(FileLength, UserConnection*, int64_t) throw(); 
	virtual void on(MaxedOut, UserConnection*) throw(); 
	virtual	void on(FileNotAvailable, UserConnection*) throw(); 
 
	virtual void on(Command::SND, UserConnection*, const Command&) throw(); 
	 
	bool prepareFile(UserConnection* aSource, int64_t newSize = -1); 
	// TimerManagerListener 
	virtual void on(TimerManagerListener::Second, u_int32_t aTick) throw(); 
}; 
 
#endif // !defined(AFX_DOWNLOADMANAGER_H__D6409156_58C2_44E9_B63C_B58C884E36A3__INCLUDED_) 
 
/** 
 * @file 
 * $Id: DownloadManager.h,v 1.69 2004/09/09 09:27:36 arnetheduck Exp $ 
 */