diff --git a/src/core/CommandEnabler.java b/src/core/CommandEnabler.java index 174a5d1..12ee7b1 100644 --- a/src/core/CommandEnabler.java +++ b/src/core/CommandEnabler.java @@ -1,17 +1,111 @@ package core; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import utils.FileUtils; +import utils.GlobalLog; +import utils.LogFilter; + +// While some of the patterns in this file are similar to the localization files, +// commands that are being looked up will behave slightly differently so trimming +// rules for this file are different than the localization ones - this is more +// aggresive with whitespace removal. public class CommandEnabler { // Config/const variables public static final String filename = "commands.config"; + public static final String pairSplit = "="; + public static final char pairSeparator = '\n'; + public static final String enabled = "on"; + public static final String disabled = "off"; + public static final boolean defaultEnabledState = true; // Local variables - private HashMap enabledMap; + private HashMap enabledMap; // Quick lookup + private ArrayList keyList; // Tracking ordering for later public CommandEnabler() { enabledMap = new HashMap<>(); + keyList = new ArrayList<>(); + + ReadIn(); + GetTrackedCommands(); + WriteOut(); + } + + // Reads in the config file and parses it, keeping tabs on the order it read things + private void ReadIn() + { + File f = new File(filename); + if(f.isFile() && f.canRead()) + { + String content = FileUtils.ReadContent(f); + String[] lines = content.split("" + pairSeparator); + + for(int i = 0; i < lines.length; ++i) + { + String[] pair = lines[i].split(pairSplit); + String key = pair[0].trim(); + String value = pair[0].trim().toLowerCase(); + + keyList.add(key); + + if(value == enabled) + enabledMap.putIfAbsent(key, true); + else + enabledMap.putIfAbsent(key, false); + } + } + } + + // Look up the already scraped values from the localizer and store them if they + // don't already exist in the lookup. Defaults to defaultEnabledState. + private void GetTrackedCommands() + { + ArrayList unloc = LocCommands.GetUnlocalizedCommands(); + + for(int i = 0; i < unloc.size(); ++i) + enabledMap.putIfAbsent(unloc.get(i), defaultEnabledState); + } + + // Write out enabled/disabled file info. + private void WriteOut() + { + try + { + String outString = ""; + for(int i = 0; i < keyList.size(); ++i) + { + String key = keyList.get(i); + String value = enabled; + + if(enabledMap.get(key) == false) + value = disabled; + + outString += key + pairSplit + value + pairSeparator; + } + + BufferedWriter writer = new BufferedWriter(new FileWriter(filename)); + writer.write(outString); + writer.close(); + } + catch (IOException e) + { + GlobalLog.Error(LogFilter.Core, "Command enabler issue writing file! " + e.getMessage()); + } + } + + public boolean IsEnabled(String key) + { + if(enabledMap.containsKey(key)) + return enabledMap.get(key); + + return true; } } diff --git a/src/core/CommandManager.java b/src/core/CommandManager.java index 53a5f5a..dac2714 100644 --- a/src/core/CommandManager.java +++ b/src/core/CommandManager.java @@ -6,6 +6,7 @@ import java.util.Map.Entry; import dataStructures.KittyChannel; import dataStructures.KittyGuild; import dataStructures.KittyUser; +import dataStructures.Pair; import dataStructures.Response; import dataStructures.UserInput; import utils.GlobalLog; @@ -16,25 +17,36 @@ public class CommandManager // Variables private HashMap commands; private ArrayList threadAccumulator; + private CommandEnabler commandEnabler; private long invokeCount; - // Default Constructor - public CommandManager() + public CommandManager(CommandEnabler commandEnabler) { - commands = new HashMap(); - threadAccumulator = new ArrayList(); - invokeCount = 0; + this.commands = new HashMap(); + this.threadAccumulator = new ArrayList(); + this.invokeCount = 0; + this.commandEnabler = commandEnabler; } - // Allows the command manager to keep track of a command. - public void Register(String key, Command command) + // Allows the command manager to keep track of a command. Takes a pair (the un-localized and localzied commands) + // and the command associated with the localized commands. + public void Register(Pair pair, Command command) { - if(key == null) + if(pair == null || pair.Second == null) return; + // If we haven't already split a multisplit command (or even assessed that), + // then verify if we even need to register the commands at all. If it's + // not enabled, don't register it. + if(pair.First != null && !commandEnabler.IsEnabled(pair.First)) + return; + + String key = pair.Second; + if(key.contains(",")) { + String[] keys = key.split(","); Register(keys, command); return; @@ -58,7 +70,7 @@ public class CommandManager public void Register(String[] keys, Command command) { for(int i = 0; i < keys.length; ++i) - Register(keys[i].trim(), command); + Register(new Pair(null, keys[i].trim()), command); } // Calls the command but on a whole new thread! diff --git a/src/core/LocCommands.java b/src/core/LocCommands.java index 42fb5ac..04c6ed5 100644 --- a/src/core/LocCommands.java +++ b/src/core/LocCommands.java @@ -34,9 +34,10 @@ public class LocCommands extends LocBase } } - public static String Stub(String toStub) + // Returns a pair, the raw key and the stub key + public static Pair Stub(String toStub) { - return instance.GetKey(toStub); + return new Pair(toStub, instance.GetKey(toStub)); } // Gets all of the un-translated defaults in the commands list. diff --git a/src/core/ObjectBuilderFactory.java b/src/core/ObjectBuilderFactory.java index b6288fd..730ddaf 100644 --- a/src/core/ObjectBuilderFactory.java +++ b/src/core/ObjectBuilderFactory.java @@ -39,6 +39,9 @@ public class ObjectBuilderFactory @SuppressWarnings("unused") private static LocStrings locStrings; @SuppressWarnings("unused") private static LocCommands locCommands; + // Handles if we can or can't use specific commands, parsing a config file based on loc data to do so. + private static CommandEnabler commandEnabler; + // Lazy initialization multithreaded mutex stuff to prevent explosions. // TODO: Investigate using 'synchronized' instead potentially private static boolean hasInitialized; @@ -289,15 +292,26 @@ public class ObjectBuilderFactory user.avatarID = member.getUser().getAvatarUrl(); } - // Default construction of the command manager. - // TODO(wisp): We want to be able to keep all this data - // stored off in a file at some point, so we can reflect it onto the - // project and build it per-guild. That's for later now tho. - public static CommandManager ConstructCommandManager() + // Constructs a CommandEnabler if it doesn't exist, and gets the existing one if it does. + public static CommandEnabler ConstructCommandEnabler() + { + LazyInit(); + + if(commandEnabler == null) + commandEnabler = new CommandEnabler(); + + return commandEnabler; + } + + // Default construction of the command manager. In order to remotely resolve command enabling + // and disabling, what we do is construct the commands with a localized pair that is checked against + // the CommandEnabler object passed in. In theory, we could have multiple CommandManagers, tho we can + // only have one CommandEnabler. + public static CommandManager ConstructCommandManager(CommandEnabler commandEnabler) { LazyInit(); - CommandManager manager = new CommandManager(); + CommandManager manager = new CommandManager(commandEnabler); manager.Register(LocCommands.Stub("work"), new CommandDoWork(KittyRole.Dev, KittyRating.Safe)); manager.Register(LocCommands.Stub("shutdown"), new CommandShutdown(KittyRole.Dev, KittyRating.Safe)); @@ -341,7 +355,7 @@ public class ObjectBuilderFactory return manager; } - // NOTE(wisp): Default database manager construction. It can be constructed + // Default database manager construction. It can be constructed // in different ways, and so we construct it outside of the constructor for // the factory since it doesn't have to be present / can be elsewhere. // Effectively we cache the database here. diff --git a/src/main/Main.java b/src/main/Main.java index a30359a..2b7bc6a 100644 --- a/src/main/Main.java +++ b/src/main/Main.java @@ -25,6 +25,7 @@ public class Main extends ListenerAdapter // Variables and stuff private static JDA kitty; private static CommandManager commandManager; + private static CommandEnabler commandEnabler; private static DatabaseManager databaseManager; private static Stats stats; private static RPManager rpManager; @@ -34,7 +35,8 @@ public class Main extends ListenerAdapter { // Factory startup. The ordering is intentional. databaseManager = ObjectBuilderFactory.ConstructDatabaseManager(); - commandManager = ObjectBuilderFactory.ConstructCommandManager(); + commandEnabler = ObjectBuilderFactory.ConstructCommandEnabler(); + commandManager = ObjectBuilderFactory.ConstructCommandManager(commandEnabler); rpManager = ObjectBuilderFactory.ConstructRPManager(); stats = ObjectBuilderFactory.ConstructStats(commandManager); diff --git a/src/utils/FileUtils.java b/src/utils/FileUtils.java index ba70d6a..716fae3 100644 --- a/src/utils/FileUtils.java +++ b/src/utils/FileUtils.java @@ -12,6 +12,7 @@ import java.util.stream.Stream; public class FileUtils { // Reads all lines from a file as a string + public static String ReadContent(File file) { return ReadContent(file.toPath()); } public static String ReadContent(Path filePath) { StringBuilder contentBuilder = new StringBuilder();