X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fxdcc%2Fcore%2FCore.java;h=d89f8079eecbcea11324e6c204e9cd05c897c45f;hb=41e563cfadaff3009c1bad9acf50f8023648b2cd;hp=9d5dcb7a9877c7bf63805d599a03ee652e137fc6;hpb=6721687a11d53eeda4bfeea4ada2f5caffbcad7e;p=xudocci.git diff --git a/src/main/java/net/pterodactylus/xdcc/core/Core.java b/src/main/java/net/pterodactylus/xdcc/core/Core.java index 9d5dcb7..d89f807 100644 --- a/src/main/java/net/pterodactylus/xdcc/core/Core.java +++ b/src/main/java/net/pterodactylus/xdcc/core/Core.java @@ -17,6 +17,8 @@ package net.pterodactylus.xdcc.core; +import static net.pterodactylus.xdcc.data.Download.FILTER_RUNNING; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -46,8 +48,8 @@ import net.pterodactylus.irc.event.DccDownloadFailed; import net.pterodactylus.irc.event.DccDownloadFinished; import net.pterodactylus.irc.event.DccSendReceived; import net.pterodactylus.irc.event.NicknameChanged; -import net.pterodactylus.irc.event.PrivateNoticeReceived; import net.pterodactylus.irc.event.PrivateMessageReceived; +import net.pterodactylus.irc.event.PrivateNoticeReceived; import net.pterodactylus.irc.util.MessageCleaner; import net.pterodactylus.irc.util.RandomNickname; import net.pterodactylus.xdcc.core.event.BotAdded; @@ -66,11 +68,15 @@ import net.pterodactylus.xdcc.data.Pack; import net.pterodactylus.xdcc.data.Server; import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; import com.google.common.collect.HashBasedTable; +import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.collect.Table; import com.google.common.eventbus.EventBus; @@ -114,7 +120,7 @@ public class Core extends AbstractExecutionThreadService { private final Table networkBots = HashBasedTable.create(); /** The current downloads. */ - private final Map downloads = Maps.newHashMap(); + private final Multimap downloads = HashMultimap.create(); /** The current DCC receivers. */ private final Collection dccReceivers = Lists.newArrayList(); @@ -178,12 +184,12 @@ public class Core extends AbstractExecutionThreadService { } /** - * Returns the currently active DCC receivers. + * Returns all currently running downloads. * - * @return The currently active DCC receivers + * @return All currently running downloads */ - public Collection dccReceivers() { - return dccReceivers; + public Collection downloads() { + return downloads.values(); } // @@ -214,6 +220,25 @@ public class Core extends AbstractExecutionThreadService { return; } + /* check if we are already downloading the file? */ + if (downloads.containsKey(pack.name())) { + Collection packDownloads = downloads.get(pack.name()); + Collection runningDownloads = FluentIterable.from(packDownloads).filter(FILTER_RUNNING).toSet(); + if (!runningDownloads.isEmpty()) { + Download download = runningDownloads.iterator().next(); + eventBus.post(new GenericMessage(String.format("File %s is already downloading from %s (%s).", pack.name(), download.bot().name(), download.bot().network().name()))); + return; + } + StringBuilder bots = new StringBuilder(); + for (Download download : packDownloads) { + if (bots.length() > 0) { + bots.append(", "); + } + bots.append(download.bot().name()).append(" (").append(download.bot().network().name()).append(')'); + } + eventBus.post(new GenericMessage(String.format("File %s is already requested from %d bots (%s).", pack.name(), packDownloads.size(), bots.toString()))); + } + Download download = new Download(bot, pack); downloads.put(pack.name(), download); @@ -509,7 +534,7 @@ public class Core extends AbstractExecutionThreadService { Bot bot; synchronized (networkBots) { if (!networkBots.contains(network.get(), channelMessageReceived.source().nick().get())) { - bot = new Bot(network.get()).name(channelMessageReceived.source().nick().get()); + bot = new Bot(network.get(), channelMessageReceived.source().nick().get()); networkBots.put(network.get(), channelMessageReceived.source().nick().get(), bot); eventBus.post(new BotAdded(bot)); } else { @@ -546,7 +571,7 @@ public class Core extends AbstractExecutionThreadService { return; } - eventBus.post(new GenericMessage(String.format("Notice from %s (%s): %s", privateNoticeReceived.reply().source(), network.get(), privateNoticeReceived.text()))); + eventBus.post(new GenericMessage(String.format("Notice from %s (%s): %s", privateNoticeReceived.reply().source().get(), network.get(), privateNoticeReceived.text()))); } /** @@ -556,18 +581,41 @@ public class Core extends AbstractExecutionThreadService { * The DCC SEND event */ @Subscribe - public void dccSendReceived(DccSendReceived dccSendReceived) { - Optional network = getNetwork(dccSendReceived.connection()); + public void dccSendReceived(final DccSendReceived dccSendReceived) { + final Optional network = getNetwork(dccSendReceived.connection()); if (!network.isPresent()) { return; } - Download download = downloads.get(dccSendReceived.filename()); - if (download == null) { + Collection packDownloads = downloads.get(dccSendReceived.filename()); + if (packDownloads.isEmpty()) { /* unknown download, ignore. */ return; } + /* check if it’s already downloading. */ + Collection runningDownloads = FluentIterable.from(packDownloads).filter(FILTER_RUNNING).toSet(); + if (!runningDownloads.isEmpty()) { + eventBus.post(new GenericMessage(String.format("Ignoring offer for %s, it’s already being downloaded.", dccSendReceived.filename()))); + return; + } + + /* locate the correct download. */ + Collection requestedDownload = FluentIterable.from(packDownloads).filter(new Predicate() { + + @Override + public boolean apply(Download download) { + return download.bot().network().equals(network.get()) && download.bot().name().equalsIgnoreCase(dccSendReceived.source().nick().get()); + } + }).toSet(); + + /* we did not request this download. */ + if (requestedDownload.isEmpty()) { + return; + } + + Download download = requestedDownload.iterator().next(); + /* check if the file already exists. */ File outputFile = new File(temporaryDirectory, dccSendReceived.filename()); if (outputFile.exists()) { @@ -583,7 +631,7 @@ public class Core extends AbstractExecutionThreadService { } /* remove download. */ - downloads.remove(download.pack().name()); + downloads.removeAll(download.pack().name()); return; } @@ -612,25 +660,48 @@ public class Core extends AbstractExecutionThreadService { } @Subscribe - public void dccAcceptReceived(DccAcceptReceived dccAcceptReceived) { - Optional network = getNetwork(dccAcceptReceived.connection()); + public void dccAcceptReceived(final DccAcceptReceived dccAcceptReceived) { + final Optional network = getNetwork(dccAcceptReceived.connection()); if (!network.isPresent()) { return; } - Download download = downloads.get(dccAcceptReceived.filename()); - if (download == null) { + Collection packDownloads = downloads.get(dccAcceptReceived.filename()); + if (packDownloads.isEmpty()) { /* unknown download, ignore. */ return; } + /* check if it’s already downloading. */ + Collection runningDownloads = FluentIterable.from(packDownloads).filter(FILTER_RUNNING).toSet(); + if (!runningDownloads.isEmpty()) { + eventBus.post(new GenericMessage(String.format("Ignoring offer for %s, it’s already being downloaded.", dccAcceptReceived.filename()))); + return; + } + + /* locate the correct download. */ + Collection requestedDownload = FluentIterable.from(packDownloads).filter(new Predicate() { + + @Override + public boolean apply(Download download) { + return download.bot().network().equals(network.get()) && download.bot().name().equalsIgnoreCase(dccAcceptReceived.source().nick().get()); + } + }).toSet(); + + /* we did not request this download. */ + if (requestedDownload.isEmpty()) { + return; + } + + Download download = requestedDownload.iterator().next(); + try { File outputFile = new File(temporaryDirectory, dccAcceptReceived.filename()); if (outputFile.length() != dccAcceptReceived.position()) { eventBus.post(new GenericError(String.format("Download %s from %s does not start at the right position!"))); logger.log(Level.WARNING, String.format("Download %s from %s: have %d bytes but wants to resume from %d!", dccAcceptReceived.filename(), dccAcceptReceived.source(), outputFile.length(), dccAcceptReceived.position())); - downloads.remove(download.pack().name()); + downloads.removeAll(download.pack().name()); return; } OutputStream outputStream = new FileOutputStream(outputFile, true); @@ -652,11 +723,15 @@ public class Core extends AbstractExecutionThreadService { */ @Subscribe public void dccDownloadFinished(DccDownloadFinished dccDownloadFinished) { - Download download = downloads.get(dccDownloadFinished.dccReceiver().filename()); - if (download == null) { - /* probably shouldn’t happen. */ + + /* locate the correct download. */ + Collection requestedDownload = FluentIterable.from(downloads.get(dccDownloadFinished.dccReceiver().filename())).filter(FILTER_RUNNING).toSet(); + if (requestedDownload.isEmpty()) { + /* this seems wrong. */ + logger.warning("Download finished but could not be located."); return; } + Download download = requestedDownload.iterator().next(); try { download.outputStream().close(); @@ -664,7 +739,7 @@ public class Core extends AbstractExecutionThreadService { file.renameTo(new File(finalDirectory, download.pack().name())); eventBus.post(new DownloadFinished(download)); dccReceivers.remove(dccDownloadFinished.dccReceiver()); - downloads.remove(download.pack().name()); + downloads.removeAll(download.pack().name()); } catch (IOException ioe1) { /* TODO - handle all the errors. */ logger.log(Level.WARNING, String.format("Could not move file %s to directory %s.", download.filename(), finalDirectory), ioe1); @@ -679,17 +754,21 @@ public class Core extends AbstractExecutionThreadService { */ @Subscribe public void dccDownloadFailed(DccDownloadFailed dccDownloadFailed) { - Download download = downloads.get(dccDownloadFailed.dccReceiver().filename()); - if (download == null) { - /* probably shouldn’t happen. */ + + /* locate the correct download. */ + Collection requestedDownload = FluentIterable.from(downloads.get(dccDownloadFailed.dccReceiver().filename())).filter(FILTER_RUNNING).toSet(); + if (requestedDownload.isEmpty()) { + /* this seems wrong. */ + logger.warning("Download finished but could not be located."); return; } + Download download = requestedDownload.iterator().next(); try { Closeables.close(download.outputStream(), true); eventBus.post(new DownloadFailed(download)); dccReceivers.remove(dccDownloadFailed.dccReceiver()); - downloads.remove(download.pack().name()); + downloads.removeAll(download.pack().name()); } catch (IOException ioe1) { /* swallow silently. */ }