📄 downloadmanagerimpl.java
字号:
// doesn't exist, assume it refers directly to the file
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 Exception( "'" + 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;
}
}
// System.out.println( "after: " + torrent_save_dir + "/" + torrent_save_file );
save_dir_file = torrent.isSimpleTorrent()?new File( torrent_save_dir ):new File( torrent_save_dir, torrent_save_file );
if ( !save_dir_file.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 )){
throw( new Exception( MessageText.getString("DownloadManager.error.datamissing") + " " + save_dir_file.toString()));
}
if ( !save_dir_file.mkdirs()){
throw( new Exception( "Directory '" + torrent_save_dir + "' creation fails" ));
}
}
// 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.setTrackerResponseCache( new HashMap());
// also remove resume data incase someone's published a torrent with resume
// data in it
if ( open_for_seeding ){
DiskManagerFactory.setTorrentResumeDataNearlyComplete(download_manager_state, torrent_save_dir, torrent_save_file );
}else{
download_manager_state.clearResumeData();
}
}
//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 = "";
}
nbPieces = torrent.getNumberOfPieces();
// only restore the tracker response cache for non-seeds
if ( DiskManagerFactory.isTorrentResumeDataComplete(download_manager_state, torrent_save_dir, torrent_save_file )) {
download_manager_state.clearTrackerResponseCache();
stats.setDownloadCompleted(1000);
setOnlySeeding(true);
}else{
setOnlySeeding(false);
}
}catch( TOTorrentException e ){
Debug.printStackTrace( e );
nbPieces = 0;
setFailed( TorrentUtils.exceptionToText( e ));
}catch( UnsupportedEncodingException e ){
Debug.printStackTrace( e );
nbPieces = 0;
setFailed( MessageText.getString("DownloadManager.error.unsupportedencoding"));
}catch( Throwable e ){
Debug.printStackTrace( e );
nbPieces = 0;
setFailed( e );
}
if ( download_manager_state == null ){
// torernt's stuffed - create a dummy "null object" to simplify use
// by other code
download_manager_state = DownloadManagerStateImpl.getDownloadState( this );
}
}
private void startServer()
{
server = PEPeerServerFactory.create();
if ( server == null || server.getPort() == 0 ) {
// single port - this situation isn't going to clear easily
setFailed( MessageText.getString("DownloadManager.error.unabletostartserver"));
}
}
/**
* @return
*/
public int getState() {
if (state != STATE_INITIALIZED)
return state;
if (diskManager == null)
return STATE_INITIALIZED;
int diskManagerState = diskManager.getState();
if (diskManagerState == DiskManager.INITIALIZING)
return STATE_INITIALIZED;
if (diskManagerState == DiskManager.ALLOCATING)
return STATE_ALLOCATING;
if (diskManagerState == DiskManager.CHECKING)
return STATE_CHECKING;
if (diskManagerState == DiskManager.READY)
return STATE_READY;
if (diskManagerState == DiskManager.FAULTY)
return STATE_ERROR;
return STATE_ERROR;
}
public boolean getOnlySeeding() {
return onlySeeding;
}
public void
setOnlySeeding(
boolean _onlySeeding)
{
//LGLogger.log(getName()+"] setOnlySeeding("+onlySeeding+") was " + onlySeeding);
if (onlySeeding != _onlySeeding) {
onlySeeding = _onlySeeding;
if (_onlySeeding && filesExist()) {
// make sure stats always knows we are completed
stats.setDownloadCompleted(1000);
}
// we are in a new list, move to the top of the list so that we continue seeding
// -1 position means it hasn't been added to the global list. We shouldn't
// touch it, since it'll get a position once it's adding is complete
if (globalManager != null && position != -1) {
DownloadManager[] dms = { DownloadManagerImpl.this };
// pretend we are at the bottom of the new list
// so that move top will shift everything down one
position = globalManager.getDownloadManagers().size() + 1;
globalManager.moveTop(dms);
// we left a gap in incomplete list, fixup
globalManager.fixUpDownloadManagerPositions();
}
listeners.dispatch( LDT_COMPLETIONCHANGED, new Boolean( _onlySeeding ));
}
}
public boolean filesExist() {
return (filesExistErrorMessage() == "");
}
private String filesExistErrorMessage() {
String strErrMessage = "";
// currently can only seed if whole torrent exists
if (diskManager == null) {
DiskManager dm = DiskManagerFactory.createNoStart( torrent, this);
if (dm.getState() == DiskManager.FAULTY)
strErrMessage = dm.getErrorMessage();
else if (!dm.filesExist())
strErrMessage = dm.getErrorMessage();
dm = null;
} else {
if (!diskManager.filesExist())
strErrMessage = diskManager.getErrorMessage();
}
if (!strErrMessage.equals("")) {
setFailed( MessageText.getString("DownloadManager.error.datamissing") + " " + strErrMessage );
}
return strErrMessage;
}
public boolean
isPersistent()
{
return( persistent );
}
/**
* Returns the 'previous' state.
*/
public int getPrevState() {
return prevState;
}
/**
* Sets the 'previous' state.
*/
public void setPrevState(int prev_state) {
prevState = prev_state;
}
public String
getDisplayName()
{
return( display_name );
}
public String getErrorDetails() {
return errorDetail;
}
public long getSize() {
if (diskManager != null)
return diskManager.getTotalLength();
if(torrent != null)
return torrent.getSize();
return 0;
}
protected void
setFailed()
{
setFailed((String)null );
}
protected void
setFailed(
Throwable e )
{
setFailed( Debug.getNestedExceptionMessage(e));
}
protected void
setFailed(
String reason )
{
if ( reason != null ){
errorDetail = reason;
}
stopIt( DownloadManager.STATE_ERROR, false, false );
}
public void
stopIt(
final int _stateAfterStopping,
final boolean remove_torrent,
final boolean remove_data )
{
if( state == DownloadManager.STATE_STOPPED ||
state == DownloadManager.STATE_ERROR ) {
//already in stopped state, just do removals if necessary
if( remove_data ) deleteDataFiles();
if( remove_torrent ) deleteTorrentFile();
setState( _stateAfterStopping );
return;
}
if (state == DownloadManager.STATE_STOPPING){
return;
}
setState( DownloadManager.STATE_STOPPING );
// this will run synchronously but on a non-daemon thread so that it will under
// normal circumstances complete, even if we're closing
try{
NonDaemonTaskRunner.run(
new NonDaemonTask()
{
public Object
run()
{
int stateAfterStopping = _stateAfterStopping;
try{
if (peerManager != null){
stats.setSavedDownloadedUploaded(
stats.getSavedDownloaded() + peerManager.getStats().getTotalReceived(),
stats.getSavedUploaded() + peerManager.getStats().getTotalSent());
stats.saveDiscarded(stats.getDiscarded());
stats.saveHashFails(stats.getHashFails());
stats.setSecondsDownloading(stats.getSecondsDownloading());
stats.setSecondsOnlySeeding(stats.getSecondsOnlySeeding());
peerManager.removeListener( peer_manager_listener );
peerManager.stopAll();
try{
peer_listeners_mon.enter();
peer_listeners.dispatch( LDT_PE_PM_REMOVED, peerManager );
}finally{
peer_listeners_mon.exit();
}
peerManager = null;
server = null; // clear down ref
}
// kill the tracker client after the peer manager so that the
// peer manager's "stopped" event has a chance to get through
if ( tracker_client != null ){
tracker_client.removeListener( tracker_client_listener );
download_manager_state.setTrackerResponseCache(
tracker_client.getTrackerResponseCache());
tracker_client.destroy();
tracker_client = null;
}
if (diskManager != null){
stats.setCompleted(stats.getCompleted());
stats.setDownloadCompleted(stats.getDownloadCompleted(true));
if (diskManager.getState() == DiskManager.READY){
try{
diskManager.dumpResumeDataToDisk(true, false);
}catch( Exception e ){
errorDetail = "Resume data save fails: " + Debug.getNestedExceptionMessage(e);
stateAfterStopping = STATE_ERROR;
}
}
// we don't want to update the torrent if we're seeding
if ( !onlySeeding ){
download_manager_state.save();
}
diskManager.storeFilePriorities();
diskManager.stop();
diskManager.removeListener( disk_manager_listener );
diskManager = null;
}
}finally{
forceStarted = false;
if( remove_data ){
deleteDataFiles();
}
if( remove_torrent ){
deleteTorrentFile();
}
setState( stateAfterStopping );
}
return( null );
}
});
}catch( Throwable e ){
Debug.printStackTrace( e );
}
}
public void
saveResumeData()
{
if ( getState() == STATE_DOWNLOADING) {
try{
getDiskManager().dumpResumeDataToDisk(false, false);
}catch( Exception e ){
setFailed( errorDetail = "Resume data save fails: " + Debug.getNestedExceptionMessage(e));
}
}
// we don't want to update the torrent if we're seeding
if ( !onlySeeding ){
download_manager_state.save();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -