📄 downloadmanagerstateimpl.java
字号:
/*
* 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.io.*;
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.TOTorrentException;
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.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.TorrentUtils;
/**
* @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()){
ACTIVE_DIR.mkdirs();
}
}
private static final Map default_parameters;
static{
default_parameters = new HashMap();
for (int i=0;i<PARAMETERS.length;i++){
default_parameters.put( PARAMETERS[i][0], PARAMETERS[i][1] );
}
}
private static AEMonitor class_mon = new AEMonitor( "DownloadManagerState:class" );
private static Map state_map = new HashMap();
private DownloadManagerImpl download_manager;
private TOTorrent torrent;
private boolean write_required;
private Map tracker_response_cache = new HashMap();
private Category category;
private List listeners = new ArrayList();
private List will_be_read_list = new ArrayList();
private Map parameters;
private AEMonitor this_mon = new AEMonitor( "DownloadManagerState" );
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 );
}
}
// 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 )
throws TOTorrentException
{
// 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{
saved_state = TorrentUtils.readFromFile( saved_file, true );
}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 );
torrent_hash = original_torrent.getHash();
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 );
}
}
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 );
}
}
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
DownloadManagerStateImpl(
DownloadManagerImpl _download_manager,
TOTorrent _torrent )
{
download_manager = _download_manager;
torrent = _torrent;
// sanity check on additional attribute types
String[] map_types = { RESUME_KEY, TRACKER_CACHE_KEY, ATTRIBUTE_KEY };
for (int i=0;i<map_types.length;i++){
String map_type = map_types[i];
Object attribute_key = torrent.getAdditionalProperty( map_type );
if ( attribute_key != null && !( attribute_key instanceof Map )){
Debug.out( "Invalid state entry type for '" + map_type + "'" );
torrent.removeAdditionalProperty( map_type );
}
}
// get initial values
tracker_response_cache = (Map)torrent.getAdditionalMapProperty( TRACKER_CACHE_KEY );
if ( tracker_response_cache == null ){
tracker_response_cache = 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 Uploads Seeding", this );
COConfigurationManager.addParameterListener( "enable.seedingonly.maxuploads", this );
}
protected void
removeListeners()
{
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()
{
return( tracker_response_cache );
}
public void
setTrackerResponseCache(
Map value )
{
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();
}
}
/*
protected boolean
mergeTrackerResponseCache(
DownloadManagerStateImpl other_state )
{
Map other_cache = other_state.getTrackerResponseCache();
if ( other_cache != null && other_cache.size() > 0 ){
Map merged_cache = TRTrackerUtils.mergeResponseCache( tracker_response_cache, other_cache );
setTrackerResponseCache( merged_cache );
return( true );
}
return( false );
}
*/
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 ){
torrent.removeAdditionalProperty( RESUME_KEY );
}else{
torrent.setAdditionalMapProperty(RESUME_KEY, data);
}
write_required = true;
}finally{
this_mon.exit();
}
}
public TOTorrent
getTorrent()
{
return( torrent );
}
public void
save()
{
boolean do_write;
try {
this_mon.enter();
do_write = write_required;
write_required = false;
} finally {
this_mon.exit();
}
if (do_write) {
try {
// System.out.println( "writing download state for '" + new String(torrent.getName()));
if (Logger.isEnabled())
Logger.log(new LogEvent(torrent, LOGID, "Saving state for download '"
+ TorrentUtils.getLocalisedName(torrent) + "'"));
TorrentUtils.writeToFile(torrent, true);
} catch (Throwable e) {
Logger.log(new LogEvent(torrent, LOGID, "Saving state", e));
}
} else {
// System.out.println( "not writing download state for '" + new String(torrent.getName()));
}
}
public void
delete()
{
try{
class_mon.enter();
HashWrapper wrapper = torrent.getHashWrapper();
state_map.remove( wrapper );
TorrentUtils.delete( torrent );
File dir = new File( ACTIVE_DIR, ByteFormatter.encodeString( wrapper.getBytes()));
if ( dir.exists() && dir.isDirectory()){
FileUtil.recursiveDelete( dir );
}
removeListeners();
}catch( Throwable e ){
Debug.printStackTrace( e );
}finally{
class_mon.exit();
}
}
protected void
mergeTorrentDetails(
TOTorrent other_torrent )
{
try{
boolean write = TorrentUtils.mergeAnnounceURLs( other_torrent, torrent );
// System.out.println( "DownloadManagerState:mergeTorrentDetails -> " + write );
if ( write ){
save();
if ( download_manager != null ){
TRTrackerAnnouncer client = download_manager.getTrackerClient();
if ( client != null ){
// pick up any URL changes
client.resetTrackerUrl( false );
}
}
}
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
public void
setFlag(
long flag,
boolean set )
{
long old_value = getLongAttribute( AT_FLAGS );
long new_value;
if ( set ){
new_value = old_value | flag;
}else{
new_value = old_value & ~flag;
}
if ( old_value != new_value ){
setLongAttribute( AT_FLAGS, new_value );
}
}
public boolean
getFlag(
long flag )
{
long value = getLongAttribute( AT_FLAGS );
return(( value & flag ) != 0 );
}
public int
getIntParameter(
String name )
{
try{
this_mon.enter();
Object value = parameters.get( name );
if ( value == null ){
value = default_parameters.get( name );
if ( value == null ){
Debug.out( "Unknown parameter '" + name + "' - must be defined in DownloadManagerState" );
return( 0 );
}else{
// default overrides
if ( name == PARAM_MAX_UPLOADS_WHEN_SEEDING_ENABLED ){
if ( COConfigurationManager.getBooleanParameter( "enable.seedingonly.maxuploads" )){
value = new Boolean( true );
}
}else if ( name == PARAM_MAX_UPLOADS_WHEN_SEEDING ){
int def = COConfigurationManager.getIntParameter( "Max Uploads Seeding" );
value = new Integer( def );
}
}
}
if ( value instanceof Boolean ){
return(((Boolean)value).booleanValue()?1:0);
}else if ( value instanceof Integer ){
return( ((Integer)value).intValue());
}else if ( value instanceof Long ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -