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.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.Set;
-import net.pterodactylus.irc.DccReceiver;
import net.pterodactylus.irc.util.MessageCleaner;
import net.pterodactylus.xdcc.core.Core;
import net.pterodactylus.xdcc.core.event.DownloadFailed;
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 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;
/**
*/
public class CommandReader extends AbstractExecutionThreadService {
- /** The core being controlled. */
- private final Core core;
+ /** The commands to process. */
+ private final Collection<Command> commands;
/** The reader to read commands from. */
private final BufferedReader reader;
* The write to write results to
*/
public CommandReader(Core core, Reader reader, Writer writer) {
- this.core = core;
this.reader = new BufferedReader(reader);
this.writer = writer;
+
+ /* initialize commands. */
+ ImmutableList.Builder<Command> 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));
+ commands = commandBuilder.build();
}
//
protected void run() throws Exception {
String lastLine = "";
String line;
- final List<Result> lastResult = 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;
}
String[] words = line.split(" +");
- if (words[0].equalsIgnoreCase("search")) {
- lastResult.clear();
- for (Bot bot : core.bots()) {
- for (Pack pack : 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 (DccReceiver dccReceiver : core.dccReceivers()) {
- writer.write(String.format("[%d] %s (%s, ", counter++, dccReceiver.filename(), 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<Bot> bots = core.bots();
- Set<String> 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()));
+ String commandName = words[0];
+ Collection<Command> 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<String> parameters = from(asList(words)).skip(1).toList();
+ state = command.execute(state, parameters, writer);
}
lastLine = line;
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. */
}
public void downloadFinished(DownloadFinished downloadFinished) {
Download download = downloadFinished.download();
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. */
}
public void downloadFailed(DownloadFailed downloadFailed) {
Download download = downloadFailed.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. */
}
// PRIVATE METHODS
//
+ private Collection<Command> findEligibleCommands(String name) {
+ ImmutableSet.Builder<Command> 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}.
*
* 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));
}
return String.format("%dB", number);
}
- /** Container for result information. */
- private static class Result implements Comparable<Result> {
-
- /** 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<Long> 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);
}
}