📄 downloadmanagerimpl.java
字号:
/*
* File : DownloadManagerImpl.java
* Created : 19-Oct-2003
* By : parg
*
* Azureus - a Java Bittorrent client
*
* 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.
*
* 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 ( see the LICENSE file ).
*
* 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
*/
package org.gudy.azureus2.core3.download.impl;
/*
* Created on 30 juin 2003
*
*/
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.net.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.config.impl.TransferSpeedValidator;
import org.gudy.azureus2.core3.disk.*;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.global.GlobalManagerStats;
import org.gudy.azureus2.core3.internat.*;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.*;
import org.gudy.azureus2.core3.tracker.client.*;
import org.gudy.azureus2.core3.torrent.*;
import org.gudy.azureus2.core3.util.*;
import org.gudy.azureus2.core3.download.*;
import org.gudy.azureus2.plugins.download.DownloadAnnounceResult;
import org.gudy.azureus2.plugins.download.DownloadScrapeResult;
import org.gudy.azureus2.plugins.network.ConnectionManager;
import com.aelitis.azureus.core.AzureusCoreOperation;
import com.aelitis.azureus.core.AzureusCoreOperationTask;
import com.aelitis.azureus.core.util.CaseSensitiveFileMap;
import com.aelitis.azureus.core.util.CopyOnWriteList;
/**
* @author Olivier
*
*/
public class
DownloadManagerImpl
extends LogRelation
implements DownloadManager
{
private final static long SCRAPE_DELAY_ERROR_TORRENTS = 1000 * 60 * 60 * 2;// 2 hrs
private final static long SCRAPE_DELAY_STOPPED_TORRENTS = 1000 * 60 * 60; // 1 hr
private static int upload_when_busy_min_secs;
static{
COConfigurationManager.addAndFireParameterListener(
"max.uploads.when.busy.inc.min.secs",
new ParameterListener()
{
public void
parameterChanged(
String name )
{
upload_when_busy_min_secs = COConfigurationManager.getIntParameter( name );
}
});
}
private static final String CFG_MOVE_COMPLETED_TOP = "Newly Seeding Torrents Get First Priority";
// DownloadManager listeners
private static final int LDT_STATECHANGED = 1;
private static final int LDT_DOWNLOADCOMPLETE = 2;
private static final int LDT_COMPLETIONCHANGED = 3;
private static final int LDT_POSITIONCHANGED = 4;
private static final int LDT_FILEPRIORITYCHANGED = 5;
private AEMonitor listeners_mon = new AEMonitor( "DM:DownloadManager:L" );
private static ListenerManager listeners_aggregator = ListenerManager.createAsyncManager(
"DM:ListenAggregatorDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object _value )
{
DownloadManagerListener listener = (DownloadManagerListener)_listener;
Object[] value = (Object[])_value;
DownloadManagerImpl dm = (DownloadManagerImpl)value[0];
if ( type == LDT_STATECHANGED ){
listener.stateChanged(dm, ((Integer)value[1]).intValue());
}else if ( type == LDT_DOWNLOADCOMPLETE ){
listener.downloadComplete(dm);
}else if ( type == LDT_COMPLETIONCHANGED ){
listener.completionChanged(dm, ((Boolean)value[1]).booleanValue());
}else if ( type == LDT_FILEPRIORITYCHANGED ){
listener.filePriorityChanged(dm, (DiskManagerFileInfo)value[1]);
}else if ( type == LDT_POSITIONCHANGED ){
listener.positionChanged( dm, ((Integer)value[1]).intValue(), ((Integer)value[2]).intValue());
}
}
});
private ListenerManager listeners = ListenerManager.createManager(
"DM:ListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object listener,
int type,
Object value )
{
listeners_aggregator.dispatch( listener, type, value );
}
});
// TrackerListeners
private static final int LDT_TL_ANNOUNCERESULT = 1;
private static final int LDT_TL_SCRAPERESULT = 2;
private ListenerManager tracker_listeners = ListenerManager.createManager(
"DM:TrackerListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerTrackerListener listener = (DownloadManagerTrackerListener)_listener;
if ( type == LDT_TL_ANNOUNCERESULT ){
listener.announceResult((TRTrackerAnnouncerResponse)value);
}else if ( type == LDT_TL_SCRAPERESULT ){
listener.scrapeResult((TRTrackerScraperResponse)value);
}
}
});
// PeerListeners
private static final int LDT_PE_PEER_ADDED = 1;
private static final int LDT_PE_PEER_REMOVED = 2;
private static final int LDT_PE_PIECE_ADDED = 3;
private static final int LDT_PE_PIECE_REMOVED = 4;
private static final int LDT_PE_PM_ADDED = 5;
private static final int LDT_PE_PM_REMOVED = 6;
// one static async manager for them all
private static ListenerManager peer_listeners_aggregator = ListenerManager.createAsyncManager(
"DM:PeerListenAggregatorDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerPeerListener listener = (DownloadManagerPeerListener)_listener;
if ( type == LDT_PE_PEER_ADDED ){
listener.peerAdded((PEPeer)value);
}else if ( type == LDT_PE_PEER_REMOVED ){
listener.peerRemoved((PEPeer)value);
}else if ( type == LDT_PE_PIECE_ADDED ){
listener.pieceAdded((PEPiece)value);
}else if ( type == LDT_PE_PIECE_REMOVED ){
listener.pieceRemoved((PEPiece)value);
}else if ( type == LDT_PE_PM_ADDED ){
listener.peerManagerAdded((PEPeerManager)value);
}else if ( type == LDT_PE_PM_REMOVED ){
listener.peerManagerRemoved((PEPeerManager)value);
}
}
});
private ListenerManager peer_listeners = ListenerManager.createManager(
"DM:PeerListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object listener,
int type,
Object value )
{
peer_listeners_aggregator.dispatch( listener, type, value );
}
});
private AEMonitor peer_listeners_mon = new AEMonitor( "DM:DownloadManager:PL" );
private List current_peers = new ArrayList();
private List current_pieces = new ArrayList();
private DownloadManagerController controller;
private DownloadManagerStatsImpl stats;
protected AEMonitor this_mon = new AEMonitor( "DM:DownloadManager" );
private boolean persistent;
/**
* Pretend this download is complete while not running,
* even if it has no data. When the torrent starts up, the real complete
* level will be checked (probably by DiskManager), and if the torrent
* actually does have missing data at that point, the download will be thrown
* into error state.
* <p>
* Only a forced-recheck should clear this flag.
* <p>
* Current Implementation:<br>
* - implies that the user completed the download at one point<br>
* - Checks if there's Data Missing when torrent is done (or torrent load)
*/
private boolean assumedComplete;
/**
* forceStarted torrents can't/shouldn't be automatically stopped
*/
private int last_informed_state = STATE_START_OF_DAY;
private boolean latest_informed_force_start;
private GlobalManager globalManager;
private String torrentFileName;
private boolean open_for_seeding;
private String display_name = "";
private String internal_name = "";
// Used by setTorrentSaveDir and renameDownload.
private String temporary_new_save_path_name = null;
// for simple torrents this refers to the torrent file itself. For non-simple it refers to the
// folder containing the torrent's files
private File torrent_save_location;
// Position in Queue
private int position = -1;
private Object[] read_torrent_state;
private DownloadManagerState download_manager_state;
private TOTorrent torrent;
private String torrent_comment;
private String torrent_created_by;
private TRTrackerAnnouncer tracker_client;
private TRTrackerAnnouncerListener tracker_client_listener =
new TRTrackerAnnouncerListener()
{
public void
receivedTrackerResponse(
TRTrackerAnnouncerResponse response)
{
PEPeerManager pm = controller.getPeerManager();
if ( pm != null ) {
pm.processTrackerResponse( response );
}
tracker_listeners.dispatch( LDT_TL_ANNOUNCERESULT, response );
}
public void
urlChanged(
String url,
boolean explicit)
{
if ( explicit ){
requestTrackerAnnounce( true );
}
}
public void
urlRefresh()
{
requestTrackerAnnounce( true );
}
};
// a second listener used to catch and propagate the "stopped" event
private TRTrackerAnnouncerListener stopping_tracker_client_listener =
new TRTrackerAnnouncerListener()
{
public void
receivedTrackerResponse(
TRTrackerAnnouncerResponse response)
{
tracker_listeners.dispatch( LDT_TL_ANNOUNCERESULT, response );
}
public void
urlChanged(
String url,
boolean explicit)
{
}
public void
urlRefresh()
{
}
};
private CopyOnWriteList activation_listeners = new CopyOnWriteList();
private long scrape_random_seed = SystemTime.getCurrentTime();
private HashMap data;
private boolean data_already_allocated = false;
private long creation_time = SystemTime.getCurrentTime();
private int iSeedingRank;
private boolean az_messaging_enabled = true;
private boolean dl_identity_obtained;
private byte[] dl_identity;
private int dl_identity_hashcode;
private int max_uploads = DownloadManagerState.MIN_MAX_UPLOADS;
private int max_connections;
private int max_connections_when_seeding;
private boolean max_connections_when_seeding_enabled;
private int max_seed_connections;
private int max_uploads_when_seeding = DownloadManagerState.MIN_MAX_UPLOADS;
private boolean max_uploads_when_seeding_enabled;
private int max_upload_when_busy_bps;
private int current_upload_when_busy_bps;
private long last_upload_when_busy_update;
private long last_upload_when_busy_dec_time;
// Only call this with STATE_QUEUED, STATE_WAITING, or STATE_STOPPED unless you know what you are doing
public
DownloadManagerImpl(
GlobalManager _gm,
byte[] _torrent_hash,
String _torrentFileName,
String _torrent_save_dir,
String _torrent_save_file,
int _initialState,
boolean _persistent,
boolean _recovered,
boolean _open_for_seeding,
boolean _has_ever_been_started,
List _file_priorities,
DownloadManagerInitialisationAdapter _initialisation_adapter )
{
if ( _initialState != STATE_WAITING &&
_initialState != STATE_STOPPED &&
_initialState != STATE_QUEUED ){
Debug.out( "DownloadManagerImpl: Illegal start state, " + _initialState );
}
persistent = _persistent;
globalManager = _gm;
open_for_seeding = _open_for_seeding;
// TODO: move this to download state!
if ( _file_priorities != null ){
setData( "file_priorities", _file_priorities );
}
stats = new DownloadManagerStatsImpl( this );
controller = new DownloadManagerController( this );
torrentFileName = _torrentFileName;
while( _torrent_save_dir.endsWith( File.separator )){
_torrent_save_dir = _torrent_save_dir.substring(0, _torrent_save_dir.length()-1 );
}
// readTorrent adjusts the save dir and file to be sensible values
readTorrent( _torrent_save_dir, _torrent_save_file, _torrent_hash,
persistent && !_recovered, _open_for_seeding, _has_ever_been_started,
_initialState );
if ( torrent != null && _initialisation_adapter != null ){
try{
_initialisation_adapter.initialised( this );
}catch( Throwable e ){
Debug.printStackTrace(e);
}
}
}
private void
readTorrent(
String torrent_save_dir,
String torrent_save_file,
byte[] torrent_hash, // can be null for initial torrents
boolean new_torrent, // probably equivalend to (torrent_hash == null)????
boolean for_seeding,
boolean has_ever_been_started,
int initial_state )
{
try{
display_name = torrentFileName; // default if things go wrong decoding it
internal_name = "";
torrent_comment = "";
torrent_created_by = "";
try{
// this is the first thing we do and most likely to go wrong - hence its
// existence is used below to indicate success or not
download_manager_state =
DownloadManagerStateImpl.getDownloadState(
this, torrentFileName, torrent_hash, initial_state == DownloadManager.STATE_STOPPED );
readParameters();
// establish any file links
download_manager_state.addListener(
new DownloadManagerStateListener()
{
public void
stateChanged(
DownloadManagerState state,
DownloadManagerStateEvent event )
{
if ( event.getType() == DownloadManagerStateEvent.ET_ATTRIBUTE_WRITTEN ){
String attribute_name = (String)event.getData();
if ( attribute_name.equals( DownloadManagerState.AT_FILE_LINKS )){
setFileLinks();
}else if ( attribute_name.equals( DownloadManagerState.AT_PARAMETERS )){
readParameters();
}
}
}
});
torrent = download_manager_state.getTorrent();
setFileLinks();
// We can't have the identity of this download changing as this will screw up
// anyone who tries to maintain a unique set of downloads (e.g. the GlobalManager)
//
if ( !dl_identity_obtained ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -