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

📄 downloadmanagerstateimpl.java

📁 这是一个基于java编写的torrent的P2P源码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * Created on 15-Nov-2004
 * Created by Paul Gardner
 * Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
 *
 * 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.
 * 
 * AELITIS, SAS au capital de 46,603.30 euros
 * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
 *
 */

package org.gudy.azureus2.core3.download.impl;

import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.io.*;
import java.net.URL;

import org.gudy.azureus2.core3.disk.DiskManagerFactory;
import org.gudy.azureus2.core3.disk.DiskManagerFileInfo;
import org.gudy.azureus2.core3.download.*;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.PEPeerSource;
import org.gudy.azureus2.core3.category.*;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentAnnounceURLGroup;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncer;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.AENetworkClassifier;
import org.gudy.azureus2.core3.util.BDecoder;
import org.gudy.azureus2.core3.util.BEncoder;
import org.gudy.azureus2.core3.util.ByteFormatter;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.FileUtil;
import org.gudy.azureus2.core3.util.HashWrapper;
import org.gudy.azureus2.core3.util.IndentWriter;
import org.gudy.azureus2.core3.util.TorrentUtils;

import com.aelitis.azureus.core.AzureusCoreFactory;
import com.aelitis.azureus.core.util.CaseSensitiveFileMap;

/**
 * @author parg
 * Overall aim of this is to stop updating the torrent file itself and update something
 * Azureus owns. To this end a file based on torrent hash is created in user-dir/active
 * It is actually just a copy of the torrent file
 */

public class 
DownloadManagerStateImpl
	implements DownloadManagerState, ParameterListener
{
	private static final LogIDs LOGID = LogIDs.DISK;
	private static final String			RESUME_KEY			= "resume";
	private static final String			TRACKER_CACHE_KEY	= "tracker_cache";
	private static final String			ATTRIBUTE_KEY		= "attributes";
		
	private static final File			ACTIVE_DIR;
	
	static{
	
		ACTIVE_DIR = FileUtil.getUserFile( "active" );
		
		if ( !ACTIVE_DIR.exists()){
			
			FileUtil.mkdirs(ACTIVE_DIR);
		}
	}
	
	private static final Map	default_parameters;
	private static final Map	default_attributes;
	
	static{
		default_parameters  = new HashMap();
		
		for (int i=0;i<PARAMETERS.length;i++){
			
			default_parameters.put( PARAMETERS[i][0], PARAMETERS[i][1] );
		}
		
		default_attributes  = new HashMap();
		
		for (int i=0;i<ATTRIBUTE_DEFAULTS.length;i++){
			
			default_attributes.put( ATTRIBUTE_DEFAULTS[i][0], ATTRIBUTE_DEFAULTS[i][1] );
		}
	}
	
	private static AEMonitor	class_mon	= new AEMonitor( "DownloadManagerState:class" );
	
	private static Map					state_map 					= new HashMap();
	private static Map					global_state_cache			= new HashMap();
	private static List					global_state_cache_wrappers	= new ArrayList();
	
	private DownloadManagerImpl			download_manager;
	
	private TOTorrent					torrent;
	
	private boolean						write_required;
	
	private Map							tracker_response_cache;
  
		
	private Category 	category;

	private List		listeners	= new ArrayList();
	
	private List		will_be_read_list	= new ArrayList();
	
	private Map			parameters;
	private Map			attributes;
	
	private AEMonitor	this_mon	= new AEMonitor( "DownloadManagerState" );
	
	private boolean firstPrimaryFileRead = true;


	private static DownloadManagerState
	getDownloadState(
		DownloadManagerImpl	download_manager,
		TOTorrent			original_torrent,
		TOTorrent			target_torrent )
	
		throws TOTorrentException
	{
		byte[]	hash	= target_torrent.getHash();
		
		DownloadManagerStateImpl	res	= null;
		
		try{
			class_mon.enter();
		
			HashWrapper	hash_wrapper = new HashWrapper( hash );
			
			res = (DownloadManagerStateImpl)state_map.get(hash_wrapper); 
			
			if ( res == null ){
			
				res = new DownloadManagerStateImpl( download_manager, target_torrent );
									
				state_map.put( hash_wrapper, res );
				
			}else{
				
					// if original state was created without a download manager, 
					// bind it to this one
				
				if ( res.getDownloadManager() == null && download_manager != null ){
					
					res.setDownloadManager( download_manager );
				}
				
				if ( original_torrent != null ){
						
					res.mergeTorrentDetails( original_torrent );
				}
			}
		}finally{
			
			class_mon.exit();
		}
				
		return( res );
	}

	
	public static DownloadManagerState
	getDownloadState(
		TOTorrent		original_torrent )
	
		throws TOTorrentException
	{
		byte[]	torrent_hash = original_torrent.getHash();
		
		// System.out.println( "getDownloadState: hash = " + ByteFormatter.encodeString(torrent_hash));
		
		TOTorrent saved_state	= null;
				
		File	saved_file = getStateFile( torrent_hash ); 
		
		if ( saved_file.exists()){
			
			try{
				saved_state = TorrentUtils.readFromFile( saved_file, true );
				
			}catch( Throwable e ){
				
				Debug.out( "Failed to load download state for " + saved_file, e );
			}
		}
		
			// if saved state not found then recreate from original torrent 
		
		if ( saved_state == null ){
		
			TorrentUtils.copyToFile( original_torrent, saved_file );
			
			saved_state = TorrentUtils.readFromFile( saved_file, true );
		}

		return( getDownloadState( null, original_torrent, saved_state ));
	}
	
	protected static DownloadManagerState
	getDownloadState(
		DownloadManagerImpl	download_manager,
		String				torrent_file,
		byte[]				torrent_hash,
		boolean				force_piece_discard )
	
		throws TOTorrentException
	{
		boolean	discard_pieces = state_map.size() > 32;
		
		// System.out.println( "getDownloadState: hash = " + (torrent_hash==null?"null":ByteFormatter.encodeString(torrent_hash) + ", file = " + torrent_file ));

		TOTorrent	original_torrent	= null;
		TOTorrent 	saved_state			= null;
		
			// first, if we already have the hash then see if we can load the saved state
		
		if ( torrent_hash != null ){
			
			File	saved_file = getStateFile( torrent_hash ); 
		
			if ( saved_file.exists()){
				
				try{
					Map	cached_state = (Map)global_state_cache.remove( new HashWrapper( torrent_hash ));
					
					if ( cached_state != null ){
						
						CachedStateWrapper wrapper = new CachedStateWrapper( download_manager, torrent_file, torrent_hash, cached_state, force_piece_discard );
						
						global_state_cache_wrappers.add( wrapper );
						
						saved_state	= wrapper;
					}else{
						
						saved_state = TorrentUtils.readFromFile( saved_file, true, discard_pieces );
					}
					
				}catch( Throwable e ){
					
					Debug.out( "Failed to load download state for " + saved_file );
				}
			}
		}
		
			// if saved state not found then recreate from original torrent if required
		
		if ( saved_state == null ){
		
			original_torrent = TorrentUtils.readFromFile( new File(torrent_file), true, discard_pieces );
			
			torrent_hash = original_torrent.getHash();
			
			File	saved_file = getStateFile( torrent_hash ); 
			
			if ( saved_file.exists()){
				
				try{
					saved_state = TorrentUtils.readFromFile( saved_file, true, discard_pieces );
					
				}catch( Throwable e ){
					
					Debug.out( "Failed to load download state for " + saved_file );
				}
			}
			
			if ( saved_state == null ){
						
					// we must copy the torrent as we want one independent from the
					// original (someone might still have references to the original
					// and do stuff like write it somewhere else which would screw us
					// up)
				
				TorrentUtils.copyToFile( original_torrent, saved_file );
				
				saved_state = TorrentUtils.readFromFile( saved_file, true, discard_pieces );
			}
		}

		return( getDownloadState( download_manager, original_torrent, saved_state ));
	}
	
	protected static File
	getStateFile(
		byte[]		torrent_hash )
	{
		return( new File( ACTIVE_DIR, ByteFormatter.encodeString( torrent_hash ) + ".dat" ));
	}
	
	protected static File
	getGlobalStateFile()
	{
		return( new File( ACTIVE_DIR, "cache.dat" ));
	}
	
	public static void
	loadGlobalStateCache()
	{
		File file = getGlobalStateFile();
		
		if ( !file.canRead()){
			
			return;
		}
		
		try{
			
			BufferedInputStream is = new BufferedInputStream( new GZIPInputStream( new FileInputStream( file )));
			
			try{
				
				Map	map = BDecoder.decode( is );
				
				List	cache = (List)map.get( "state" );
				
				if ( cache != null ){
					
					for (int i=0;i<cache.size();i++){
						
						Map	entry = (Map)cache.get(i);
						
						byte[]	hash = (byte[])entry.get( "hash" );
						
						if ( hash != null ){
							
							global_state_cache.put( new HashWrapper( hash ), entry );
						}
					}
				}
				
				is.close();
				
			}catch( IOException e){
				
				Debug.printStackTrace( e );
			}finally{
				
				try{
					is.close();
					
				}catch( Throwable e ){
				}
			}
		}catch( Throwable e ){
			
			Debug.printStackTrace( e );
		}
	}
	
	public static void
	saveGlobalStateCache()
	{
		try{
			class_mon.enter();

			Map	map = new HashMap();
			
			List	cache = new ArrayList();
			
			map.put( "state", cache );

			Iterator	it = state_map.values().iterator();
			
			while( it.hasNext()){
				
				DownloadManagerState dms = (DownloadManagerState)it.next();
				
				DownloadManager dm = dms.getDownloadManager();
				
				if ( dm != null && dm.isPersistent()){
					
					try{
						Map	state = CachedStateWrapper.export( dms );
					
						cache.add( state );
						
					}catch( Throwable e ){
						
						Debug.printStackTrace( e );
					}
				}
			}
			
			GZIPOutputStream	os = new GZIPOutputStream( new FileOutputStream( getGlobalStateFile()));
			
			try{
				
				os.write( BEncoder.encode( map ));
				
				os.close();
				
			}catch( IOException e ){
				
				Debug.printStackTrace( e );
			
				try{
					os.close();
					
				}catch( IOException f ){
					
				}
			}
		}catch( Throwable e ){
			
			Debug.printStackTrace( e );
			
		}finally{
			
			class_mon.exit();

		}
	}
	
	public static void
	discardGlobalStateCache()
	{
		getGlobalStateFile().delete();
		
		for ( int i=0;i<global_state_cache_wrappers.size();i++){
			
			((CachedStateWrapper)global_state_cache_wrappers.get(i)).clearCache();
		}
		
		global_state_cache_wrappers.clear();
	}

	protected
	DownloadManagerStateImpl(
		DownloadManagerImpl	_download_manager,
		TOTorrent			_torrent )
	{
		download_manager	= _download_manager;
		torrent				= _torrent;
		
		attributes = torrent.getAdditionalMapProperty( ATTRIBUTE_KEY );
		
		if ( attributes == null ){
        	
			attributes	= new HashMap();
        }
		
        String cat_string = getStringAttribute( AT_CATEGORY );

        if ( cat_string != null ){
        	
        	Category cat = CategoryManager.getCategory( cat_string );
        	
        	if ( cat != null ){
        		
        		setCategory( cat );
        	}
        }
        
        parameters	= getMapAttribute( AT_PARAMETERS );
        
        if ( parameters == null ){
        	
        	parameters	= new HashMap();
        }
        

        addListeners();
	}
	
	public void 
	parameterChanged(
		String parameterName)
	{
			// get any listeners to pick up new values as their defaults are based on core params
		
		informWritten( AT_PARAMETERS );
	}
	
	protected void
	addListeners()
	{
		COConfigurationManager.addParameterListener( "Max.Peer.Connections.Per.Torrent.When.Seeding", this );
		COConfigurationManager.addParameterListener( "Max.Peer.Connections.Per.Torrent.When.Seeding.Enable", this );
		COConfigurationManager.addParameterListener( "Max.Peer.Connections.Per.Torrent", this );
		COConfigurationManager.addParameterListener( "Max Uploads", this );
		COConfigurationManager.addParameterListener( "Max Uploads Seeding", this );
		COConfigurationManager.addParameterListener( "enable.seedingonly.maxuploads", this );
	}
	
	protected void
	removeListeners()
	{
		COConfigurationManager.removeParameterListener( "Max.Peer.Connections.Per.Torrent.When.Seeding", this );
		COConfigurationManager.removeParameterListener( "Max.Peer.Connections.Per.Torrent.When.Seeding.Enable", this );
		COConfigurationManager.removeParameterListener( "Max.Peer.Connections.Per.Torrent", this );
		COConfigurationManager.removeParameterListener( "Max Uploads", this );
		COConfigurationManager.removeParameterListener( "Max Uploads Seeding", this );
		COConfigurationManager.removeParameterListener( "enable.seedingonly.maxuploads", this );
	}
	
	public DownloadManager
	getDownloadManager()
	{
		return( download_manager );
	}
	
	protected void
	setDownloadManager(
		DownloadManagerImpl		dm )
	{
		download_manager	= dm;
	}
	
	public File
	getStateFile(
		String	name )
	{
		try{
			File	parent = new File( ACTIVE_DIR, ByteFormatter.encodeString( torrent.getHash()));
		
			return( new File( parent, name ));

		}catch( Throwable e ){

			Debug.printStackTrace(e);
			
			return( null );
		}
	}
	
	public void
	clearTrackerResponseCache()
	{
		setTrackerResponseCache( new HashMap());
	}
	
	public Map
	getTrackerResponseCache()
	{
		if ( tracker_response_cache == null ){
		
			tracker_response_cache	= torrent.getAdditionalMapProperty( TRACKER_CACHE_KEY );
			
			if ( tracker_response_cache == null ){
			
				tracker_response_cache	= new HashMap();
			}
		}
		
		return( tracker_response_cache );
	}
	
	public void
	setTrackerResponseCache(
		Map		value )
	{
			// ensure initial value read
		
		getTrackerResponseCache();
		
		try{
			this_mon.enter();
		
			// System.out.println( "setting download state/tracker cache for '" + new String(torrent.getName()));

			boolean	changed = !BEncoder.mapsAreIdentical( value, tracker_response_cache );
		
			if ( changed ){
				
				write_required	= true;
				
				tracker_response_cache	 = value;
		
				torrent.setAdditionalMapProperty( TRACKER_CACHE_KEY, tracker_response_cache );
			}	
			
		}finally{
			
			this_mon.exit();
		}
	}

	public Map
	getResumeData()
	{
		try{
			this_mon.enter();
		
			return( torrent.getAdditionalMapProperty(RESUME_KEY));
		
		}finally{
			
			this_mon.exit();
		}
	}
	
	public void
	clearResumeData()
	{
		setResumeData( null );
	}
	
	public void
	setResumeData(
		Map	data )
	{
		try{
			this_mon.enter();
		
			// System.out.println( "setting download state/resume data for '" + new String(torrent.getName()));

			if ( data == null ){
				
				setLongAttribute( AT_RESUME_STATE, 1 );
				
				torrent.removeAdditionalProperty( RESUME_KEY );
				
			}else{
				
				torrent.setAdditionalMapProperty( RESUME_KEY, data );
				
				boolean complete = DiskManagerFactory.isTorrentResumeDataComplete( this );
				
				setLongAttribute( AT_RESUME_STATE, complete?2:1 );
			}
			
			write_required	= true;

⌨️ 快捷键说明

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