X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fxdcc%2Fui%2Fstdin%2FCommandReader.java;h=66447b06d9b628a940532f3fe84d31493c41bfcd;hb=5e7f77e44cacc40da04ac9f744566de0710b12a1;hp=eaaef2389c127b747548799928e681b3b2431710;hpb=52be4d6d0bf21502d301814ba88735fd72a3f284;p=xudocci.git diff --git a/src/main/java/net/pterodactylus/xdcc/ui/stdin/CommandReader.java b/src/main/java/net/pterodactylus/xdcc/ui/stdin/CommandReader.java index eaaef23..66447b0 100644 --- a/src/main/java/net/pterodactylus/xdcc/ui/stdin/CommandReader.java +++ b/src/main/java/net/pterodactylus/xdcc/ui/stdin/CommandReader.java @@ -17,17 +17,21 @@ package net.pterodactylus.xdcc.ui.stdin; +import static com.google.common.collect.FluentIterable.from; +import static java.util.Arrays.asList; +import static net.pterodactylus.xdcc.ui.stdin.Ansi.bold; +import static net.pterodactylus.xdcc.ui.stdin.Ansi.green; +import static net.pterodactylus.xdcc.ui.stdin.Ansi.red; +import static net.pterodactylus.xdcc.ui.stdin.Command.TO_NAME; + import java.io.BufferedReader; import java.io.IOException; import java.io.Reader; import java.io.Writer; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Set; -import net.pterodactylus.irc.Connection; -import net.pterodactylus.irc.DccReceiver; import net.pterodactylus.irc.util.MessageCleaner; import net.pterodactylus.xdcc.core.Core; import net.pterodactylus.xdcc.core.event.DownloadFailed; @@ -35,14 +39,14 @@ import net.pterodactylus.xdcc.core.event.DownloadFinished; import net.pterodactylus.xdcc.core.event.DownloadStarted; import net.pterodactylus.xdcc.core.event.GenericMessage; import net.pterodactylus.xdcc.core.event.MessageReceived; -import net.pterodactylus.xdcc.data.Bot; import net.pterodactylus.xdcc.data.Download; -import net.pterodactylus.xdcc.data.Pack; +import net.pterodactylus.xdcc.util.io.DuplicateLineSuppressingWriter; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; +import com.google.common.base.Joiner; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.eventbus.Subscribe; -import com.google.common.primitives.Ints; import com.google.common.util.concurrent.AbstractExecutionThreadService; /** @@ -52,14 +56,15 @@ import com.google.common.util.concurrent.AbstractExecutionThreadService; */ public class CommandReader extends AbstractExecutionThreadService { - /** The core being controlled. */ - private final Core core; + /** The commands to process. */ + private final Collection commands; /** The reader to read commands from. */ private final BufferedReader reader; /** The writer to write the results to. */ - private final Writer writer; + private final DuplicateLineSuppressingWriter writer; + private final Collection failedDownloads; /** * Creates a new command reader. @@ -71,10 +76,25 @@ public class CommandReader extends AbstractExecutionThreadService { * @param writer * The write to write results to */ - public CommandReader(Core core, Reader reader, Writer writer) { - this.core = core; + public CommandReader(Core core, Reader reader, Writer writer, Collection failedDownloads) { this.reader = new BufferedReader(reader); - this.writer = writer; + this.writer = new DuplicateLineSuppressingWriter(writer); + this.failedDownloads = failedDownloads; + + /* initialize commands. */ + ImmutableList.Builder commandBuilder = ImmutableList.builder(); + commandBuilder.add(new ListDownloadsCommand(core)); + commandBuilder.add(new SearchCommand(core)); + commandBuilder.add(new DownloadCommand(core)); + commandBuilder.add(new StatsCommand(core)); + commandBuilder.add(new ListConnectionsCommand(core)); + commandBuilder.add(new AbortDownloadCommand(core)); + commandBuilder.add(new DisconnectCommand(core)); + commandBuilder.add(new FailedDownloadsCommand(failedDownloads)); + commandBuilder.add(new RestartCommand(core, failedDownloads)); + commandBuilder.add(new ResearchCommand(core)); + commandBuilder.add(new UptimeCommand(core)); + commands = commandBuilder.build(); } // @@ -85,100 +105,25 @@ public class CommandReader extends AbstractExecutionThreadService { protected void run() throws Exception { String lastLine = ""; String line; - final List lastResult = Lists.newArrayList(); - final List lastConnections = Lists.newArrayList(); + net.pterodactylus.xdcc.ui.stdin.State state = new net.pterodactylus.xdcc.ui.stdin.State(); while ((line = reader.readLine()) != null) { + line = line.trim(); if (line.equals("")) { line = lastLine; } + writer.reset(); String[] words = line.split(" +"); - if (words[0].equalsIgnoreCase("search")) { - lastResult.clear(); - for (Bot bot : Lists.newArrayList(core.bots())) { - for (Pack pack : Lists.newArrayList(bot)) { - boolean found = true; - for (int wordIndex = 1; wordIndex < words.length; ++wordIndex) { - if (words[wordIndex].startsWith("-") && pack.name().toLowerCase().contains(words[wordIndex].toLowerCase().substring(1))) { - found = false; - break; - } - if (!words[wordIndex].startsWith("-") && !pack.name().toLowerCase().contains(words[wordIndex].toLowerCase())) { - found = false; - break; - } - } - if (found) { - lastResult.add(new Result(bot, pack)); - } - } - } - Collections.sort(lastResult); - int counter = 0; - for (Result result : lastResult) { - writeLine(String.format("[%d] %s (%s) from %s (#%s) on %s", counter++, result.pack().name(), result.pack().size(), result.bot().name(), result.pack().id(), result.bot().network().name())); - } - writeLine("End of Search."); - } else if (words[0].equalsIgnoreCase("dcc")) { - int counter = 0; - for (Download download : core.downloads()) { - DccReceiver dccReceiver = download.dccReceiver(); - if (dccReceiver == null) { - /* download has not even started. */ - writer.write(String.format("[%d] %s requested from %s (not started yet)\n", counter++, download.pack().name(), download.bot().name())); - continue; - } - writer.write(String.format("[%d] %s from %s (%s, ", counter++, dccReceiver.filename(), download.bot().name(), f(dccReceiver.size()))); - if (dccReceiver.isRunning()) { - writer.write(String.format("%.1f%%, %s", dccReceiver.progress() * 100.0 / dccReceiver.size(), f(dccReceiver.currentRate()))); - } else { - if (dccReceiver.progress() >= dccReceiver.size()) { - writer.write(String.format("complete, %s", f(dccReceiver.overallRate()))); - } else { - writer.write(String.format("aborted at %.1f%%, %s", dccReceiver.progress() * 100.0 / dccReceiver.size(), f(dccReceiver.currentRate()))); - } - } - writer.write("/s)\n"); - } - writeLine("End of DCCs."); - } else if (words[0].equalsIgnoreCase("get")) { - Integer index = Ints.tryParse(words[1]); - if ((index != null) && (index < lastResult.size())) { - core.fetch(lastResult.get(index).bot(), lastResult.get(index).pack()); - } - } else if (words[0].equalsIgnoreCase("stats")) { - int configuredChannelsCount = core.channels().size(); - int joinedChannelsCount = core.joinedChannels().size(); - int extraChannelsCount = core.extraChannels().size(); - Collection bots = core.bots(); - Set packNames = Sets.newHashSet(); - int packsCount = 0; - for (Bot bot : bots) { - packsCount += bot.packs().size(); - for (Pack pack : bot) { - packNames.add(pack.name()); - } - } - - writeLine(String.format("%d channels (%d joined, %d extra), %d bots offering %d packs (%d unique).", configuredChannelsCount, joinedChannelsCount, extraChannelsCount, bots.size(), packsCount, packNames.size())); - } else if (words[0].equalsIgnoreCase("connections")) { - lastConnections.clear(); - int counter = 0; - for (Connection connection : core.connections()) { - lastConnections.add(connection); - writer.write(String.format("[%d] %s:%d, %s/s\n", counter++, connection.hostname(), connection.port(), f(connection.getInputRate()))); - } - writeLine("End of connections."); - } else if (words[0].equalsIgnoreCase("disconnect")) { - if ((words.length == 1) || ("all".equals(words[1]))) { - for (Connection connection : lastConnections) { - core.closeConnection(connection); - } - } else { - Integer index = Ints.tryParse(words[1]); - if ((index != null) && (index < lastConnections.size())) { - core.closeConnection(lastConnections.get(index)); - } - } + String commandName = words[0]; + Collection eligibleCommands = findEligibleCommands(commandName); + if (eligibleCommands.isEmpty()) { + writeLine(String.format("Invalid command: %s, valid: %s.", commandName, Joiner.on(' ').join(from(commands).transform(TO_NAME)))); + } else if (eligibleCommands.size() > 1) { + writeLine(String.format("Commands: %s.", Joiner.on(' ').join(from(eligibleCommands).transform(TO_NAME)))); + } else { + Command command = eligibleCommands.iterator().next(); + List parameters = from(asList(words)).skip(1).toList(); + state = command.execute(state, parameters, writer); + writer.flush(); } lastLine = line; @@ -199,7 +144,7 @@ public class CommandReader extends AbstractExecutionThreadService { public void downloadStarted(DownloadStarted downloadStarted) { Download download = downloadStarted.download(); try { - writeLine(String.format("Download of %s (from %s, %s) has started.", download.pack().name(), download.bot().name(), download.bot().network().name())); + writeLine(String.format("Download of %s (from %s, %s) has started.", bold(download.pack().name()), download.bot().name(), download.bot().network().name())); } catch (IOException ioe1) { /* ignore. */ } @@ -214,13 +159,24 @@ public class CommandReader extends AbstractExecutionThreadService { @Subscribe public void downloadFinished(DownloadFinished downloadFinished) { Download download = downloadFinished.download(); + removeFailedDownloads(download.pack().name()); try { - writeLine(String.format("Download of %s (from %s, %s) has finished, at %s/s.", download.pack().name(), download.bot().name(), download.bot().network().name(), f(download.dccReceiver().overallRate()))); + writeLine(green(String.format("Download of %s (from %s, %s) has finished, at %s/s.", download.pack().name(), download.bot().name(), download.bot().network().name(), f(download.dccReceiver().overallRate())))); } catch (IOException ioe1) { /* ignore. */ } } + private void removeFailedDownloads(String name) { + List failedDownloadsToRemove = new ArrayList<>(); + for (Download failedDownload : failedDownloads) { + if (failedDownload.pack().name().equals(name)) { + failedDownloadsToRemove.add(failedDownload); + } + } + failedDownloads.removeAll(failedDownloadsToRemove); + } + /** * Called when a download fails. * @@ -230,8 +186,9 @@ public class CommandReader extends AbstractExecutionThreadService { @Subscribe public void downloadFailed(DownloadFailed downloadFailed) { Download download = downloadFailed.download(); + failedDownloads.add(download); try { - writeLine(String.format("Download of %s (from %s, %s) has failed at %.1f%% and %s/s.", download.filename(), download.bot().name(), download.bot().network().name(), download.dccReceiver().progress() * 100.0 / download.dccReceiver().size(), f(download.dccReceiver().overallRate()))); + writeLine(red(String.format("Download of %s (from %s, %s) has failed at %.1f%% and %s/s.", download.filename(), download.bot().name(), download.bot().network().name(), download.dccReceiver().progress() * 100.0 / download.dccReceiver().size(), f(download.dccReceiver().overallRate())))); } catch (IOException ioe1) { /* ignore. */ } @@ -271,6 +228,21 @@ public class CommandReader extends AbstractExecutionThreadService { // PRIVATE METHODS // + private Collection findEligibleCommands(String name) { + ImmutableSet.Builder eligibleCommands = ImmutableSet.builder(); + for (Command command : commands) { + if (command.getName().toLowerCase().startsWith(name.toLowerCase())) { + eligibleCommands.add(command); + } + for (String alias : command.getAliases()) { + if (alias.toLowerCase().startsWith(name.toLowerCase())) { + eligibleCommands.add(command); + } + } + } + return eligibleCommands.build(); + } + /** * Writes the given line followed by an LF to the {@link #writer}. * @@ -292,7 +264,7 @@ public class CommandReader extends AbstractExecutionThreadService { * The number to convert * @return The converted number */ - private static String f(long number) { + static String f(long number) { if (number >= (1 << 30)) { return String.format("%.1fG", number / (double) (1 << 30)); } @@ -305,59 +277,21 @@ public class CommandReader extends AbstractExecutionThreadService { return String.format("%dB", number); } - /** Container for result information. */ - private static class Result implements Comparable { - - /** The bot carrying the pack. */ - private final Bot bot; - - /** The pack. */ - private final Pack pack; - - /** - * Creates a new result. - * - * @param bot - * The bot carrying the pack - * @param pack - * The pack - */ - private Result(Bot bot, Pack pack) { - this.bot = bot; - this.pack = pack; - } - - // - // ACCESSORS - // - - /** - * Returns the bot carrying the pack. - * - * @return The bot carrying the pack - */ - public Bot bot() { - return bot; - } - - /** - * Returns the pack. - * - * @return The pack - */ - public Pack pack() { - return pack; + /** + * Formats the given number of seconds into a more easily readable string. + * + * @param seconds + * The number of seconds + * @return The formatted time, or “unknown” if the time is unknown + */ + static String t(Optional seconds) { + if (!seconds.isPresent()) { + return "unknown"; } - - // - // COMPARABLE METHODS - // - - @Override - public int compareTo(Result result) { - return pack().name().compareToIgnoreCase(result.pack().name()); + if (seconds.get() > 3600) { + return String.format("%02d:%02d:%02d", seconds.get() / 3600, (seconds.get() / 60) % 60, seconds.get() % 60); } - + return String.format("%02d:%02d", (seconds.get() / 60) % 60, seconds.get() % 60); } }