package com.limegroup.bittorrent; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.limewire.bittorrent.LimeWireTorrentProperties; import org.limewire.bittorrent.Torrent; import org.limewire.bittorrent.TorrentFileEntry; import org.limewire.bittorrent.TorrentInfo; import org.limewire.bittorrent.TorrentParams; import org.limewire.core.settings.BittorrentSettings; import org.limewire.inject.LazySingleton; import org.limewire.libtorrent.LibTorrentParams; import org.limewire.logging.Log; import org.limewire.logging.LogFactory; import org.limewire.util.FileUtils; import org.limewire.util.GenericsUtils; import org.limewire.util.URIUtils; import org.limewire.util.GenericsUtils.ScanMode; import com.google.inject.Inject; import com.google.inject.Provider; import com.limegroup.gnutella.ActivityCallback; /** * This class is responsible for saving a torrent as an upload memento and * loading them at startup. */ @LazySingleton public class TorrentUploadManager implements BTUploaderFactory { private static final Log LOG = LogFactory.getLog(TorrentUploadManager.class); private final Provider<ActivityCallback> activityCallback; private final Provider<LimeWireTorrentManager> torrentManager; @Inject public TorrentUploadManager(Provider<LimeWireTorrentManager> torrentManager, Provider<ActivityCallback> activityCallback) { this.torrentManager = torrentManager; this.activityCallback = activityCallback; } /** * Iterates through the uploads folder finding saved torrent mementos and * starting off the uploads. */ @SuppressWarnings("unchecked") public void loadSavedUploads() { File uploadsDirectory = BittorrentSettings.TORRENT_UPLOADS_FOLDER.get(); if (uploadsDirectory.exists()) { File[] uploadMementos = uploadsDirectory.listFiles(new FileFilter() { @Override public boolean accept(File file) { return "memento".equals(FileUtils.getFileExtension(file)); } }); if (uploadMementos != null) { for (File mementoFile : uploadMementos) { Map<String, Object> memento = null; try { memento = readMemento(mementoFile); } catch (IllegalArgumentException e) { LOG.error("Error reading memento for: " + mementoFile, e); } catch (IOException e) { LOG.error("Error reading memento for: " + mementoFile, e); } catch (ClassNotFoundException e) { LOG.error("Error reading memento for: " + mementoFile, e); } if (memento != null) { long mementoModifiedTime = mementoFile.lastModified(); File torrentFile = (File) memento.get("torrentFile"); File fastResumeFile = (File) memento.get("fastResumeFile"); File torrentDataFile = (File) memento.get("torrentDataFile"); String sha1 = (String) memento.get("sha1"); String name = (String) memento.get("name"); Float seedRatioLimit = (Float) memento.get("seedRatioLimit"); Integer timeRatioLimit = (Integer) memento.get("timeRatioLimit"); List<URI> trackers = (List<URI>) memento.get("trackers"); if (trackers == null) { String firstTracker = (String) memento.get("trackerURL"); try { trackers = Arrays.asList(URIUtils.toURI(firstTracker)); } catch (URISyntaxException e) { // No valid trackers found in memento } } boolean torrentAdded = false; boolean torrentLoaded = false; Torrent torrent = null; if (torrentDataFile.exists() && fastResumeFile != null && fastResumeFile.exists()) { if (torrentManager.get().isValid() && !torrentManager.get().isDownloadingTorrent(mementoFile)) { try { TorrentParams params = new LibTorrentParams(torrentDataFile .getParentFile(), name, sha1); params.setTrackers(trackers); params.setFastResumeFile(fastResumeFile); params.setTorrentFile(torrentFile); params.setTorrentDataFile(torrentDataFile); if(seedRatioLimit != null) params.setSeedRatioLimit(seedRatioLimit); if(timeRatioLimit != null) params.setTimeRatioLimit(timeRatioLimit); torrent = torrentManager.get().seedTorrent(params); if (torrent != null) { torrentAdded = true; if (torrent.hasMetaData()) { TorrentInfo torrentInfo = torrent.getTorrentInfo(); boolean filesOk = true; for (TorrentFileEntry entry : torrentInfo .getTorrentFileEntries()) { int priority = entry.getPriority(); if (priority > 0) { File torrentFileEntry = torrent .getTorrentDataFile(entry); boolean exists = torrentFileEntry.exists(); long fileModifiedTime = torrentFileEntry .lastModified(); if (!exists || fileModifiedTime > mementoModifiedTime) { filesOk = false; break; } } } if (filesOk) { createBTUploader(torrent); torrent.setAutoManaged(true); torrent.start(); torrentLoaded = true; } } } } catch (IOException e) { LOG.error("Error initializing memento from: " + mementoFile, e); } } } if (!torrentLoaded) { cleanup(mementoFile, torrentFile, fastResumeFile); if (torrent != null && torrentAdded) { torrentManager.get().removeTorrent(torrent); } } } } } } } private void cleanup(File mementoFile, File torrentFile, File fastResumeFile) { if (torrentFile != null) { FileUtils.delete(torrentFile, false); } if (fastResumeFile != null) { FileUtils.delete(fastResumeFile, false); } if (mementoFile != null) { FileUtils.delete(mementoFile, false); } } private Map<String, Object> readMemento(File mementoFile) throws IOException, ClassNotFoundException, IllegalArgumentException { Object mementoObject = FileUtils.readObject(mementoFile); Map<String, Object> memento = GenericsUtils.scanForMap(mementoObject, String.class, Object.class, ScanMode.EXCEPTION); return memento; } /** * Creates an upload memento from the Torrent and writes it to disk. */ public void writeMemento(Torrent torrent) throws IOException { File torrentMomento = getMementoFile(torrent); torrentMomento.getParentFile().mkdirs(); Map<String, Object> map = new HashMap<String, Object>(); map.put("torrentDataFile", torrent.getTorrentDataFile().getAbsoluteFile()); File torrentFile = torrent.getTorrentFile(); if(torrentFile != null) map.put("torrentFile", torrentFile.getAbsoluteFile()); map.put("fastResumeFile", torrent.getFastResumeFile().getAbsoluteFile()); map.put("sha1", torrent.getSha1()); map.put("trackers", torrent.getTrackerURIS()); map.put("name", torrent.getName()); float seedRatioLimit = torrent.getProperty(LimeWireTorrentProperties.MAX_SEED_RATIO_LIMIT, -1f); if(seedRatioLimit >= 0) map.put("seedRatioLimit", seedRatioLimit); int seedTimeRatioLimit = torrent.getProperty(LimeWireTorrentProperties.MAX_SEED_TIME_RATIO_LIMIT, -1); if(seedTimeRatioLimit >= 0) map.put("timeRatioLimit", seedTimeRatioLimit); FileUtils.writeObject(torrentMomento, map); } private File getMementoFile(Torrent torrent) { File torrentMomento = new File(BittorrentSettings.TORRENT_UPLOADS_FOLDER.get(), torrent .getName() + ".memento"); return torrentMomento; } /** * Removes any found upload mementos/artifacts for the given torrent from * disk. */ public void removeMemento(Torrent torrent) { File torrentMomento = getMementoFile(torrent); FileUtils.forceDelete(torrentMomento); if(torrent.getTorrentFile() != null && torrent.getTorrentFile().getParentFile().equals(BittorrentSettings.TORRENT_UPLOADS_FOLDER.get())) { FileUtils.forceDelete(torrent.getTorrentFile()); } if(torrent.getFastResumeFile().getParentFile().equals(BittorrentSettings.TORRENT_UPLOADS_FOLDER.get())) { FileUtils.forceDelete(torrent.getFastResumeFile()); } } @Override public BTUploader createBTUploader(Torrent torrent) { BTUploader btUploader = new BTUploader(torrent, activityCallback.get(), this, torrentManager.get()); btUploader.registerTorrentListener(); activityCallback.get().addUpload(btUploader); return btUploader; } }