📄 downloadmanagercontroller.java
字号:
/*
* Created on 29-Jul-2005
* Created by Paul Gardner
* Copyright (C) 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.io.File;
import java.util.ArrayList;
import java.util.List;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.disk.DiskManager;
import org.gudy.azureus2.core3.disk.DiskManagerFactory;
import org.gudy.azureus2.core3.disk.DiskManagerFileInfo;
import org.gudy.azureus2.core3.disk.DiskManagerListener;
import org.gudy.azureus2.core3.disk.DiskManagerPiece;
import org.gudy.azureus2.core3.download.DownloadManager;
import org.gudy.azureus2.core3.download.DownloadManagerDiskListener;
import org.gudy.azureus2.core3.download.DownloadManagerState;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.global.GlobalManagerStats;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.LogRelation;
import org.gudy.azureus2.core3.peer.PEPeer;
import org.gudy.azureus2.core3.peer.PEPeerManager;
import org.gudy.azureus2.core3.peer.PEPeerManagerAdapter;
import org.gudy.azureus2.core3.peer.PEPeerManagerFactory;
import org.gudy.azureus2.core3.peer.PEPeerSource;
import org.gudy.azureus2.core3.peer.PEPiece;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentFile;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncer;
import org.gudy.azureus2.core3.tracker.client.TRTrackerAnnouncerDataProvider;
import org.gudy.azureus2.core3.tracker.client.TRTrackerScraperResponse;
import org.gudy.azureus2.core3.util.AEMonitor;
import org.gudy.azureus2.core3.util.AESemaphore;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.FileUtil;
import org.gudy.azureus2.core3.util.ListenerManager;
import org.gudy.azureus2.core3.util.ListenerManagerDispatcher;
import org.gudy.azureus2.core3.util.NonDaemonTask;
import org.gudy.azureus2.core3.util.NonDaemonTaskRunner;
import org.gudy.azureus2.plugins.network.ConnectionManager;
public class
DownloadManagerController
extends LogRelation
implements PEPeerManagerAdapter
{
// DISK listeners
private static final int LDT_DL_ADDED = 1;
private static final int LDT_DL_REMOVED = 2;
private static ListenerManager disk_listeners_agregator = ListenerManager.createAsyncManager(
"DMC:DiskListenAgregatorDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerDiskListener listener = (DownloadManagerDiskListener)_listener;
if ( type == LDT_DL_ADDED ){
listener.diskManagerAdded((DiskManager)value);
}else if ( type == LDT_DL_REMOVED ){
listener.diskManagerRemoved((DiskManager)value);
}
}
});
private ListenerManager disk_listeners = ListenerManager.createManager(
"DMC:DiskListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object listener,
int type,
Object value )
{
disk_listeners_agregator.dispatch( listener, type, value );
}
});
private AEMonitor disk_listeners_mon = new AEMonitor( "DownloadManagerController:DL" );
protected AEMonitor this_mon = new AEMonitor( "DownloadManagerController" );
protected AEMonitor state_mon = new AEMonitor( "DownloadManagerController:State" );
private DownloadManagerImpl download_manager;
private DownloadManagerStatsImpl stats;
// these are volatile as we want to ensure that if a state is read it is always the
// most up to date value available (as we don't synchronize state read - see below
// for comments)
private volatile int state_set_by_method = DownloadManager.STATE_START_OF_DAY;
private volatile int substate;
private volatile boolean force_start;
// to try and ensure people don't start using disk_manager without properly considering its
// access implications we've given it a silly name
private volatile DiskManager disk_manager_use_accessors;
private DiskManagerFileInfo[] skeleton_files;
private fileInfoFacade[] files_facade;
private PEPeerManager peer_manager;
private String errorDetail;
private GlobalManagerStats global_stats;
protected
DownloadManagerController(
DownloadManagerImpl _download_manager )
{
download_manager = _download_manager;
GlobalManager gm = download_manager.getGlobalManager();
global_stats = gm.getStats();
stats = (DownloadManagerStatsImpl)download_manager.getStats();
}
protected void
setInitialState(
int initial_state )
{
files_facade = new fileInfoFacade[download_manager.getTorrent()==null?0:download_manager.getTorrent().getFiles().length];
for (int i=0;i<files_facade.length;i++){
files_facade[i] = new fileInfoFacade(i);
}
// only take note if there's been no errors
if ( getState() == DownloadManager.STATE_START_OF_DAY ){
setState( initial_state, true );
}
}
public void
startDownload(
TRTrackerAnnouncer tracker_client )
{
DiskManager dm;
try{
this_mon.enter();
if ( getState() != DownloadManager.STATE_READY ){
Debug.out( "DownloadManagerController::startDownload state must be ready, " + getState());
setFailed( "Inconsistent download state: startDownload, state = " + getState());
return;
}
if ( peer_manager != null ){
Debug.out( "DownloadManagerController::startDownload: peer manager not null" );
// try and continue....
peer_manager.stopAll();
peer_manager = null;
}
dm = getDiskManager();
if ( dm == null ){
Debug.out( "DownloadManagerController::startDownload: disk manager is null" );
return;
}
setState( DownloadManager.STATE_DOWNLOADING, false );
}finally{
this_mon.exit();
}
// make sure it is started beore making it "visible"
final PEPeerManager temp = PEPeerManagerFactory.create( tracker_client.getPeerId(), this, dm );
temp.start();
//The connection to the tracker
tracker_client.setAnnounceDataProvider(
new TRTrackerAnnouncerDataProvider()
{
public String
getName()
{
return( getDisplayName());
}
public long
getTotalSent()
{
return(temp.getStats().getTotalDataBytesSent());
}
public long
getTotalReceived()
{
long verified =
temp.getStats().getTotalDataBytesReceived() -
( temp.getStats().getTotalDiscarded() + temp.getStats().getTotalHashFailBytes());
return( verified < 0?0:verified );
}
public long
getRemaining()
{
return( temp.getRemaining());
}
public String
getExtensions()
{
return( getTrackerClientExtensions());
}
public int
getMaxNewConnectionsAllowed()
{
return( temp.getMaxNewConnectionsAllowed());
}
});
peer_manager = temp;
// Inform only after peer_manager.start(), because it
// may have switched it to STATE_SEEDING (in which case we don't need to
// inform).
if (getState() == DownloadManager.STATE_DOWNLOADING) {
download_manager.informStateChanged();
}
download_manager.informStarted( temp );
}
public void
initializeDiskManager(
int initialising_state )
{
initializeDiskManagerSupport(
initialising_state,
new DiskManagerListener()
{
public void
stateChanged(
int oldDMState,
int newDMState )
{
DiskManager dm;
try{
this_mon.enter();
dm = getDiskManager();
if ( dm == null ){
// already been cleared down
return;
}
}finally{
this_mon.exit();
}
try{
if ( newDMState == DiskManager.FAULTY ){
setFailed( dm.getErrorMessage());
}
if ( oldDMState == DiskManager.CHECKING ){
stats.setDownloadCompleted(stats.getDownloadCompleted(true));
download_manager.setOnlySeeding(dm.getRemaining() == 0);
}
if ( newDMState == DiskManager.READY ){
if ( stats.getTotalDataBytesReceived() == 0 &&
stats.getTotalDataBytesSent() == 0 &&
stats.getSecondsDownloading() == 0 ){
int completed = stats.getDownloadCompleted(false);
if ( completed < 1000 ){
// make up some sensible "downloaded" figure for torrents that have been re-added to Azureus
// and resumed
// assume downloaded = uploaded, optimistic but at least results in
// future share ratios relevant to amount up/down from now on
// see bug 1077060
long amount_downloaded = (completed*dm.getTotalLength())/1000;
stats.setSavedDownloadedUploaded( amount_downloaded, amount_downloaded );
}else{
// see GlobalManager for comment on this
int dl_copies = COConfigurationManager.getIntParameter("StartStopManager_iAddForSeedingDLCopyCount");
if ( dl_copies > 0 ){
stats.setSavedDownloadedUploaded( download_manager.getSize()*dl_copies, stats.getTotalDataBytesSent());
}
download_manager.getDownloadState().setFlag( DownloadManagerState.FLAG_ONLY_EVER_SEEDED, true );
}
}
}
}finally{
download_manager.informStateChanged();
}
}
public void
filePriorityChanged(
DiskManagerFileInfo file )
{
}
public void
pieceDoneChanged(
DiskManagerPiece piece )
{
}
public void
fileAccessModeChanged(
DiskManagerFileInfo file,
int old_mode,
int new_mode )
{
}
});
}
protected void
initializeDiskManagerSupport(
int initialising_state,
DiskManagerListener listener )
{
try{
this_mon.enter();
int entry_state = getState();
if ( entry_state != DownloadManager.STATE_WAITING &&
entry_state != DownloadManager.STATE_STOPPED &&
entry_state != DownloadManager.STATE_QUEUED &&
entry_state != DownloadManager.STATE_ERROR ){
Debug.out( "DownloadManagerController::initializeDiskManager: Illegal initialize state, " + entry_state );
setFailed( "Inconsistent download state: initSupport, state = " + entry_state );
return;
}
DiskManager old_dm = getDiskManager();
if ( old_dm != null ){
Debug.out( "DownloadManagerController::initializeDiskManager: disk manager is not null" );
// we shouldn't get here but try to recover the situation
old_dm.stop();
setDiskManager( null );
}
errorDetail = "";
setState( initialising_state, false );
DiskManager dm = DiskManagerFactory.create( download_manager.getTorrent(), download_manager);
setDiskManager( dm );
dm.addListener( listener );
}finally{
this_mon.exit();
download_manager.informStateChanged();
}
}
public boolean
canForceRecheck()
{
int state = getState();
// gotta check error + disk manager state as error can be generated by both
// an overall error or a running disk manager in faulty state
return( (state == DownloadManager.STATE_STOPPED ) ||
(state == DownloadManager.STATE_QUEUED ) ||
(state == DownloadManager.STATE_ERROR && getDiskManager() == null));
}
public void
forceRecheck()
{
try{
this_mon.enter();
if ( getDiskManager() != null || !canForceRecheck() ){
Debug.out( "DownloadManagerController::forceRecheck: illegal entry state" );
return;
}
final int start_state = DownloadManagerController.this.getState();
// remove resume data
download_manager.getDownloadState().clearResumeData();
// For extra protection from a plugin stopping a checking torrent,
// fake a forced start.
final boolean wasForceStarted = force_start;
force_start = true;
// if a file has been deleted we want this recheck to recreate the file and mark
// it as 0%, not fail the recheck. Otherwise the only way of recovering is to remove and
// re-add the torrent
download_manager.setDataAlreadyAllocated( false );
initializeDiskManagerSupport(
DownloadManager.STATE_CHECKING,
new DiskManagerListener()
{
public void
stateChanged(
int oldDMState,
int newDMState )
{
try{
this_mon.enter();
if ( getDiskManager() == null ){
// already closed down via stop
download_manager.setOnlySeeding(false);
return;
}
}finally{
this_mon.exit();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -