📄 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.UnsupportedEncodingException;
import java.util.*;
import java.net.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.disk.*;
import org.gudy.azureus2.core3.global.GlobalManager;
import org.gudy.azureus2.core3.internat.*;
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.core3.logging.*;
/**
* @author Olivier
*
*/
public class
DownloadManagerImpl
implements DownloadManager
{
// 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 ListenerManager listeners = ListenerManager.createManager(
"DMM:ListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerListener listener = (DownloadManagerListener)_listener;
if ( type == LDT_STATECHANGED ){
listener.stateChanged(DownloadManagerImpl.this, ((Integer)value).intValue());
}else if ( type == LDT_DOWNLOADCOMPLETE ){
listener.downloadComplete(DownloadManagerImpl.this);
}else if ( type == LDT_COMPLETIONCHANGED ){
listener.completionChanged(DownloadManagerImpl.this, ((Boolean)value).booleanValue());
}else if ( type == LDT_POSITIONCHANGED ){
listener.positionChanged(DownloadManagerImpl.this,
((Integer)value).intValue(), position);
}
}
});
// TrackerListeners
private static final int LDT_TL_ANNOUNCERESULT = 1;
private static final int LDT_TL_SCRAPERESULT = 2;
private ListenerManager tracker_listeners = ListenerManager.createManager(
"DMM:TrackerListenDispatcher",
new ListenerManagerDispatcher()
{
public void
dispatch(
Object _listener,
int type,
Object value )
{
DownloadManagerTrackerListener listener = (DownloadManagerTrackerListener)_listener;
if ( type == LDT_TL_ANNOUNCERESULT ){
listener.announceResult((TRTrackerResponse)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;
private ListenerManager peer_listeners = ListenerManager.createAsyncManager(
"DMM:PeerListenDispatcher",
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 AEMonitor peer_listeners_mon = new AEMonitor( "DownloadManager:PL" );
private List current_peers = new ArrayList();
private List current_pieces = new ArrayList();
private DownloadManagerStatsImpl stats;
private boolean persistent;
/**
* forceStarted torrents can't/shouldn't be automatically stopped
*/
private boolean forceStarted;
/**
* Only seed this torrent. Never download or allocate<P>
* Current Implementation:
* - implies that the user completed the download at one point
* - Checks if there's Data Missing when torrent is done (or torrent load)
*
* Perhaps a better name would be "bCompleted"
*/
protected boolean onlySeeding;
private int state = -1;
private int prevState = -1;
private String errorDetail;
private GlobalManager globalManager;
private String torrentFileName;
private int nbPieces;
private String display_name;
// torrent_save_dir is always the directory within which torrent data is being saved. That is, it
// never includes the torrent data itself. In particular it DOESN'T include the dir name of a
// non-simple torrent
private String torrent_save_dir;
// torrent_save_file is the top level file corresponding to the torrent save data location. This
// will be the file name for simple torrents and the folder name for non-simple ones
private String torrent_save_file;
// Position in Queue
private int position = -1;
//Used when trackerConnection is not yet created.
// private String trackerUrl;
private PEPeerServer server;
private DownloadManagerState download_manager_state;
private TOTorrent torrent;
private String torrent_comment;
private String torrent_created_by;
private TRTrackerClient tracker_client;
private TRTrackerClientListener tracker_client_listener;
private long scrape_random_seed = SystemTime.getCurrentTime();
private DiskManager diskManager;
private DiskManagerListener disk_manager_listener;
private PEPeerManager peerManager;
private PEPeerManagerListener peer_manager_listener;
private HashMap data;
private boolean data_already_allocated = false;
private long creation_time = SystemTime.getCurrentTime();
// 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 )
{
persistent = _persistent;
stats = new DownloadManagerStatsImpl( this );
globalManager = _gm;
stats.setMaxUploads( COConfigurationManager.getIntParameter("Max Uploads") );
forceStarted = false;
torrentFileName = _torrentFileName;
torrent_save_dir = _torrent_save_dir;
torrent_save_file = _torrent_save_file;
// readTorrent adjusts the save dir and file to be sensible values
readTorrent( _torrent_hash, persistent && !_recovered, _open_for_seeding );
// must be after readTorrent, so that any listeners have a TOTorrent
if (state == -1){
setState( _initialState );
}
}
public void
initialize()
{
setState( STATE_INITIALIZING );
// If we only want to seed, do a quick check first (before we create the diskManager, which allocates diskspace)
if (onlySeeding && !filesExist()) {
// If the user wants to re-download the missing files, they must
// do a re-check, which will reset the onlySeeding flag.
return;
}
if ( torrent == null ) {
setFailed();
return;
}
errorDetail = "";
startServer();
if ( state == STATE_WAITING || state == STATE_ERROR ){
return;
}
try{
if ( tracker_client != null ){
tracker_client.destroy();
}
tracker_client = TRTrackerClientFactory.create( torrent, server );
tracker_client.setTrackerResponseCache( download_manager_state.getTrackerResponseCache());
tracker_client_listener = new TRTrackerClientListener() {
public void receivedTrackerResponse(TRTrackerResponse response) {
PEPeerManager pm = peerManager;
if ( pm != null ) {
pm.processTrackerResponse( response );
}
tracker_listeners.dispatch( LDT_TL_ANNOUNCERESULT, response );
}
public void urlChanged(String url, boolean explicit) {
if ( explicit ){
checkTracker( true );
}
}
public void urlRefresh() {
checkTracker( true );
}
};
tracker_client.addListener( tracker_client_listener );
if ( getState() != STATE_ERROR ){
// we need to set the state to "initialized" before kicking off the disk manager
// initialisation as it should only report its status while in the "initialized"
// state (see getState for how this works...)
setState( STATE_INITIALIZED );
initializeDiskManager();
}
}catch( TRTrackerClientException e ){
setFailed( e );
}
}
public void
startDownload()
{
setState( STATE_DOWNLOADING );
PEPeerManager temp = PEPeerManagerFactory.create(this, server, tracker_client, diskManager);
peer_manager_listener =
new PEPeerManagerListener()
{
public void
stateChanged(
int new_state )
{
}
};
temp.addListener( peer_manager_listener );
temp.start();
try{
peer_listeners_mon.enter();
peerManager = temp; // delay this so peerManager var not available to other threads until it is started
peer_listeners.dispatch( LDT_PE_PM_ADDED, temp );
}finally{
peer_listeners_mon.exit();
}
tracker_client.update( true );
}
private void
readTorrent(
byte[] torrent_hash, // can be null for initial torrents
boolean new_torrent, // probably equivalend to (torrent_hash == null)????
boolean open_for_seeding )
{
display_name = torrentFileName; // default if things go wrong decoding it
//trackerUrl = "";
torrent_comment = "";
torrent_created_by = "";
nbPieces = 0;
try {
download_manager_state =
DownloadManagerStateImpl.getDownloadState(
this, torrentFileName, torrent_hash );
torrent = download_manager_state.getTorrent();
LocaleUtilDecoder locale_decoder = LocaleUtil.getSingleton().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 );
// 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 ){
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{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -