private void startNewDownloads() { boolean isLimited = true; int currentAllowedDownloadCount = 0; { final int allowedConcurrentDownloads = Core.frostSettings.getIntValue(SettingsClass.DOWNLOAD_MAX_THREADS); if (allowedConcurrentDownloads <= 0) { isLimited = false; } else { int runningDownloads = 0; for (final FrostDownloadItem dlItem : downloadModelItems.values()) { if (!dlItem.isExternal() && dlItem.getState() == FrostDownloadItem.STATE_PROGRESS) { runningDownloads++; } } currentAllowedDownloadCount = allowedConcurrentDownloads - runningDownloads; if (currentAllowedDownloadCount < 0) { currentAllowedDownloadCount = 0; } } } { while (!isLimited || currentAllowedDownloadCount > 0) { final FrostDownloadItem dlItem = FileTransferManager.inst().getDownloadManager().selectNextDownloadItem(); if (dlItem == null) { break; } // start the download if (startDownload(dlItem)) { currentAllowedDownloadCount--; } } } }
private void applyPriority(final FrostDownloadItem dlItem, final FcpPersistentGet getReq) { // apply externally changed priority if (dlItem.getPriority() != getReq.getPriority()) { if (Core.frostSettings.getBoolValue(SettingsClass.FCP2_ENFORCE_FROST_PRIO_FILE_DOWNLOAD)) { // reset priority with our current value fcpTools.changeRequestPriority(getReq.getIdentifier(), dlItem.getPriority()); } else { // apply to downloaditem dlItem.setPriority(getReq.getPriority()); } } }
public void persistentRequestError(final String id, final NodeMessage nm) { if (uploadModelItems.containsKey(id)) { final FrostUploadItem item = uploadModelItems.get(id); item.setEnabled(false); item.setState(FrostUploadItem.STATE_FAILED); item.setErrorCodeDescription(nm.getStringValue("CodeDescription")); } else if (downloadModelItems.containsKey(id)) { final FrostDownloadItem item = downloadModelItems.get(id); item.setEnabled(false); item.setState(FrostDownloadItem.STATE_FAILED); item.setErrorCodeDescription(nm.getStringValue("CodeDescription")); } else { System.out.println("persistentRequestError: ID not in any model: " + id); } }
public synchronized void appendItemToQueue(final FrostDownloadItem item) { final String id = item.getGqIdentifier(); directGETsInProgress.add(id); queue.addLast(item); notifyAll(); // notify all waiters (if any) of new record }
/** * Enqueue a direct GET if not already enqueued, or already downloaded to download dir. * * @return true if item was enqueued */ public boolean maybeEnqueueDirectGet( final FrostDownloadItem dlItem, final long expectedFileSize) { if (!isDirectTransferInProgress(dlItem)) { final File targetFile = new File(dlItem.getDownloadFilename()); if (!targetFile.isFile() || targetFile.length() != expectedFileSize) { directTransferQueue.appendItemToQueue(dlItem); return true; } } return false; }
private void addExternalItem(final FcpPersistentGet downloadRequest) { // direct downloads maybe have no filename, use identifier String fileName = downloadRequest.getFilename(); if (fileName == null) { fileName = downloadRequest.getIdentifier(); } else if (fileName.indexOf('/') > -1 || fileName.indexOf('\\') > -1) { // filename contains directories, use only filename final String stmp = new File(fileName).getName(); if (stmp.length() > 0) { fileName = stmp; // use plain filename } } final FrostDownloadItem dlItem = new FrostDownloadItem(fileName, downloadRequest.getUri()); dlItem.setExternal(true); dlItem.setGqIdentifier(downloadRequest.getIdentifier()); dlItem.setState(FrostDownloadItem.STATE_PROGRESS); SwingUtilities.invokeLater( new Runnable() { public void run() { downloadModel.addExternalItem(dlItem); } }); applyState(dlItem, downloadRequest); }
public boolean startDownload(final FrostDownloadItem dlItem) { if (dlItem == null || dlItem.getState() != FrostDownloadItem.STATE_WAITING) { return false; } dlItem.setDownloadStartedTime(System.currentTimeMillis()); dlItem.setState(FrostDownloadItem.STATE_PROGRESS); final String gqid = dlItem.getGqIdentifier(); final File targetFile = new File(dlItem.getDownloadFilename()); boolean isDda = fcpTools.startPersistentGet(dlItem.getKey(), gqid, targetFile, dlItem.getPriority()); dlItem.setDirect(!isDda); return true; }
public void persistentRequestRemoved(final FcpPersistentGet downloadRequest) { if (downloadModelItems.containsKey(downloadRequest.getIdentifier())) { final FrostDownloadItem dlItem = downloadModelItems.get(downloadRequest.getIdentifier()); if (dlItem.isExternal()) { SwingUtilities.invokeLater( new Runnable() { public void run() { List<FrostDownloadItem> itemList = new ArrayList<FrostDownloadItem>(); itemList.add(dlItem); downloadModel.removeItems(itemList); } }); } else { if (dlItem.isInternalRemoveExpected()) { dlItem.setInternalRemoveExpected(false); // clear flag } else if (dlItem.getState() != FrostDownloadItem.STATE_DONE) { dlItem.setEnabled(false); dlItem.setState(FrostDownloadItem.STATE_FAILED); dlItem.setErrorCodeDescription("Disappeared from global queue"); } } } }
/** Must be called after the upload and download model is initialized! */ public PersistenceManager(final UploadModel um, final DownloadModel dm) throws Throwable { showExternalItemsDownload = Core.frostSettings.getBoolValue(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_DOWNLOAD); showExternalItemsUpload = Core.frostSettings.getBoolValue(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_UPLOAD); if (FcpHandler.inst().getFreenetNode() == null) { throw new Exception("No freenet nodes defined"); } final NodeAddress na = FcpHandler.inst().getFreenetNode(); fcpConn = FcpListenThreadConnection.createInstance(na); fcpTools = new FcpMultiRequestConnectionFileTransferTools(fcpConn); Core.frostSettings.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(final PropertyChangeEvent evt) { if (evt.getPropertyName().equals(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_DOWNLOAD)) { showExternalItemsDownload = Core.frostSettings.getBoolValue(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_DOWNLOAD); if (showExternalItemsDownload) { // get external items showExternalDownloadItems(); } } else if (evt.getPropertyName().equals(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_UPLOAD)) { showExternalItemsUpload = Core.frostSettings.getBoolValue(SettingsClass.GQ_SHOW_EXTERNAL_ITEMS_UPLOAD); if (showExternalItemsUpload) { // get external items showExternalUploadItems(); } } } }); uploadModel = um; downloadModel = dm; // initially get all items from model for (int x = 0; x < uploadModel.getItemCount(); x++) { final FrostUploadItem ul = (FrostUploadItem) uploadModel.getItemAt(x); if (ul.getGqIdentifier() != null) { uploadModelItems.put(ul.getGqIdentifier(), ul); } } for (int x = 0; x < downloadModel.getItemCount(); x++) { final FrostDownloadItem ul = (FrostDownloadItem) downloadModel.getItemAt(x); if (ul.getGqIdentifier() != null) { downloadModelItems.put(ul.getGqIdentifier(), ul); } } // enqueue listeners to keep updated about the model items uploadModel.addOrderedModelListener( new SortedModelListener<FrostUploadItem>() { public void modelCleared() { for (final FrostUploadItem ul : uploadModelItems.values()) { if (ul.isExternal() == false) { fcpTools.removeRequest(ul.getGqIdentifier()); } } uploadModelItems.clear(); } public void itemAdded(final int position, final FrostUploadItem item) { uploadModelItems.put(item.getGqIdentifier(), item); if (!item.isExternal()) { // maybe start immediately startNewUploads(); } } public void itemChanged(final int position, final FrostUploadItem item) {} public void itemsRemoved(final int[] positions, final List<FrostUploadItem> items) { for (final FrostUploadItem item : items) { uploadModelItems.remove(item.getGqIdentifier()); if (item.isExternal() == false) { fcpTools.removeRequest(item.getGqIdentifier()); } } } }); downloadModel.addOrderedModelListener( new SortedModelListener<FrostDownloadItem>() { public void modelCleared() { for (final FrostDownloadItem ul : downloadModelItems.values()) { if (ul.isExternal() == false) { fcpTools.removeRequest(ul.getGqIdentifier()); } } downloadModelItems.clear(); } public void itemAdded(final int position, final FrostDownloadItem item) { downloadModelItems.put(item.getGqIdentifier(), item); if (!item.isExternal()) { // maybe start immediately startNewDownloads(); } } public void itemChanged(final int position, final FrostDownloadItem item) {} public void itemsRemoved(final int[] positions, final List<FrostDownloadItem> items) { for (final FrostDownloadItem item : items) { downloadModelItems.remove(item.getGqIdentifier()); if (item.isExternal() == false) { fcpTools.removeRequest(item.getGqIdentifier()); } } } }); directTransferQueue = new DirectTransferQueue(); directTransferThread = new DirectTransferThread(); persistentQueue = new FcpPersistentQueue(fcpTools, this); }
@Override public void run() { final int maxAllowedExceptions = 5; int catchedExceptions = 0; while (true) { try { // if there is no work in queue this call waits for a new queue item final ModelItem<?> item = directTransferQueue.getItemFromQueue(); if (item == null) { // paranoia, should never happen Mixed.wait(5 * 1000); continue; } if (item instanceof FrostUploadItem) { // transfer bytes to node final FrostUploadItem ulItem = (FrostUploadItem) item; // FIXME: provide item, state=Transfer to node, % shows progress final String gqid = ulItem.getGqIdentifier(); final boolean doMime; final boolean setTargetFileName; if (ulItem.isSharedFile()) { doMime = false; setTargetFileName = false; } else { doMime = true; setTargetFileName = true; } final NodeMessage answer = fcpTools.startDirectPersistentPut( gqid, ulItem.getFile(), ulItem.getFileName(), doMime, setTargetFileName, ulItem.getCompress(), ulItem.getFreenetCompatibilityMode(), ulItem.getPriority()); if (answer == null) { final String desc = "Could not open a new FCP2 socket for direct put!"; final FcpResultPut result = new FcpResultPut(FcpResultPut.Error, -1, desc, false); FileTransferManager.inst().getUploadManager().notifyUploadFinished(ulItem, result); logger.severe(desc); } else { // wait for an answer, don't start request again directPUTsWithoutAnswer.add(gqid); } directPUTsInProgress.remove(gqid); } else if (item instanceof FrostDownloadItem) { // transfer bytes from node final FrostDownloadItem dlItem = (FrostDownloadItem) item; // FIXME: provide item, state=Transfer from node, % shows progress final String gqid = dlItem.getGqIdentifier(); final File targetFile = new File(dlItem.getDownloadFilename()); final boolean retryNow; NodeMessage answer = null; try { answer = fcpTools.startDirectPersistentGet(gqid, targetFile); } catch (final FileNotFoundException e) { final String msg = "Could not write to " + dlItem.getDownloadFilename() + ": " + e.getMessage(); System.out.println(msg); logger.severe(msg); } if (answer != null) { final FcpResultGet result = new FcpResultGet(true); FileTransferManager.inst() .getDownloadManager() .notifyDownloadFinished(dlItem, result, targetFile); retryNow = false; } else { logger.severe("Could not open a new fcp socket for direct get!"); final FcpResultGet result = new FcpResultGet(false); retryNow = FileTransferManager.inst() .getDownloadManager() .notifyDownloadFinished(dlItem, result, targetFile); } directGETsInProgress.remove(gqid); if (retryNow) { startDownload(dlItem); } } } catch (final Throwable t) { logger.log(Level.SEVERE, "Exception catched", t); catchedExceptions++; } if (catchedExceptions > maxAllowedExceptions) { logger.log(Level.SEVERE, "Stopping DirectTransferThread because of too much exceptions"); break; } } }
public boolean isDirectTransferInProgress(final FrostDownloadItem dlItem) { final String id = dlItem.getGqIdentifier(); return directGETsInProgress.contains(id); }
/** Apply the states of FcpRequestGet to the FrostDownloadItem. */ private void applyState(final FrostDownloadItem dlItem, final FcpPersistentGet getReq) { // when cancelled and we expect this, don't set failed; don't even set the old priority! if (dlItem.isInternalRemoveExpected() && getReq.isFailed()) { final int returnCode = getReq.getCode(); if (returnCode == 25) { return; } } applyPriority(dlItem, getReq); if (dlItem.isDirect() != getReq.isDirect()) { dlItem.setDirect(getReq.isDirect()); } if (!getReq.isProgressSet() && !getReq.isSuccess() && !getReq.isFailed()) { if (dlItem.getState() == FrostDownloadItem.STATE_WAITING) { dlItem.setState(FrostDownloadItem.STATE_PROGRESS); } return; } if (getReq.isProgressSet()) { final int doneBlocks = getReq.getDoneBlocks(); final int requiredBlocks = getReq.getRequiredBlocks(); final int totalBlocks = getReq.getTotalBlocks(); final boolean isFinalized = getReq.isFinalized(); if (totalBlocks > 0) { dlItem.setDoneBlocks(doneBlocks); dlItem.setRequiredBlocks(requiredBlocks); dlItem.setTotalBlocks(totalBlocks); dlItem.setFinalized(isFinalized); dlItem.fireValueChanged(); } if (dlItem.getState() != FrostDownloadItem.STATE_PROGRESS) { dlItem.setState(FrostDownloadItem.STATE_PROGRESS); } } if (getReq.isSuccess()) { // maybe progress was not completely sent dlItem.setFinalized(true); if (dlItem.getTotalBlocks() > 0 && dlItem.getDoneBlocks() < dlItem.getRequiredBlocks()) { dlItem.setDoneBlocks(dlItem.getRequiredBlocks()); dlItem.fireValueChanged(); } if (dlItem.isExternal()) { dlItem.setFileSize(getReq.getFilesize()); dlItem.setState(FrostDownloadItem.STATE_DONE); } else { if (dlItem.isDirect()) { maybeEnqueueDirectGet(dlItem, getReq.getFilesize()); } else { final FcpResultGet result = new FcpResultGet(true); final File targetFile = new File(dlItem.getDownloadFilename()); FileTransferManager.inst() .getDownloadManager() .notifyDownloadFinished(dlItem, result, targetFile); } } } if (getReq.isFailed()) { final String desc = getReq.getCodeDesc(); if (dlItem.isExternal()) { dlItem.setState(FrostDownloadItem.STATE_FAILED); dlItem.setErrorCodeDescription(desc); } else { final int returnCode = getReq.getCode(); final boolean isFatal = getReq.isFatal(); final String redirectURI = getReq.getRedirectURI(); final FcpResultGet result = new FcpResultGet(false, returnCode, desc, isFatal, redirectURI); final File targetFile = new File(dlItem.getDownloadFilename()); final boolean retry = FileTransferManager.inst() .getDownloadManager() .notifyDownloadFinished(dlItem, result, targetFile); if (retry) { fcpTools.removeRequest(getReq.getIdentifier()); startDownload(dlItem); // restart immediately } } } }
/** * @param dlItem items whose global identifier is to check * @return true if this item is currently in the global queue, no matter in what state */ public boolean isItemInGlobalQueue(final FrostDownloadItem dlItem) { return persistentQueue.isIdInGlobalQueue(dlItem.getGqIdentifier()); }