package org.limewire.core.impl.download.listener; import java.io.File; import java.io.IOException; import java.util.List; import org.limewire.bittorrent.TorrentManager; import org.limewire.core.api.download.DownloadAction; import org.limewire.core.api.download.DownloadException; import org.limewire.core.api.download.DownloadItem; import org.limewire.listener.EventListener; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import org.limewire.util.FileUtils; import org.limewire.util.Objects; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.limegroup.bittorrent.BTDownloader; import com.limegroup.bittorrent.BTTorrentFileDownloader; import com.limegroup.gnutella.ActivityCallback; import com.limegroup.gnutella.DownloadManager; import com.limegroup.gnutella.Downloader; import com.limegroup.gnutella.Downloader.DownloadState; import com.limegroup.gnutella.downloader.CoreDownloader; import com.limegroup.gnutella.downloader.DownloadStateEvent; /** * Listens for downloads of .torrent files to complete. When the download * finishes then the torrent download will be started. */ public class TorrentDownloadListener implements EventListener<DownloadStateEvent> { private static final Log LOG = LogFactory.getLog(TorrentDownloadListener.class); private final Downloader downloader; private final DownloadManager downloadManager; private final ActivityCallback activityCallback; private final List<DownloadItem> downloadItems; private final TorrentManager torrentManager; @Inject public TorrentDownloadListener(DownloadManager downloadManager, ActivityCallback activityCallback, TorrentManager torrentManager, @Assisted List<DownloadItem> downloadItems, @Assisted Downloader downloader) { this.downloader = Objects.nonNull(downloader, "downloader"); this.downloadManager = Objects.nonNull(downloadManager, "downloadManager"); this.torrentManager = Objects.nonNull(torrentManager, "torrentManager"); this.activityCallback = Objects.nonNull(activityCallback, "activityCallback"); this.downloadItems = Objects.nonNull(downloadItems, "downloadItems"); if (downloader.getState() == DownloadState.COMPLETE) { if (downloader instanceof CoreDownloader) { handleEvent(new DownloadStateEvent((CoreDownloader) downloader, DownloadState.COMPLETE)); } } } @Override public void handleEvent(DownloadStateEvent event) { DownloadState downloadStatus = event.getType(); if (DownloadState.SCAN_FAILED == downloadStatus) { if (downloader instanceof BTDownloader) { return; } if (!activityCallback.promptAboutTorrentDownloadWithFailedScan()) { // Don't start downloading if the user said not to return; } } else if (DownloadState.COMPLETE != downloadStatus) { // Don't need to kick off any torrents for other states since the // torrent file hasn't been recieved. return; } if (downloader instanceof BTTorrentFileDownloader) { handleBTTorrentFileDownloader(); } else { handleCoreDownloader(); } } private void handleCoreDownloader() { File possibleTorrentFile = null; possibleTorrentFile = downloader.getSaveFile(); String fileExtension = FileUtils.getFileExtension(possibleTorrentFile); if ("torrent".equalsIgnoreCase(fileExtension)) { try { downloadManager.downloadTorrent(possibleTorrentFile, null, false); downloadItems.remove(getDownloadItem(downloader)); } catch (DownloadException e) { final File torrentFile = possibleTorrentFile; activityCallback.handleDownloadException(new DownloadAction() { @Override public void download(File saveDirectory, boolean overwrite) throws DownloadException { downloadManager.downloadTorrent(torrentFile, saveDirectory, overwrite); downloadItems.remove(getDownloadItem(downloader)); } @Override public void downloadCanceled(DownloadException ignored) { // nothing to do } }, e, false); } } } private void handleBTTorrentFileDownloader() { File torrentCopy = null; File torrentFile = null; final BTTorrentFileDownloader btTorrentFileDownloader = (BTTorrentFileDownloader) downloader; try { torrentFile = btTorrentFileDownloader.getTorrentFile(); try { torrentCopy = FileUtils.createTempFile("tmp-torrent", ""); torrentCopy.deleteOnExit(); } catch (IOException e) { //If the copy does not succeed the download can still continue. //It is just recovering from an error that will not be possible //When this happens. LOG.error("Error copying the torrentFile", e); } //copy used to handle certain exception cases where the //old torrent file may have been removed because of logic to //clean up the downloaders. This is because downloadTorrent, will //call the deleteIncomplete files method for the downloader and //the only copy is the one in the incomplete files directory. //by keeping a copy around we can continue the download if needed. FileUtils.copy(torrentFile, torrentCopy); downloadManager.downloadTorrent(torrentFile, null, false); downloadItems.remove(getDownloadItem(downloader)); } catch (DownloadException e) { final File torrentFileFinal = torrentFile; final File torrentCopyFinal = torrentCopy; activityCallback.handleDownloadException(new DownloadAction() { @Override public void download(File saveDirectory, boolean overwrite) throws DownloadException { FileUtils.copy(torrentCopyFinal, torrentFileFinal); downloadManager.downloadTorrent(torrentFileFinal, saveDirectory, overwrite); downloadItems.remove(getDownloadItem(downloader)); FileUtils.forceDelete(torrentCopyFinal); } @Override public void downloadCanceled(DownloadException ex) { if (!torrentManager.isDownloadingTorrent(torrentFileFinal)) { // need to delete to clean up the torrent file in the // incomplete directory FileUtils.forceDelete(torrentFileFinal); } FileUtils.forceDelete(torrentCopyFinal); } }, e, false); } } DownloadItem getDownloadItem(Downloader downloader) { DownloadItem item = (DownloadItem) downloader.getAttribute(DownloadItem.DOWNLOAD_ITEM); return item; } }