package the8472.mldht.cli; import static the8472.utils.Functional.tap; import static the8472.utils.Functional.unchecked; import the8472.bencode.BEncoder; import the8472.mldht.cli.commands.Burst; import the8472.mldht.cli.commands.Get; import the8472.mldht.cli.commands.GetPeers; import the8472.mldht.cli.commands.GetTorrent; import the8472.mldht.cli.commands.Help; import the8472.mldht.cli.commands.Ping; import the8472.mldht.cli.commands.Put; import lbms.plugins.mldht.kad.DHT; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.stream.Collectors; public abstract class CommandProcessor { protected Consumer<ByteBuffer> writer; protected Collection<DHT> dhts; protected List<String> arguments; protected Path currentWorkDir = Paths.get(""); BooleanSupplier active = () -> true; static Map<String, Class<? extends CommandProcessor>> SUPPORTED_COMMANDS = tap(new HashMap<>(), m -> { m.put("BURST", Burst.class); m.put("PING", Ping.class); m.put("HELP", Help.class); m.put("GETTORRENT", GetTorrent.class); m.put("GETPEERS", GetPeers.class); m.put("GET", Get.class); m.put("PUT", Put.class); }); public static CommandProcessor from(List<byte[]> rawArgs, Consumer<ByteBuffer> writer, Collection<DHT> dhts) { List<String> args = rawArgs.stream().map(b -> new String(b, StandardCharsets.UTF_8)).collect(Collectors.toCollection(ArrayList::new)); String commandName = args.size() > 0 ? args.get(0).toUpperCase() : "HELP"; Class<? extends CommandProcessor> clazz = Optional.<Class<? extends CommandProcessor>>ofNullable(SUPPORTED_COMMANDS.get(commandName)).orElse(Help.class); CommandProcessor proc = unchecked(() -> clazz.newInstance()); proc.writer = writer; proc.dhts = dhts; proc.arguments = args.size() > 1 ? args.subList(1, args.size()) : Collections.emptyList(); return proc; } protected abstract void process(); protected void handleException(Throwable ex) { Writer w = new CharArrayWriter(1024); PrintWriter pw = new PrintWriter(w); ex.printStackTrace(pw); printErr(w.toString()); exit(200); } protected void println(String str) { Map<String, Object> map = new HashMap<>(); map.put("action", "sysout"); byte[] bytes = (str + '\n').getBytes(StandardCharsets.UTF_8); map.put("payload", bytes); writer.accept(new BEncoder().encode(map, bytes.length + 40)); } protected void printErr(String str) { Map<String, Object> map = new HashMap<>(); map.put("action", "syserr"); map.put("payload", str.getBytes(StandardCharsets.UTF_8)); writer.accept(new BEncoder().encode(map, str.length()*4 + 40)); } protected void exit(int code) { active = () -> false; Map<String, Object> map = new HashMap<>(); map.put("action", "exit"); map.put("exitCode", code); writer.accept(new BEncoder().encode(map, 64)); } protected boolean isRunning() { return active.getAsBoolean(); } }