📄 downloadmanagerimpl.java
字号:
// flag set true below
dl_identity = torrent_hash==null?torrent.getHash():torrent_hash;
this.dl_identity_hashcode = new String( dl_identity ).hashCode();
}
if ( !Arrays.equals( dl_identity, torrent.getHash())){
torrent = null; // prevent this download from being used
// set up some kinda default else things don't work wel...
torrent_save_location = new File( torrent_save_dir, torrentFileName );
throw( new NoStackException( "Download identity changed - please remove and re-add the download" ));
}
read_torrent_state = null; // no longer needed if we saved it
LocaleUtilDecoder locale_decoder = LocaleTorrentUtil.getTorrentEncoding( torrent );
// if its a simple torrent and an explicit save file wasn't supplied, use
// the torrent name itself
display_name = locale_decoder.decodeString( torrent.getName());
display_name = FileUtil.convertOSSpecificChars( display_name );
internal_name = ByteFormatter.nicePrint(torrent.getHash(),true);
// now we know if its a simple torrent or not we can make some choices about
// the save dir and file. On initial entry the save_dir will have the user-selected
// save location and the save_file will be null
File save_dir_file = new File( torrent_save_dir );
// System.out.println( "before: " + torrent_save_dir + "/" + torrent_save_file );
// if save file is non-null then things have already been sorted out
if ( torrent_save_file == null ){
// make sure we're working off a canonical save dir if possible
try{
if ( save_dir_file.exists()){
save_dir_file = save_dir_file.getCanonicalFile();
}
}catch( Throwable e ){
Debug.printStackTrace(e);
}
if ( torrent.isSimpleTorrent()){
// if target save location is a directory then we use that as the save
// dir and use the torrent display name as the target. Otherwise we
// use the file name
if ( save_dir_file.exists()){
if ( save_dir_file.isDirectory()){
torrent_save_file = display_name;
}else{
torrent_save_dir = save_dir_file.getParent().toString();
torrent_save_file = save_dir_file.getName();
}
}else{
// doesn't exist, assume it refers directly to the file
if ( save_dir_file.getParent() == null ){
throw( new NoStackException( "Data location '" + torrent_save_dir + "' is invalid" ));
}
torrent_save_dir = save_dir_file.getParent().toString();
torrent_save_file = save_dir_file.getName();
}
}else{
// torrent is a folder. It is possible that the natural location
// for the folder is X/Y and that in fact 'Y' already exists and
// has been selected. If ths is the case the select X as the dir and Y
// as the file name
if ( save_dir_file.exists()){
if ( !save_dir_file.isDirectory()){
throw( new NoStackException( "'" + torrent_save_dir + "' is not a directory" ));
}
if ( save_dir_file.getName().equals( display_name )){
torrent_save_dir = save_dir_file.getParent().toString();
}
}
torrent_save_file = display_name;
}
}
torrent_save_location = new File( torrent_save_dir, torrent_save_file );
// final validity test must be based of potentially linked target location as file
// may have been re-targetted
File linked_target = getSaveLocation();
if ( !linked_target.exists()){
// if this isn't a new torrent then we treat the absence of the enclosing folder
// as a fatal error. This is in particular to solve a problem with the use of
// externally mounted torrent data on OSX, whereby a re-start with the drive unmounted
// results in the creation of a local diretory in /Volumes that subsequently stuffs
// up recovery when the volume is mounted
// changed this to only report the error on non-windows platforms
if ( !(new_torrent || Constants.isWindows )){
// another exception here - if the torrent has never been started then we can
// fairly safely continue as its in a stopped state
if ( has_ever_been_started ){
throw( new NoStackException( MessageText.getString("DownloadManager.error.datamissing") + " " + linked_target.toString()));
}
}
}
// if this is a newly introduced torrent trash the tracker cache. We do this to
// prevent, say, someone publishing a torrent with a load of invalid cache entries
// in it and a bad tracker URL. This could be used as a DOS attack
if ( new_torrent ){
download_manager_state.setLongParameter( DownloadManagerState.PARAM_DOWNLOAD_ADDED_TIME, SystemTime.getCurrentTime());
download_manager_state.setTrackerResponseCache( new HashMap());
// also remove resume data incase someone's published a torrent with resume
// data in it
if ( for_seeding ){
DiskManagerFactory.setTorrentResumeDataNearlyComplete(download_manager_state);
// Prevent download being considered for on-completion moving - it's considered complete anyway.
download_manager_state.setFlag(DownloadManagerState.FLAG_MOVE_ON_COMPLETION_DONE, true);
}else{
download_manager_state.clearResumeData();
}
}else{
long add_time = download_manager_state.getLongParameter( DownloadManagerState.PARAM_DOWNLOAD_ADDED_TIME );
if ( add_time == 0 ){
// grab an initial value from torrent file - migration only
try{
add_time = new File( torrentFileName ).lastModified();
}catch( Throwable e ){
}
if ( add_time == 0 ){
add_time = SystemTime.getCurrentTime();
}
download_manager_state.setLongParameter( DownloadManagerState.PARAM_DOWNLOAD_ADDED_TIME, add_time );
}
}
//trackerUrl = torrent.getAnnounceURL().toString();
torrent_comment = locale_decoder.decodeString(torrent.getComment());
if ( torrent_comment == null ){
torrent_comment = "";
}
torrent_created_by = locale_decoder.decodeString(torrent.getCreatedBy());
if ( torrent_created_by == null ){
torrent_created_by = "";
}
// only restore the tracker response cache for non-seeds
if ( download_manager_state.isResumeDataComplete()){
// actually, can't think of a good reason not to restore the
// cache for seeds, after all if the tracker's down we still want
// to connect to peers to upload to
// download_manager_state.clearTrackerResponseCache();
stats.setDownloadCompleted(1000);
setAssumedComplete(true);
}else{
setAssumedComplete(false);
}
}catch( TOTorrentException e ){
//Debug.printStackTrace( e );
setFailed( TorrentUtils.exceptionToText( e ));
}catch( UnsupportedEncodingException e ){
Debug.printStackTrace( e );
setFailed( MessageText.getString("DownloadManager.error.unsupportedencoding"));
}catch( NoStackException e ){
Debug.outNoStack( e.getMessage());
}catch( Throwable e ){
Debug.printStackTrace( e );
setFailed( e );
}finally{
dl_identity_obtained = true;
}
if ( download_manager_state == null ){
read_torrent_state =
new Object[]{
torrent_save_dir, torrent_save_file, torrent_hash,
new Boolean(new_torrent), new Boolean( for_seeding ), new Boolean( has_ever_been_started ),
new Integer( initial_state )
};
// torrent's stuffed - create a dummy "null object" to simplify use
// by other code
download_manager_state = DownloadManagerStateImpl.getDownloadState( this );
// make up something vaguely sensible for save location
if ( torrent_save_file == null ){
torrent_save_location = new File( torrent_save_dir );
}else{
torrent_save_location = new File( torrent_save_dir, torrent_save_file );
}
}else{
// make up something vaguely sensible for save location if we haven't got one
if ( torrent_save_file == null ){
torrent_save_location = new File( torrent_save_dir );
}
// make sure we know what networks to use for this download
if ( download_manager_state.getNetworks().length == 0 ){
String[] networks = AENetworkClassifier.getNetworks( torrent, display_name );
download_manager_state.setNetworks( networks );
}
if ( download_manager_state.getPeerSources().length == 0 ){
String[] ps = PEPeerSource.getPeerSources();
download_manager_state.setPeerSources( ps );
}
}
}finally{
if ( torrent_save_location != null ){
try{
torrent_save_location = torrent_save_location.getCanonicalFile();
}catch( Throwable e ){
torrent_save_location = torrent_save_location.getAbsoluteFile();
}
}
// must be after torrent read, so that any listeners have a TOTorrent
// not that if things have failed above this method won't override a failed
// state with the initial one
controller.setInitialState( initial_state );
}
}
protected void
readTorrent()
{
if ( read_torrent_state == null ){
return;
}
readTorrent(
(String)read_torrent_state[0],
(String)read_torrent_state[1],
(byte[])read_torrent_state[2],
((Boolean)read_torrent_state[3]).booleanValue(),
((Boolean)read_torrent_state[4]).booleanValue(),
((Boolean)read_torrent_state[5]).booleanValue(),
((Integer)read_torrent_state[6]).intValue());
}
protected void
readParameters()
{
max_connections = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_PEERS );
max_connections_when_seeding_enabled = getDownloadState().getBooleanParameter( DownloadManagerState.PARAM_MAX_PEERS_WHEN_SEEDING_ENABLED );
max_connections_when_seeding = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_PEERS_WHEN_SEEDING );
max_seed_connections = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_SEEDS );
max_uploads = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_UPLOADS );
max_uploads_when_seeding_enabled = getDownloadState().getBooleanParameter( DownloadManagerState.PARAM_MAX_UPLOADS_WHEN_SEEDING_ENABLED );
max_uploads_when_seeding = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_UPLOADS_WHEN_SEEDING );
max_upload_when_busy_bps = getDownloadState().getIntParameter( DownloadManagerState.PARAM_MAX_UPLOAD_WHEN_BUSY ) * 1024;
max_uploads = Math.max( max_uploads, DownloadManagerState.MIN_MAX_UPLOADS );
max_uploads_when_seeding = Math.max( max_uploads_when_seeding, DownloadManagerState.MIN_MAX_UPLOADS );
}
protected int
getMaxConnections()
{
return( max_connections );
}
protected int
getMaxConnectionsWhenSeeding()
{
return( max_connections_when_seeding );
}
protected boolean
isMaxConnectionsWhenSeedingEnabled()
{
return( max_connections_when_seeding_enabled );
}
protected int
getMaxSeedConnections()
{
return( max_seed_connections );
}
protected boolean
isMaxUploadsWhenSeedingEnabled()
{
return( max_uploads_when_seeding_enabled );
}
protected int
getMaxUploadsWhenSeeding()
{
return( max_uploads_when_seeding );
}
public int
getMaxUploads()
{
return( max_uploads );
}
public void
setMaxUploads(
int max )
{
download_manager_state.setIntParameter( DownloadManagerState.PARAM_MAX_UPLOADS, max );
}
public int
getEffectiveMaxUploads()
{
if ( isMaxUploadsWhenSeedingEnabled() && getState() == DownloadManager.STATE_SEEDING ){
return( getMaxUploadsWhenSeeding());
}else{
return( max_uploads );
}
}
public int
getEffectiveUploadRateLimitBytesPerSecond()
{
int local_max_bps = stats.getUploadRateLimitBytesPerSecond();
int rate = local_max_bps;
if ( max_upload_when_busy_bps != 0 ){
long now = SystemTime.getCurrentTime();
if ( now < last_upload_when_busy_update || now - last_upload_when_busy_update > 5000 ){
last_upload_when_busy_update = now;
// might need to impose the limit
String key = TransferSpeedValidator.getActiveUploadParameter( globalManager );
int global_limit_bps = COConfigurationManager.getIntParameter( key )*1024;
if ( global_limit_bps > 0 && max_upload_when_busy_bps < global_limit_bps ){
// we have a global limit and a valid busy limit
local_max_bps = local_max_bps==0?global_limit_bps:local_max_bps;
GlobalManagerStats gm_stats = globalManager.getStats();
int actual = gm_stats.getDataSendRateNoLAN() + gm_stats.getProtocolSendRateNoLAN();
int move_by = ( local_max_bps - max_upload_when_busy_bps ) / 10;
if ( move_by < 1024 ){
move_by = 1024;
}
if ( global_limit_bps - actual <= 2*1024 ){
// close enough to impose the busy limit downwards
if ( current_upload_when_busy_bps == 0 ){
current_upload_when_busy_bps = local_max_bps;
}
int prev_upload_when_busy_bps = current_upload_when_busy_bps;
current_upload_when_busy_bps -= move_by;
if ( current_upload_when_busy_bps < max_upload_when_busy_bps ){
current_upload_when_busy_bps = max_upload_when_busy_bps;
}
if ( current_upload_when_busy_bps < prev_upload_when_busy_bps ){
last_upload_when_busy_dec_time = now;
}
}else{
// not hitting limit, increase
if ( current_upload_when_busy_bps != 0 ){
// only try increment if sufficient time passed
if ( upload_when_busy_min_secs == 0 ||
now < last_upload_when_busy_dec_time ||
now - last_upload_when_busy_dec_time >= upload_when_busy_min_secs*1000 ){
current_upload_when_busy_bps += move_by;
if ( current_upload_when_busy_bps >= local_max_bps ){
current_upload_when_busy_bps = 0;
}
}
}
}
if ( current_upload_when_busy_bps > 0 ){
rate = current_upload_when_busy_bps;
}
}else{
current_upload_when_busy_bps = 0;
}
}else{
if ( current_upload_when_busy_bps > 0 ){
rate = current_upload_when_busy_bps;
}
}
}
return( rate );
}
protected void
setFileLinks()
{
// invalidate the cache info in case its now wrong
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -